package com.smppw.utils;

import com.smppw.common.cache.CaffeineLocalCache;
import com.smppw.common.pojo.IndexesTradeDateDo;
import com.smppw.common.pojo.enums.TimeRange;
import com.smppw.common.timerange.TimeRangeFactory;
import org.apache.commons.lang3.StringUtils;

import java.util.*;

public class TradeDateUtil {

    /**
     * 判断这一天是否是交易日  如果是交易日  则获取前4个交易日  如果不是交易日 则获取前5个交易日
     *
     * @param dateStr 日期
     * @return 判断结果集
     */
    public static List<String> getBefore4TradeDate(String dateStr) {

        int preDays = 4;
        if (!CaffeineLocalCache.getIsTradingDay(dateStr)) {
            preDays = 5;
        }

        List<String> preFourTradeDays = new ArrayList<>();
        if (StringUtils.isEmpty(dateStr)) {
            return preFourTradeDays;
        }
        String preDate = dateStr;
        do {
            //获取前一天
            preDate = DateUtil.getPreDate(preDate);

            if (CaffeineLocalCache.getIsTradingDay(preDate)) {
                preFourTradeDays.add(preDate);
            }
        } while (preFourTradeDays.size() < preDays && preDate.compareTo("2001-01-01") > 0);
        return preFourTradeDays;
    }

    /**
     * @param startDate
     * @param endDate
     * @return
     */
    public static List<String> getThisMonthAfter5Days(String startDate, String endDate) {
        List<String> preOneMonthDays = new ArrayList<>();
        if (StringUtils.isEmpty(startDate)) {
            return preOneMonthDays;
        }
        String thisMonth6Day = DateUtil.getThisMonthNumDate(startDate, 6);

        String dateStr = null;
        if (startDate.compareTo(thisMonth6Day) < 0) {
            dateStr = DateUtil.getBeforeMonth(startDate);
        } else {
            dateStr = startDate;
        }

        String lastMonthFirstDate = DateUtil.getThisMonthNumDate(dateStr, 6);
        String lastMonthEndDate = DateUtil.getThisMonthEndDate(dateStr);
        if (lastMonthEndDate.compareTo(endDate) < 0) {
            preOneMonthDays.add(lastMonthEndDate);
        }
        String preDate = lastMonthEndDate;
        while (true) {
            //获取前一天
            preDate = DateUtil.getPreDate(preDate);

            if (preDate.compareTo(lastMonthFirstDate) < 0 || preDate.compareTo("2001-01-01") <= 0) {
                break;
            }
            if (preDate.compareTo(endDate) < 0) {
                preOneMonthDays.add(preDate);
            }
        }
        return preOneMonthDays;
    }

    /**
     * @param dateStr
     * @param endDate
     * @return
     */
    public static List<String> getThisMonthBefore6Days(String dateStr, String endDate) {
        List<String> preOneMonthDays = new ArrayList<>();
        if (StringUtils.isEmpty(dateStr)) {
            return preOneMonthDays;
        }
        String thisMonth6Day = DateUtil.getThisMonthNumDate(dateStr, 6);
        String laterMonthEndDate = null;
        if (dateStr.compareTo(thisMonth6Day) < 0) {
            laterMonthEndDate = dateStr;
        } else {
            laterMonthEndDate = DateUtil.getLaterMonth(dateStr);
        }

        String lastMonthFirstDate = DateUtil.getThisMonthFirstDate(laterMonthEndDate);
        String lastMonthEndDate = DateUtil.getThisMonthNumDate(laterMonthEndDate, 5);
        if (lastMonthEndDate.compareTo(endDate) < 0) {
            preOneMonthDays.add(lastMonthEndDate);
        }
        String preDate = lastMonthEndDate;
        while (true) {
            //获取前一天
            preDate = DateUtil.getPreDate(preDate);

            if (preDate.compareTo(lastMonthFirstDate) < 0 || preDate.compareTo("2001-01-01") <= 0) {
                break;
            }
            if (preDate.compareTo(endDate) < 0) {
                preOneMonthDays.add(preDate);
            }
        }
        Collections.sort(preOneMonthDays);
        return preOneMonthDays;
    }

    /**
     * 返回startDate 到endDate之间的交易日
     *
     * @param startDate
     * @param endDate
     * @return
     */
    public static List<IndexesTradeDateDo> listInfoByDateInterval(String startDate, String endDate) {

        if (StringUtils.isEmpty(startDate) || StringUtils.isEmpty(endDate)) {
            return new ArrayList<>();
        }
        //获取到缓存的交易日
        List<IndexesTradeDateDo> listInfoTrendDateList = CaffeineLocalCache.getListInfoTrendDate();

        IndexesTradeDateDo firstIndexesTradeDateDo = listInfoTrendDateList.get(0);
        IndexesTradeDateDo lastIndexesTradeDateDo = listInfoTrendDateList.get(listInfoTrendDateList.size() - 1);

        String firstDate = firstIndexesTradeDateDo.getTradeDate();
        String lastDate = lastIndexesTradeDateDo.getTradeDate();

        if (startDate.compareTo(firstDate) < 0) {
            startDate = firstDate;
        }

        if (endDate.compareTo(lastDate) > 0) {
            endDate = lastDate;
        }

        Integer startIndex = getMostRightThan(listInfoTrendDateList, startDate);
        Integer endIndex = getMostLeftLess(listInfoTrendDateList, endDate);

        if (startIndex == -1 || endIndex == -1 || endIndex < startIndex) {
            return new ArrayList<>();
        }

        return listInfoTrendDateList.subList(startIndex, endIndex + 1);
    }

    public static List<String> listTradeDaysByDateInterval(String startDate, String endDate) {

        List<IndexesTradeDateDo> indexesTradeDateDos = listInfoByDateInterval(startDate, endDate);
        List<String> tradeDays = new ArrayList<>();
        for (IndexesTradeDateDo dateDo : indexesTradeDateDos) {
            if (dateDo != null && dateDo.getIsholiday() == 0) {
                tradeDays.add(dateDo.getTradeDate());
            }
        }

        return tradeDays;
    }

    /**
     * @param indexesTradeDateDoList 从小到大的日期序列
     * @param date                   日期
     * @return 小于等于 date 的 日期最大的 日期
     */
    public static Integer getMostLeftLess(List<IndexesTradeDateDo> indexesTradeDateDoList, String date) {
        if (indexesTradeDateDoList == null || indexesTradeDateDoList.size() == 0) {
            return -1;
        }
        int L = 0;
        int R = indexesTradeDateDoList.size() - 1;
        int ans = -1;
        while (L <= R) {
            int mid = (L + R) / 2;
            if (indexesTradeDateDoList.get(mid) != null && indexesTradeDateDoList.get(mid).getTradeDate().compareTo(date) <= 0) {
                ans = mid;
                L = mid + 1;
            } else {
                R = mid - 1;
            }
        }
        return ans;
    }

    /**
     * @param indexesTradeDateDoList 从小到大的日期序列
     * @param date                   日期
     * @return 大于等于 date 的 日期最小的 日期
     */
    public static Integer getMostRightThan(List<IndexesTradeDateDo> indexesTradeDateDoList, String date) {
        if (indexesTradeDateDoList == null || Objects.requireNonNull(indexesTradeDateDoList).size() == 0) {
            return -1;
        } else if (indexesTradeDateDoList.get(indexesTradeDateDoList.size() - 1).getTradeDate().compareTo(date) < 0) {
            return indexesTradeDateDoList.size() - 1;
        }
        int low = 0;
        int high = indexesTradeDateDoList.size() - 1;
        while (low < high) {
            //防止溢出
            int mid = low + (high - low) / 2;
            if (indexesTradeDateDoList.get(mid).getTradeDate().compareTo(date) < 0) {
                low = mid + 1;
            } else {
                high = mid;
            }
        }
        return low;
    }

    public static List<String> getEveryWeekLastTradeDay(String startDate, String endDate) {
        List<IndexesTradeDateDo> indexesTradeDateDoList = listInfoByDateInterval(startDate, endDate);

        if (indexesTradeDateDoList == null || indexesTradeDateDoList.size() == 0) {
            return new ArrayList<>();
        }

        List<String> yearWeekList = new ArrayList<>();

        Map<String, List<IndexesTradeDateDo>> yearWeekIndexesTradeDateDoListMap = new HashMap<>();
        for (IndexesTradeDateDo indexesTradeDateDo : indexesTradeDateDoList) {
            if (!yearWeekList.contains(indexesTradeDateDo.getYearWeek())) {
                yearWeekList.add(indexesTradeDateDo.getYearWeek());
            }
            if (yearWeekIndexesTradeDateDoListMap.containsKey(indexesTradeDateDo.getYearWeek())) {
                List<IndexesTradeDateDo> yearWeekIndexesTradeDateDoList = yearWeekIndexesTradeDateDoListMap.get(indexesTradeDateDo.getYearWeek());
                yearWeekIndexesTradeDateDoList.add(indexesTradeDateDo);
            } else {
                List<IndexesTradeDateDo> yearWeekIndexesTradeDateDoList = new ArrayList<>();
                yearWeekIndexesTradeDateDoList.add(indexesTradeDateDo);
                yearWeekIndexesTradeDateDoListMap.put(indexesTradeDateDo.getYearWeek(), yearWeekIndexesTradeDateDoList);
            }
        }

        List<String> everyWeekLastTradeList = new ArrayList<>();
        for (String yearWeek : yearWeekList) {
            List<IndexesTradeDateDo> yearWeekIndexesTradeDateDoList = yearWeekIndexesTradeDateDoListMap.get(yearWeek);
            String lastTradeDate = null;
            for (int i = yearWeekIndexesTradeDateDoList.size() - 1; i >= 0; i--) {
                IndexesTradeDateDo indexesTradeDateDo = yearWeekIndexesTradeDateDoList.get(i);
                if (indexesTradeDateDo.getIsholiday().compareTo(0) == 0) {
                    lastTradeDate = indexesTradeDateDo.getTradeDate();
                    break;
                }
            }
            everyWeekLastTradeList.add(lastTradeDate);
        }
        return everyWeekLastTradeList;
    }

    //上上周最后一个交易日有更新净值，如果上上周完全没有交易日（比如国庆、春节），则用上上上周最后一个交易日
    public static String getPreWeekTradeDay(String date, int preNum) {
        String startDate = TimeRangeFactory.getInstance().get(TimeRange.Last1Month).generateStartDate(date, TimeRange.Last1Month);
        //获取到缓存的交易日
        List<IndexesTradeDateDo> listInfoTrendDateList = listInfoByDateInterval(startDate, date);

        List<String> weekList = new ArrayList<>();
        for (IndexesTradeDateDo listInfoTrendDate : listInfoTrendDateList) {
            String tradeDate = listInfoTrendDate.getTradeDate();
            String yearWeek = CaffeineLocalCache.getYearWeekByDate(tradeDate);
            if (!weekList.contains(yearWeek)) {
                weekList.add(yearWeek);
            }
        }
        Collections.sort(weekList);

        String thisYearWeek = CaffeineLocalCache.getYearWeekByDate(date);

        int index = weekList.indexOf(thisYearWeek);
        if (index < (preNum + 1)) {
            return null;
        }
        String preWeek = weekList.get(index - preNum);
        String lastTradeDate = CaffeineLocalCache.getLastTradeDateByYearWeek(preWeek);
        if (StringUtils.isEmpty(lastTradeDate)) {
            preWeek = weekList.get(index - (preNum + 1));
            lastTradeDate = CaffeineLocalCache.getLastTradeDateByYearWeek(preWeek);
        }
        return lastTradeDate;
    }

    //上上周最后一个交易日有更新净值，如果上上周完全没有交易日（比如国庆、春节），则直接返回null
    public static String getPreWeekTradeDayWithoutDerived(String date, int preNum) {
        String startDate = TimeRangeFactory.getInstance().get(TimeRange.Last1Month).generateStartDate(date, TimeRange.Last1Month);
        //获取到缓存的交易日
        List<IndexesTradeDateDo> listInfoTrendDateList = listInfoByDateInterval(startDate, date);

        List<String> weekList = new ArrayList<>();
        for (IndexesTradeDateDo listInfoTrendDate : listInfoTrendDateList) {
            String tradeDate = listInfoTrendDate.getTradeDate();
            String yearWeek = CaffeineLocalCache.getYearWeekByDate(tradeDate);
            if (!weekList.contains(yearWeek)) {
                weekList.add(yearWeek);
            }
        }
        Collections.sort(weekList);

        String thisYearWeek = CaffeineLocalCache.getYearWeekByDate(date);

        int index = weekList.indexOf(thisYearWeek);
        if (index < (preNum + 1)) {
            return null;
        }
        String preWeek = weekList.get(index - preNum);
        String lastTradeDate = CaffeineLocalCache.getLastTradeDateByYearWeek(preWeek);
        return lastTradeDate;
    }
}
