package com.smppw.core.reta.calc;


import com.smppw.common.pojo.dto.CompoundRet;
import com.smppw.common.pojo.dto.DateValue;
import com.smppw.common.pojo.enums.Frequency;
import com.smppw.core.reta.Rate;
import com.smppw.utils.DateUtil;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * @author lizhuang
 * @date 2022/4/27 17:19
 * <p>
 * 超额收益--几何
 */
public class ExcessReturnRealTimeCalc extends Rate {

    /**
     * 超额净值算法
     */
    @Override
    public Double calc(List<DateValue> fundNavList, List<DateValue> bmkNavList, Frequency frequency, boolean ifAnnualized) {
        ExtraNav extraNav = new ExtraNav();
        List<DateValue> dateValues = extraNav.extraNav(fundNavList, bmkNavList);
        if (dateValues.isEmpty()) {
            return null;
        }
        Double result = new IntervalReturn().calc(dateValues);
        if (ifAnnualized && result != null && result != 0D) {
            int trands = DateUtil.getDateDistance(dateValues.get(0).getDate(), dateValues.get(dateValues.size() - 1).getDate(), frequency, true);
            result = Math.pow(1 + result, frequency.getNum() / trands) - 1;
        }
        return result;
    }

    // 超额收益，用收益推算的方法
    public Double calc(List<CompoundRet> list, Frequency frequency, boolean ifAnnualized) {
        List<CompoundRet> compoundRets = list;
        Double retOfFund = null;
        Double retOfBenchmark = null;
        for (CompoundRet cr : compoundRets) {
            if (retOfFund == null) {
                retOfFund = 1.0D;
            }
            if (retOfBenchmark == null) {
                retOfBenchmark = 1.0D;
            }
            if (cr.getRetOfBmk() != null && cr.getRetOfFund() != null) {
                retOfFund *= (1 + cr.getRetOfFund());
                retOfBenchmark *= (1 + cr.getRetOfBmk());
            }
        }
        Double result = null;
        if (retOfFund != null && retOfBenchmark != 0.0D) {
            result = retOfFund / retOfBenchmark - 1;
        }

        if (ifAnnualized && result != null) {
            compoundRets.sort((c1, c2) -> {
                int c1EndDate = Integer.parseInt(c1.getEndDate().replaceAll("-", ""));
                int c2EndDate = Integer.parseInt(c2.getEndDate().replaceAll("-", ""));
                return Integer.compare(c1EndDate, c2EndDate);
            });
            String firstDate = compoundRets.get(0).getEndDate();
            String lastDate = compoundRets.get(compoundRets.size() - 1).getEndDate();
            int dateDis = DateUtil.getDateDistance(firstDate, lastDate, frequency, true);

            if (dateDis == 8) {
                result = Math.pow(1 + result, Frequency.Weekly.getNum()) - 1;
            } else {
                if (frequency == Frequency.Daily) {
                    result = Math.pow(1 + result, 365.25 / dateDis) - 1;
                } else if (frequency == Frequency.Weekly){
                    result = Math.pow(1 + result, Frequency.Weekly.getNum() / dateDis) - 1;
                } else if (frequency == Frequency.Monthly) {
                    result = Math.pow(1 + result, Frequency.Monthly.getNum() / dateDis) - 1;
                }

            }
        }
        return result;
    }

    @Override
    public Double calc(List<DateValue> dateValues) {
        return new IntervalReturn().calc(dateValues);
    }

    public List<CompoundRet> transValue(List<CompoundRet> rets) {
        if (rets == null || rets.isEmpty()) {
            return Collections.emptyList();
        }
        List<CompoundRet> result = new ArrayList<>();
        for (CompoundRet ret : rets) {
            Double fundRet = ret.getRetOfFund();
            Double bmkRet = ret.getRetOfBmk();
            String date = ret.getEndDate();
            if (fundRet == null || bmkRet == null || date == null || fundRet == 0D || bmkRet == 0D || date.isEmpty()) {
                continue;
            }

            Double value = ((1 + fundRet) / (1 + bmkRet)) - 1;
            CompoundRet compoundRet = new CompoundRet();
            compoundRet.setEndDate(date);
            compoundRet.setRetOfFund(value);
            compoundRet.setRetOfBmk(bmkRet);
            compoundRet.setRetOfRf(ret.getRetOfRf());
            result.add(compoundRet);
        }
        return result;
    }
}
