package com.smppw.utils;

import com.smppw.constants.DateConst;
import com.smppw.constants.IndicatorConst;
import com.smppw.common.pojo.dto.CompoundRet;
import com.smppw.common.pojo.dto.DateValue;
import com.smppw.common.pojo.enums.Frequency;
import com.smppw.common.pojo.enums.Indicator;
import com.smppw.common.pojo.enums.TimeRange;
import com.smppw.core.reta.IndicatorFactory;
import com.smppw.core.reta.Rate;
import com.smppw.core.reta.calc.PerformanceConsistency;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author lzj
 */
@Slf4j
public class IndicatorCalc {
    public static List<Double> getFundRetList(List<CompoundRet> list) {
        List<Double> doubleList = new ArrayList<>();
        for (CompoundRet value : list) {
            if (value.getRetOfFund() != null) {
                doubleList.add(value.getRetOfFund());
            }
        }
        return doubleList;
    }

    public static Map<String, String> calcNavIndicatorValue(List<DateValue> navList, List<Indicator> navIndicatorList) {
        IndicatorFactory factory = IndicatorFactory.getInstance();
        Map<String, String> navIndicatorValueMap = new HashMap<>();
        for (Indicator indicator : navIndicatorList) {
            if (null == navList || navList.size() == 0) {
                navIndicatorValueMap.put(indicator.name(), null);
                continue;
            }
            Rate rate = factory.get(indicator);
            Double navIndicatorValue = null;
            try {
                navIndicatorValue = rate.calc(navList);
            } catch (Exception e) {
                log.error("计算异常Exception",e.getMessage(),e);
                navIndicatorValue = null;
            }

            if(navIndicatorValue != null && navIndicatorValue.isNaN()){
                navIndicatorValue = null;
            } else if( navIndicatorValue != null ) {
                BigDecimal bigDecimalValue = new BigDecimal(navIndicatorValue.toString());
                BigDecimal maxBigDecimalValue = new BigDecimal(IndicatorConst.MAX_INDICATOR_VALUE_STRING);
                BigDecimal minBigDecimalValue = new BigDecimal(IndicatorConst.MIN_INDICATOR_VALUE_STRING);

                if (bigDecimalValue.compareTo(maxBigDecimalValue)>0) {
                    navIndicatorValueMap.put(indicator.name(), maxBigDecimalValue.toPlainString());
                    continue;
                } else if (bigDecimalValue.compareTo(minBigDecimalValue)<0) {
                    navIndicatorValueMap.put(indicator.name(), minBigDecimalValue.toPlainString());
                    continue;
                }
            }
            if (Indicator.INTEGER_VALUE_ARRAY.contains(indicator)) {
                navIndicatorValueMap.put(indicator.name(), CommonUtil.double2IntegerString(navIndicatorValue));
            } else {
                navIndicatorValueMap.put(indicator.name(), CommonUtil.double2StringPoint6WithoutHalfUp(navIndicatorValue));
            }
        }
        convertMaxDrawdownRecureDate(navIndicatorValueMap, navIndicatorList);

        return navIndicatorValueMap;
    }

    private static void convertMaxDrawdownRecureDate(Map<String, String> dataMap, List<Indicator> indicators) {
        if (indicators.contains(Indicator.MaxDrawdownRecureDate)) {
            String value = dataMap.get(Indicator.MaxDrawdownRecureDate.name());
            if (value != null) {
                String dateStr = String.valueOf(Double.valueOf(value).intValue());
                dataMap.put(Indicator.MaxDrawdownRecureDate.name(), DateTime
                        .parse(dateStr, DateTimeFormat.forPattern(DateConst.YYYYMMDD)).toString(DateConst.YYYY_MM_DD));
            }
        }

        if (indicators.contains(Indicator.MaxDrawdownPeakDate)) {
            String value = dataMap.get(Indicator.MaxDrawdownPeakDate.name());
            if (value != null) {
                String dateStr = String.valueOf(Double.valueOf(value).intValue());
                dataMap.put(Indicator.MaxDrawdownPeakDate.name(), DateTime
                        .parse(dateStr, DateTimeFormat.forPattern(DateConst.YYYYMMDD)).toString(DateConst.YYYY_MM_DD));
            }
        }

        if (indicators.contains(Indicator.MaxDrawdownValleyDate)) {
            String value = dataMap.get(Indicator.MaxDrawdownValleyDate.name());
            if (value != null) {
                String dateStr = String.valueOf(Double.valueOf(value).intValue());
                dataMap.put(Indicator.MaxDrawdownValleyDate.name(), DateTime
                        .parse(dateStr, DateTimeFormat.forPattern(DateConst.YYYYMMDD)).toString(DateConst.YYYY_MM_DD));
            }
        }
    }

    public static Map<String, String> calcRetIndicatorValue(List<CompoundRet> retList, TimeRange timeRange,
                                                            Frequency frequency, boolean ifAnnualize, List<Indicator> retIndicatorList, boolean ifConvertPerformanceConsistencyWord, int leastRetNum) {
        Map<String,String> retIndicatorValueMap = new HashMap<>();

        IndicatorFactory factory = IndicatorFactory.getInstance();
        for (Indicator indicator : retIndicatorList) {
            if (indicator == null) {
                continue;
            }
            Double value = null;
            if (null == retList) {
                retIndicatorValueMap.put(indicator.name(), null);
                continue;
            }
            // update by wangzaijun on 2023-04-06 超额胜率支持
            if (indicator.name().startsWith("ExcessReturn") || indicator == Indicator.ExcessAriIntervalReturn || indicator == Indicator.ExcessAnnualAriIntervalReturn || indicator == Indicator.WinRate
                    || (retList != null && retList.size() >= leastRetNum) || timeRange == TimeRange.FromSetup) {
                Rate rate = factory.get(indicator);

                try {
                    value = rate.calc(retList, frequency, ifAnnualize);
                } catch (Exception e) {
                    log.info("计算异常Exception",e.getMessage(),e);
                    value = null;
                }
                if (value != null && (value.isNaN() || value.isInfinite() )) {
                    value = null;
                } else if (value != null) {
                    BigDecimal bigDecimalValue = new BigDecimal(value.toString());
                    BigDecimal maxBigDecimalValue = new BigDecimal(IndicatorConst.MAX_INDICATOR_VALUE_STRING);
                    BigDecimal minBigDecimalValue = new BigDecimal(IndicatorConst.MIN_INDICATOR_VALUE_STRING);

                    if (bigDecimalValue.compareTo(maxBigDecimalValue) > 0) {
                        retIndicatorValueMap.put(indicator.name(), maxBigDecimalValue.toPlainString());
                        continue;
                    } else if (bigDecimalValue.compareTo(minBigDecimalValue) < 0) {
                        retIndicatorValueMap.put(indicator.name(), minBigDecimalValue.toPlainString());
                        continue;
                    }
                }
                retIndicatorValueMap.put(indicator.name(), CommonUtil.double2StringPoint6WithoutHalfUp(value));
            } else {
                retIndicatorValueMap.put(indicator.name(), null);
            }
        }
        convertPerformanceConsistency(retIndicatorList, retIndicatorValueMap, ifConvertPerformanceConsistencyWord);
        return retIndicatorValueMap;
    }

    private static void convertPerformanceConsistency(List<Indicator> retIndicatorList, Map<String, String> retIndicatorValueMap, boolean ifConvertPerformanceConsistencyWord) {

        if (retIndicatorList.contains(Indicator.PerformanceConsistency) && ifConvertPerformanceConsistencyWord) {
            String value = retIndicatorValueMap.get(Indicator.PerformanceConsistency.name());
            if (value != null) {
                retIndicatorValueMap.put(Indicator.PerformanceConsistency.name(),
                        PerformanceConsistency.convert2Word(Double.valueOf(value)));
            }
        }
    }

}
