package com.smppw.utils;


import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.map.MapUtil;
import com.smppw.common.cache.CaffeineLocalCache;
import com.smppw.common.pojo.IndexesTradeDateDo;
import com.smppw.common.pojo.dto.DateValue;
import com.smppw.common.pojo.dto.NavDto;
import com.smppw.common.pojo.dto.calc.IndicatorCalcPropertyDto;
import com.smppw.common.pojo.enums.Frequency;
import com.smppw.common.pojo.enums.Indicator;
import com.smppw.common.pojo.enums.NavType;
import org.apache.commons.lang3.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

public class NavUtil {

    public static List<DateValue> filterFrequencyNav(List<DateValue> mainSecNavList, List<IndexesTradeDateDo> indexesTradeDateDoList, Frequency frequency) {
        Map<String, DateValue> mainSecNavMap = new HashMap<>();
        if (mainSecNavList == null || mainSecNavList.size() == 0) {
            return new ArrayList<>();
        }
        for (DateValue mainSecNav : mainSecNavList) {
            String mainSecNavDate = mainSecNav.getDate();
            mainSecNavMap.put(mainSecNavDate, mainSecNav);
        }

        List<DateValue> validMainSecNavList = new ArrayList<>();
        if (Frequency.Daily == frequency) {
            validMainSecNavList = new ArrayList<>();
            List<String> dailyTradeDateList = new ArrayList<>();
            for (IndexesTradeDateDo indexesTradeDateDo : indexesTradeDateDoList) {
                dailyTradeDateList.add(indexesTradeDateDo.getTradeDate());
            }
            for (String dailyTradeDate : dailyTradeDateList) {
                if (mainSecNavMap.containsKey(dailyTradeDate)) {
                    DateValue dv = new DateValue();
                    dv.setDate(dailyTradeDate);
                    dv.setValue(mainSecNavMap.get(dailyTradeDate).getValue());
                    dv.setIsvalid(1);
                    validMainSecNavList.add(dv);
                }
            }
        } else if (Frequency.Weekly == frequency) {
            validMainSecNavList = filterWeeklyFrequencyNav(indexesTradeDateDoList, mainSecNavMap);
        } else if (Frequency.Monthly == frequency) {
            validMainSecNavList = filterMonthlyFrequencyNav(mainSecNavList, indexesTradeDateDoList, mainSecNavMap, frequency);
        } else if (Frequency.Quarterly == frequency) {
            validMainSecNavList = filterMonthlyFrequencyNav(mainSecNavList, indexesTradeDateDoList, mainSecNavMap, frequency);
        } else if (Frequency.Annually == frequency) {
            validMainSecNavList = filterMonthlyFrequencyNav(mainSecNavList, indexesTradeDateDoList, mainSecNavMap, frequency);
        }

        Collections.sort(validMainSecNavList, new Comparator<DateValue>() {
            @Override
            public int compare(DateValue o1, DateValue o2) {
                return o1.getDate().compareTo(o2.getDate());
            }
        });

        return validMainSecNavList;
    }

    private static List<DateValue> filterWeeklyFrequencyNav(List<IndexesTradeDateDo> indexesTradeDateDoList, Map<String, DateValue> mainSecNavMap) {
        List<DateValue> validMainSecNavList = 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);
            }
        }

        for (String yearWeek : yearWeekList) {
            List<IndexesTradeDateDo> yearWeekIndexesTradeDateDoList = yearWeekIndexesTradeDateDoListMap.get(yearWeek);
            DateValue weekDateValue = null;
            for (int i = yearWeekIndexesTradeDateDoList.size() - 1; i >= 0; i--) {
                IndexesTradeDateDo indexesTradeDateDo = yearWeekIndexesTradeDateDoList.get(i);
                DateValue dv = mainSecNavMap.get(indexesTradeDateDo.getTradeDate());
                if (dv != null) {
                    if (weekDateValue == null) {
                        weekDateValue = new DateValue();
                        weekDateValue.setValue(dv.getValue());
                        weekDateValue.setDate(dv.getDate());
                        weekDateValue.setIsvalid(1);
                        validMainSecNavList.add(weekDateValue);
                    } else {
                        DateValue notWeekDateValue = new DateValue();
                        notWeekDateValue.setValue(dv.getValue());
                        notWeekDateValue.setDate(dv.getDate());
                        notWeekDateValue.setIsvalid(0);
                        validMainSecNavList.add(notWeekDateValue);
                    }
                }
            }
        }
        return validMainSecNavList;
    }

    private static List<DateValue> filterMonthlyFrequencyNav(List<DateValue> mainSecNavList, List<IndexesTradeDateDo> indexesTradeDateDoList, Map<String, DateValue> mainSecNavMap,
                                                             Frequency frequency) {
        List<DateValue> validMainSecNavList = new ArrayList<>();
        List<String> yearMonthList = new ArrayList<>();
        Map<String, List<String>> yearMonthTradeDateListMap = new HashMap<>();
        for (IndexesTradeDateDo indexesTradeDateDo : indexesTradeDateDoList) {
            if (!yearMonthList.contains(indexesTradeDateDo.getYearmonth())) {
                yearMonthList.add(indexesTradeDateDo.getYearmonth());
            }
            if (yearMonthTradeDateListMap.containsKey(indexesTradeDateDo.getYearmonth())) {
                List<String> yearMonthTradeDateList = yearMonthTradeDateListMap.get(indexesTradeDateDo.getYearmonth());
                yearMonthTradeDateList.add(indexesTradeDateDo.getTradeDate());
            } else {
                List<String> yearMonthTradeDateList = new ArrayList<>();
                yearMonthTradeDateList.add(indexesTradeDateDo.getTradeDate());
                yearMonthTradeDateListMap.put(indexesTradeDateDo.getYearmonth(), yearMonthTradeDateList);
            }
        }
        String lastMonth = mainSecNavList.get(mainSecNavList.size() - 1).getDate().substring(0, 7);
        String firstMonth = mainSecNavList.get(0).getDate().substring(0, 7);
        List<String> validDateList = new ArrayList<>();
        for (int i = 0; i < yearMonthList.size(); i++) {
            if (!lastMonth.equals(yearMonthList.get(i)) && !firstMonth.equals(yearMonthList.get(i))) {
                if (frequency == Frequency.Quarterly) {
                    if (!yearMonthList.get(i).endsWith("03") && !yearMonthList.get(i).endsWith("06") &&
                            !yearMonthList.get(i).endsWith("09") && !yearMonthList.get(i).endsWith("12")) {
                        continue;
                    }
                } else if (frequency == Frequency.Annually) {
                    if (!yearMonthList.get(i).endsWith("12")) {
                        continue;
                    }
                }
            }
            DateValue thisMonthDateValue = null;
            DateValue laterMonthDateValue = null;
            List<String> yearMonthTradeDateList = yearMonthTradeDateListMap.get(yearMonthList.get(i));
            for (int j = yearMonthTradeDateList.size() - 1; j >= 0; j--) {
                int dayOfMonth = DateUtil.getDayOfMonth(DateUtil.StringToDate(yearMonthTradeDateList.get(j)));
                if (dayOfMonth <= 5) {
                    break;
                }
                DateValue dv = mainSecNavMap.get(yearMonthTradeDateList.get(j));
                if (dv != null) {
                    thisMonthDateValue = new DateValue();
                    thisMonthDateValue.setValue(dv.getValue());
                    thisMonthDateValue.setDate(dv.getDate());
                    break;
                }
            }

            if (i != yearMonthList.size() - 1) {
                List<String> laterYearMonthTradeDateList = yearMonthTradeDateListMap.get(yearMonthList.get(i + 1));
                for (int j = 0; j < laterYearMonthTradeDateList.size(); j++) {
                    int dayOfMonth = DateUtil.getDayOfMonth(DateUtil.StringToDate(laterYearMonthTradeDateList.get(j)));
                    if (dayOfMonth > 5) {
                        break;
                    }
                    DateValue dv = mainSecNavMap.get(laterYearMonthTradeDateList.get(j));
                    if (dv != null) {
                        laterMonthDateValue = new DateValue();
                        laterMonthDateValue.setValue(dv.getValue());
                        laterMonthDateValue.setDate(dv.getDate());
                        break;
                    }
                }
            }

            if (null == thisMonthDateValue && null == laterMonthDateValue) {
                continue;
            }
            if (null == thisMonthDateValue) {
                laterMonthDateValue.setIsvalid(1);
                validDateList.add(laterMonthDateValue.getDate());
                validMainSecNavList.add(laterMonthDateValue);
                continue;
            } else if (null == laterMonthDateValue) {
                thisMonthDateValue.setIsvalid(1);
                validDateList.add(thisMonthDateValue.getDate());
                validMainSecNavList.add(thisMonthDateValue);
                continue;
            }
            String thisMonthDate = thisMonthDateValue.getDate();
            String laterMonthDate = laterMonthDateValue.getDate();

            int laterMonthDateDistance = 1;
            List<String> laterYearMonthTradeDateList = yearMonthTradeDateListMap.get(yearMonthList.get(i + 1));
            for (String laterYearMonthTradeDate : laterYearMonthTradeDateList) {
                if (laterYearMonthTradeDate.equals(laterMonthDate)) {
                    break;
                } else {
                    boolean isTradingDay = CaffeineLocalCache.getIsTradingDay(laterYearMonthTradeDate);
                    if (isTradingDay) {
                        laterMonthDateDistance++;
                    }
                }
            }
            int thisMonthDateDistance = 0;
            for (int j = yearMonthTradeDateList.size() - 1; j >= 0; j--) {
                String date = yearMonthTradeDateList.get(j);
                if (date.equals(thisMonthDate)) {
                    break;
                } else {
                    boolean isTradingDay = CaffeineLocalCache.getIsTradingDay(date);
                    if (isTradingDay) {
                        thisMonthDateDistance++;
                    }
                }
            }

            if (thisMonthDateDistance <= laterMonthDateDistance) {
                thisMonthDateValue.setIsvalid(1);
                validDateList.add(thisMonthDateValue.getDate());
                validMainSecNavList.add(thisMonthDateValue);
            } else {
                laterMonthDateValue.setIsvalid(1);
                validDateList.add(laterMonthDateValue.getDate());
                validMainSecNavList.add(laterMonthDateValue);
            }
        }

        for (DateValue mainSecNav : mainSecNavList) {
            String date = mainSecNav.getDate();
            if (!validDateList.contains(date)) {
                DateValue notIsvalidDateValue = new DateValue();
                notIsvalidDateValue.setIsvalid(0);
                notIsvalidDateValue.setDate(date);
                notIsvalidDateValue.setValue(mainSecNav.getValue());
                validMainSecNavList.add(notIsvalidDateValue);
            }
        }

        return validMainSecNavList;
    }

    public static List<DateValue> filterDefaultRollingFrequencyNav(List<DateValue> mainSecNavList, List<IndexesTradeDateDo> indexesTradeDateDoList, Frequency frequency,
                                                                   String endDateStr) {
        Map<String, DateValue> mainSecNavMap = new HashMap<>();
        if (mainSecNavList == null || mainSecNavList.size() == 0) {
            return new ArrayList<>();
        }
        for (DateValue mainSecNav : mainSecNavList) {
            String mainSecNavDate = mainSecNav.getDate();
            mainSecNavMap.put(mainSecNavDate, mainSecNav);
        }

        List<DateValue> validMainSecNavList = CollectionUtil.newArrayList();
        if (Frequency.Daily == frequency) {
            validMainSecNavList = new ArrayList<>();
            List<String> dailyTradeDateList = new ArrayList<>();
            for (IndexesTradeDateDo indexesTradeDateDo : indexesTradeDateDoList) {
                dailyTradeDateList.add(indexesTradeDateDo.getTradeDate());
            }
            for (String dailyTradeDate : dailyTradeDateList) {
                if (mainSecNavMap.containsKey(dailyTradeDate)) {
                    DateValue dv = new DateValue();
                    dv.setDate(dailyTradeDate);
                    dv.setValue(mainSecNavMap.get(dailyTradeDate).getValue());
                    dv.setIsvalid(1);
                    validMainSecNavList.add(dv);
                }
            }
        } else if (Frequency.Weekly == frequency) {
            validMainSecNavList = filterWeeklyFrequencyNavFillNullWeek(indexesTradeDateDoList, mainSecNavMap);
        } else if (Frequency.Monthly == frequency) {
            validMainSecNavList = filterMonthlyFrequencyNavFillNullMonth(indexesTradeDateDoList, mainSecNavMap, frequency, endDateStr);
        } else if (Frequency.Quarterly == frequency) {
            validMainSecNavList = filterMonthlyFrequencyNavFillNullMonth(indexesTradeDateDoList, mainSecNavMap, frequency, endDateStr);
        } else if (Frequency.Annually == frequency) {
            validMainSecNavList = filterMonthlyFrequencyNavFillNullMonth(indexesTradeDateDoList, mainSecNavMap, frequency, endDateStr);
        }

        Collections.sort(validMainSecNavList, (o1, o2) -> o1.getDate().compareTo(o2.getDate()));

        return validMainSecNavList;
    }

    private static List<DateValue> filterMonthlyFrequencyNavFillNullMonth(List<IndexesTradeDateDo> indexesTradeDateDoList, Map<String, DateValue> mainSecNavMap,
                                                                          Frequency frequency, String endDateStr) {
        List<DateValue> validMainSecNavList = new ArrayList<>();
        List<String> yearMonthList = new ArrayList<>();
        Map<String, List<String>> yearMonthTradeDateListMap = new HashMap<>();
        for (IndexesTradeDateDo indexesTradeDateDo : indexesTradeDateDoList) {
            if (!yearMonthList.contains(indexesTradeDateDo.getYearmonth())) {
                yearMonthList.add(indexesTradeDateDo.getYearmonth());
            }
            if (yearMonthTradeDateListMap.containsKey(indexesTradeDateDo.getYearmonth())) {
                List<String> yearMonthTradeDateList = yearMonthTradeDateListMap.get(indexesTradeDateDo.getYearmonth());
                yearMonthTradeDateList.add(indexesTradeDateDo.getTradeDate());
            } else {
                List<String> yearMonthTradeDateList = new ArrayList<>();
                yearMonthTradeDateList.add(indexesTradeDateDo.getTradeDate());
                yearMonthTradeDateListMap.put(indexesTradeDateDo.getYearmonth(), yearMonthTradeDateList);
            }
        }

        String lastMonth = null;
        if (StringUtils.isNotEmpty(endDateStr)) {
            lastMonth = endDateStr.substring(0, 7);
        }

        List<String> validDateList = new ArrayList<>();
        for (int i = 0; i < yearMonthList.size(); i++) {
            if (lastMonth == null || !lastMonth.equals(yearMonthList.get(i))) {
                if (frequency == Frequency.Quarterly) {
                    if (!yearMonthList.get(i).endsWith("03") && !yearMonthList.get(i).endsWith("06") &&
                            !yearMonthList.get(i).endsWith("09") && !yearMonthList.get(i).endsWith("12")) {
                        continue;
                    }
                } else if (frequency == Frequency.Annually) {
                    if (!yearMonthList.get(i).endsWith("12")) {
                        continue;
                    }
                }
            }
            DateValue thisMonthDateValue = null;
            DateValue laterMonthDateValue = null;
            List<String> yearMonthTradeDateList = yearMonthTradeDateListMap.get(yearMonthList.get(i));
            for (int j = yearMonthTradeDateList.size() - 1; j >= 0; j--) {
                int dayOfMonth = DateUtil.getDayOfMonth(DateUtil.StringToDate(yearMonthTradeDateList.get(j)));
                if (dayOfMonth <= 5) {
                    break;
                }
                DateValue dv = mainSecNavMap.get(yearMonthTradeDateList.get(j));
                if (dv != null) {
                    thisMonthDateValue = new DateValue();
                    thisMonthDateValue.setValue(dv.getValue());
                    thisMonthDateValue.setDate(dv.getDate());
                    break;
                }
            }

            if (i != yearMonthList.size() - 1) {
                List<String> laterYearMonthTradeDateList = yearMonthTradeDateListMap.get(yearMonthList.get(i + 1));
                for (int j = 0; j < laterYearMonthTradeDateList.size(); j++) {
                    int dayOfMonth = DateUtil.getDayOfMonth(DateUtil.StringToDate(laterYearMonthTradeDateList.get(j)));
                    if (dayOfMonth > 5) {
                        break;
                    }
                    DateValue dv = mainSecNavMap.get(laterYearMonthTradeDateList.get(j));
                    if (dv != null) {
                        laterMonthDateValue = new DateValue();
                        laterMonthDateValue.setValue(dv.getValue());
                        laterMonthDateValue.setDate(dv.getDate());
                        break;
                    }
                }
            }

            if (null == thisMonthDateValue && null == laterMonthDateValue) {
                DateValue thisMonthDateNullValue = new DateValue();
                thisMonthDateNullValue.setValue(null);
                thisMonthDateNullValue.setDate(yearMonthTradeDateList.get(yearMonthTradeDateList.size() - 1));
                thisMonthDateNullValue.setIsvalid(1);
                validMainSecNavList.add(thisMonthDateNullValue);
                continue;
            }
            if (null == thisMonthDateValue) {
                laterMonthDateValue.setIsvalid(1);
                validDateList.add(laterMonthDateValue.getDate());
                validMainSecNavList.add(laterMonthDateValue);
                continue;
            } else if (null == laterMonthDateValue) {
                thisMonthDateValue.setIsvalid(1);
                validDateList.add(thisMonthDateValue.getDate());
                validMainSecNavList.add(thisMonthDateValue);
                continue;
            }
            String thisMonthDate = thisMonthDateValue.getDate();
            String laterMonthDate = laterMonthDateValue.getDate();

            int laterMonthDateDistance = 1;
            List<String> laterYearMonthTradeDateList = yearMonthTradeDateListMap.get(yearMonthList.get(i + 1));
            for (String laterYearMonthTradeDate : laterYearMonthTradeDateList) {
                if (laterYearMonthTradeDate.equals(laterMonthDate)) {
                    break;
                } else {
                    boolean isTradingDay = CaffeineLocalCache.getIsTradingDay(laterYearMonthTradeDate);
                    if (isTradingDay) {
                        laterMonthDateDistance++;
                    }
                }
            }
            int thisMonthDateDistance = 0;
            for (int j = yearMonthTradeDateList.size() - 1; j >= 0; j--) {
                String date = yearMonthTradeDateList.get(j);
                if (date.equals(thisMonthDate)) {
                    break;
                } else {
                    boolean isTradingDay = CaffeineLocalCache.getIsTradingDay(date);
                    if (isTradingDay) {
                        thisMonthDateDistance++;
                    }
                }
            }

            if (thisMonthDateDistance <= laterMonthDateDistance) {
                thisMonthDateValue.setIsvalid(1);
                validDateList.add(thisMonthDateValue.getDate());
                validMainSecNavList.add(thisMonthDateValue);
            } else {
                laterMonthDateValue.setIsvalid(1);
                validDateList.add(laterMonthDateValue.getDate());
                validMainSecNavList.add(laterMonthDateValue);
            }
        }

        return validMainSecNavList;
    }

    private static List<DateValue> filterWeeklyFrequencyNavFillNullWeek(List<IndexesTradeDateDo> indexesTradeDateDoList, Map<String, DateValue> mainSecNavMap) {
        List<DateValue> validMainSecNavList = 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);
            }
        }

        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;
                }
            }
            if (StringUtils.isEmpty(lastTradeDate)) {
                continue;
            }
            DateValue weekDateValue = null;
            for (int i = yearWeekIndexesTradeDateDoList.size() - 1; i >= 0; i--) {
                IndexesTradeDateDo indexesTradeDateDo = yearWeekIndexesTradeDateDoList.get(i);
                DateValue dv = mainSecNavMap.get(indexesTradeDateDo.getTradeDate());
                if (dv != null) {
                    weekDateValue = new DateValue();
                    weekDateValue.setValue(dv.getValue());
                    weekDateValue.setDate(lastTradeDate);
                    weekDateValue.setIsvalid(1);
                    validMainSecNavList.add(weekDateValue);
                    break;
                } else if (i == 0) {
                    weekDateValue = new DateValue();
                    weekDateValue.setValue(null);
                    weekDateValue.setDate(lastTradeDate);
                    weekDateValue.setIsvalid(1);
                    validMainSecNavList.add(weekDateValue);
                }
            }
        }
        return validMainSecNavList;
    }

    public static List<DateValue> convertNavList(List<NavDto> navDtoList, NavType navType) {
        List<DateValue> dateValueList = new ArrayList<>();
        for (NavDto navDto : navDtoList) {
            DateValue dateValue = new DateValue();
            dateValue.setDate(navDto.getPriceDate());
            if (NavType.WithdrawalNav == navType) {
                dateValue.setValue(navDto.getCumulativeNavWithdrawal() != null ? navDto.getCumulativeNavWithdrawal().doubleValue() : null);
            } else if (NavType.OriginalNav == navType) {
                dateValue.setValue(navDto.getOriginalNav() != null ? navDto.getOriginalNav().doubleValue() : null);
            } else {
                dateValue.setValue(navDto.getCumulativeNav() != null ? navDto.getCumulativeNav().doubleValue() : null);
            }
            dateValueList.add(dateValue);
        }
        return dateValueList;
    }

    public static Map<String, List<DateValue>> secNavDtoMapToDateValue(Map<String, List<NavDto>> secNavDtoMap, NavType navType) {
        Map<String, List<DateValue>> fundDateValueMap = new HashMap<>();
        for (Map.Entry<String, List<NavDto>> secNavDtoMapEntry : secNavDtoMap.entrySet()) {
            String secId = secNavDtoMapEntry.getKey();
            List<NavDto> navDtoList = secNavDtoMapEntry.getValue();

            List<DateValue> dateValueList = new ArrayList<>();
            for (NavDto navDto : navDtoList) {
                DateValue dateValue = new DateValue();
                dateValue.setDate(navDto.getPriceDate());
                if (NavType.OriginalNav == navType) {
                    dateValue.setValue(navDto.getOriginalNav() != null ? navDto.getOriginalNav().doubleValue() : null);
                } else if (NavType.CumulativeNav == navType) {
                    dateValue.setValue(navDto.getCumulativeNav() != null ? navDto.getCumulativeNav().doubleValue() : null);
                } else if (NavType.WithdrawalNav == navType) {
                    dateValue.setValue(navDto.getCumulativeNavWithdrawal() != null ? navDto.getCumulativeNavWithdrawal().doubleValue() : null);
                }
                dateValueList.add(dateValue);
            }
            fundDateValueMap.put(secId, dateValueList);
        }
        return fundDateValueMap;
    }

    public static void initNavValue(List<DateValue> navList, BigDecimal initValue) {
        if (navList == null || navList.size() == 0) {
            return;
        }
        Collections.sort(navList, new Comparator<DateValue>() {
            @Override
            public int compare(DateValue o1, DateValue o2) {
                return o1.getDate().compareTo(o2.getDate());
            }
        });
        Double firstNav = null;
        for (DateValue dateValue : navList) {
            if (null != dateValue.getValue() && dateValue.getValue().compareTo(0.0) != 0) {
                firstNav = dateValue.getValue();
                break;
            }
        }

        if (firstNav == null) {
            return;
        }


        BigDecimal coefficient = null;
        if (initValue.compareTo(BigDecimal.ZERO) == 0) {
            coefficient = new BigDecimal(firstNav);
        } else {
            coefficient = BigDecimalUtils.divide(new BigDecimal(firstNav), initValue);
        }

        for (DateValue dv : navList) {
            if (null != dv.getValue()) {
                Double nav = BigDecimalUtils.divide(new BigDecimal(dv.getValue()), coefficient).doubleValue();
                dv.setValue(nav);
            }
        }
    }

    public static List<DateValue> getGeoExtraNavList(List<DateValue> secNavNormalizeList, List<DateValue> benchmarkNavNormalizeList) {
        Map<String, DateValue> benchmarkNavMap = new HashMap<>();
        for (DateValue dateValue : benchmarkNavNormalizeList) {
            benchmarkNavMap.put(dateValue.getDate(), dateValue);
        }

        List<DateValue> extraGeoNavList = new ArrayList<>();
        for (int i = 0; i < secNavNormalizeList.size(); i++) {

            Double secNav = secNavNormalizeList.get(i).getValue();
            DateValue benchmarkNavDto = benchmarkNavMap.get(secNavNormalizeList.get(i).getDate());
            Double benchmarkNav = 0.0;
            if (benchmarkNavDto != null) {
                benchmarkNav = benchmarkNavDto.getValue();
            }

            Double extraNavGeo = 0.0;
            if (benchmarkNav.compareTo(0.0) != 0) {
                extraNavGeo = BigDecimalUtils.divide(new BigDecimal(secNav), new BigDecimal(benchmarkNav)).doubleValue();
            }

            DateValue extraGeoNav = new DateValue();
            extraGeoNav.setDate(secNavNormalizeList.get(i).getDate());
            extraGeoNav.setValue(extraNavGeo);
            extraGeoNav.setIsvalid(secNavNormalizeList.get(i).getIsvalid());
            extraGeoNavList.add(extraGeoNav);
        }
        return extraGeoNavList;
    }

    public static List<DateValue> getNewNavList(List<DateValue> dateValueList) {
        List<DateValue> newDateValueList = new ArrayList<>();
        if (dateValueList == null || dateValueList.size() == 0) {
            return newDateValueList;
        }
        for (DateValue dateValue : dateValueList) {
            DateValue newDateValue = new DateValue();
            newDateValue.setDate(dateValue.getDate());
            newDateValue.setValue(dateValue.getValue());
            newDateValue.setIsvalid(dateValue.getIsvalid());
            newDateValueList.add(newDateValue);
        }
        return newDateValueList;
    }

    /**
     * 取净值计算收益
     *
     * @param refIds             多标的id集合
     * @param indexIds           指数id集合，包括基准
     * @param multiSecRetListNew 指标计算结果
     * @param exact              是否超额
     * @return /
     */
    public static List<Map<String, Object>> handleNextStepNew(List<String> refIds, List<String> indexIds, Map<String, List<IndicatorCalcPropertyDto>> multiSecRetListNew, boolean exact) {
        List<String> secIds = CollUtil.unionAll(refIds, indexIds);
        Map<String, List<DateValue>> navMap = MapUtil.newHashMap(8);
        multiSecRetListNew.forEach((k, v) -> v.forEach(dto -> {
            List<DateValue> navList = navMap.getOrDefault(k, ListUtil.list(false));
            CollUtil.addAllIfNotContains(navList, exact ? dto.getSecData().getExtraNavList() : dto.getSecData().getOriNavList());
            navMap.put(k, navList);
            Map<String, List<DateValue>> indexNavMap = exact ? dto.getIndexData().getIndexExtraNavMap() : dto.getIndexData().getIndexNavMap();
            for (String indexId : indexIds) {
                List<DateValue> valueList = navMap.getOrDefault(indexId, ListUtil.list(false));
                List<DateValue> dateValues = indexNavMap.getOrDefault(indexId, ListUtil.empty());
                CollUtil.addAllIfNotContains(valueList, dateValues);
                navMap.put(indexId, valueList);
            }
        }));
        navMap.forEach((k, v) -> Collections.sort(v));
        List<Map<String, Object>> initRetList = ListUtil.list(true);
        for (String secId : secIds) {
            List<DateValue> navList = navMap.get(secId);
            if (navList == null) {
                continue;
            }
            Double prev = null;
            for (DateValue dateValue : navList) {
                Double ret = null;
                Double value = dateValue.getValue();
                if (prev != null && value != null) {
                    ret = BigDecimal.valueOf(value).divide(BigDecimal.valueOf(prev), 10, RoundingMode.HALF_UP)
                            .subtract(BigDecimal.ONE).doubleValue();
                }
                prev = value;
                Map<String, Object> data = MapUtil.<String, Object>builder()
                        .put("fund_id", secId).put("end_date", dateValue.getDate()).put("ret_range", ret).build();
                initRetList.add(data);
            }
        }
        return initRetList;
    }

    @Deprecated
    public static List<Map<String, Object>> handleNextStep(List<String> mainSecIdList, Map<String, List<IndicatorCalcPropertyDto>> multiSecRetListNew) {
        return handleNextStep(mainSecIdList, multiSecRetListNew, false);
    }

    @Deprecated
    public static List<Map<String, Object>> handleNextStep(List<String> mainSecIdList, Map<String, List<IndicatorCalcPropertyDto>> multiSecRetListNew, boolean exact) {
        List<Map<String, Object>> initRetList = ListUtil.list(true);
        for (String fundId : mainSecIdList) {
            List<IndicatorCalcPropertyDto> indicatorCalcPropertyDtoList = multiSecRetListNew.get(fundId);
            if (CollectionUtil.isNotEmpty(indicatorCalcPropertyDtoList)) {
                for (IndicatorCalcPropertyDto indicatorCalcPropertyDto : indicatorCalcPropertyDtoList) {
                    Map<String, Object> fundRetMap = MapUtil.newHashMap(true);
                    String id = indicatorCalcPropertyDto.getIndicatorCalcReq().getIndicatorCalcTimeRangeDto().getId();
                    String value;
                    if (exact) {
                        value = indicatorCalcPropertyDto.getSecData().getExtraGeoIndicatorValueMap().get(Indicator.IntervalReturn.name());
                    } else {
                        value = indicatorCalcPropertyDto.getSecData().getIndicatorValueMap().get(Indicator.IntervalReturn.name());
                    }
                    fundRetMap.put("fund_id", fundId);
                    fundRetMap.put("end_date", id);
                    fundRetMap.put("ret_range", value);
                    initRetList.add(fundRetMap);
                }
            }
        }
        return initRetList;
    }
}
