package com.friday.custody.service.dubboService;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.friday.custody.convertor.CdsProductInfoToOverviewOfPrivateFundConvertor;
import com.friday.custody.dao.FundNetValueInfoDao;

import com.friday.custody.dto.TenantEscrowAuthorizationInfoDto;
import com.friday.custody.entity.TenantEscrowAuthorizationInfoEntity;
import com.friday.custody.enums.RetCodeEnum;
import com.friday.custody.req.TenantMappingReq;
import com.friday.custody.service.basicService.TenantEscrowAuthorizationInfoService;
import com.friday.custody.service.logicService.LogicExternalService;
import com.friday.custody.service.tenantService.CustodyTenantMappingService;
import com.friday.custody.service.trustService.OutsourceService;
import com.friday.custody.utils.R;
import com.friday.mystery.toolkitapi.service.ITradingDayService;
import com.friday.custody.entity.CdsProductInfoEntity;
import com.friday.custody.service.basicService.CdsProductInfoService;
import com.friday.custody.utils.DateValidator;
import com.friday.custody.utils.DateValidatorUsingDateFormat;
import com.friday.base.common.response.DubboResult;
//import com.htsc.pipe.api.service.ChanpinquanjingService;
import com.friday.operation.api.custody.dto.*;
import com.friday.operation.api.custody.service.ICustodyDataService;
import com.friday.operation.api.custody.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;

@Service
@Slf4j
public class CustodyDataServiceImpl implements ICustodyDataService {

    @Autowired
    private FundNetValueInfoDao fundNetValueInfoDao;
    @Autowired
    private HtscCdsService htscCdsService;
    @Resource
    private ITradingDayService tradingDayService;
    @Autowired
    private CdsProductInfoService cdsProductInfoService;
    @Autowired
    private CustodyTenantMappingService custodyTenantMappingService;
    @Autowired
    private TenantEscrowAuthorizationInfoService escrowAuthorizationInfoService;
    @Autowired
    private OutsourceService outsourceService;

    @Override
    public DubboResult getMaximumDrawdown(FundIndicatorQueryDTO query) {
        String startDate = query.getStartDate();
        String endDate = query.getEndDate();
        String admin = query.getAdmin();
        List<String> fundCodeList = query.getFundCodeList();

        if (StringUtils.isBlank(admin)) {
            return DubboResult.newFailure(DubboResult.CLIENT_EXCEPTION, "管理人编码不能为空");
        }
        if (StringUtils.isBlank(startDate) || StringUtils.isBlank(endDate)) {
            return DubboResult.newFailure(DubboResult.CLIENT_EXCEPTION, "日期不能为空");
        }
        if (!(validatorDateStr(startDate) && validatorDateStr(endDate))) {
            return DubboResult.newFailure(DubboResult.CLIENT_EXCEPTION, "日期格式yyyy-MM-dd");
        }
        FundIndicatorVO<List<MaximumDrawdownDTO>> fundIndicatorVO = new FundIndicatorVO<>();
        List<MaximumDrawdownDTO> maximumDrawdown = fundNetValueInfoDao.getMaximumDrawdown(admin, fundCodeList, startDate, endDate);
        if (CollectionUtils.isNotEmpty(maximumDrawdown)) {
            maximumDrawdown.forEach(maximum -> {
                if ("0E-8".equalsIgnoreCase(maximum.getMaximumDrawdown())) {
                    maximum.setMaximumDrawdown("0.00000000");
                }
            });
        }
        fundIndicatorVO.setDataList(maximumDrawdown);
        return DubboResult.newSuccess(fundIndicatorVO);
    }

    @Override
    public DubboResult getSharpRatio(FundIndicatorQueryDTO query) {
        String startDate = query.getStartDate();
        String endDate = query.getEndDate();
        String admin = query.getAdmin();
        List<String> fundCodeList = query.getFundCodeList();

        if (StringUtils.isBlank(admin)) {
            return DubboResult.newFailure(DubboResult.CLIENT_EXCEPTION, "管理人编码不能为空");
        }
        if (StringUtils.isBlank(startDate) || StringUtils.isBlank(endDate)) {
            return DubboResult.newFailure(DubboResult.CLIENT_EXCEPTION, "日期不能为空");
        }
        if (!(validatorDateStr(startDate) && validatorDateStr(endDate))) {
            return DubboResult.newFailure(DubboResult.CLIENT_EXCEPTION, "日期格式yyyy-MM-dd");
        }
        if (endDate.compareTo(startDate) < 0){
            return DubboResult.newFailure(DubboResult.CLIENT_EXCEPTION, "结束日期需要大于开始日期");
        }
        List<String> tradingDayList = getTradingDay(startDate, endDate);
        if (tradingDayList.isEmpty()){
            return DubboResult.newFailure(DubboResult.SERVER_EXCEPTION, "调用IBMPS获取交易日期失败");
        }
        String previousTradingDay = getPreviousTradingDay(startDate);
        tradingDayList.add(previousTradingDay);

        String lastTradingDay = Collections.max(tradingDayList);
        // todo 测试环境取上一个交易日的数据
        lastTradingDay = tradingDayList.stream().sorted(Comparator.reverseOrder()).limit(2).skip(1).findFirst().get();
        //risk-free rate
        BigDecimal riskFreeRateBig = htscCdsService.bondYeildRate(lastTradingDay);
        if (riskFreeRateBig == null) {
            return DubboResult.newFailure(DubboResult.SERVER_EXCEPTION, "获取10年期国债利率失败"+lastTradingDay);
        }
        // 确保转dubbo，保留8位
        riskFreeRateBig = riskFreeRateBig.setScale(8, BigDecimal.ROUND_HALF_UP);
        Double riskFreeRate = riskFreeRateBig.doubleValue();

        FundIndicatorVO<List<SharpRatioDTO>> fundIndicatorDto = new FundIndicatorVO<>();
        List<SharpRatioDTO> sharpRatio = fundNetValueInfoDao.getSharpRatio(admin, startDate,endDate,fundCodeList,tradingDayList, riskFreeRate);
        fundIndicatorDto.setDataList(sharpRatio);
        return DubboResult.newSuccess(fundIndicatorDto);

    }


    private boolean validatorDateStr(String dateStr) {
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ISO_LOCAL_DATE;
        DateValidator dateValidator = new DateValidatorUsingDateFormat(dateTimeFormatter);
        return dateValidator.isValid(dateStr);
    }

    private List<String> getTradingDay(String startDate, String endDate) {
       DubboResult result = tradingDayService.getRangeOfTradingDay(startDate, endDate, "XSHG");
        log.info("ibpms:tradingDay:from:{},to:{},result:{}",startDate,endDate,result.toString());
        ArrayList<String> tradingDay = (ArrayList<String>) result.getObject();
        return tradingDay;
    }

    private String getPreviousTradingDay(String startDate){
        LocalDate endLocalDate = LocalDate.parse(startDate);
        LocalDate previoudMonthLocalDate = endLocalDate.minusMonths(1);
        DubboResult result = tradingDayService.getRangeOfTradingDay(previoudMonthLocalDate.toString(), endLocalDate.toString(), "XSHG");
        ArrayList<String> tradingDayList = (ArrayList<String>) result.getObject();
        if (tradingDayList.get(tradingDayList.size() -1).equals(endLocalDate.toString())){
           return tradingDayList.get(tradingDayList.size() - 2);
        }
           return tradingDayList.get(tradingDayList.size() - 1);
    }

    @Override
    public DubboResult<ArrayList<OverviewOfPrivateFundVO>> overviewOfPrivateFund(OverviewOfPrivateFundQueryDTO queryDTO) {

        LambdaQueryWrapper<CdsProductInfoEntity> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        if (StringUtils.isNotBlank(queryDTO.getAdmin())){
            lambdaQueryWrapper.eq(CdsProductInfoEntity::getAdmin, queryDTO.getAdmin());
        }
        if (StringUtils.isNotBlank(queryDTO.getFundCode())){
            lambdaQueryWrapper.eq(CdsProductInfoEntity::getFundCode, queryDTO.getFundCode());
        }
        if (StringUtils.isNotBlank(queryDTO.getFundName())){
            lambdaQueryWrapper.eq(CdsProductInfoEntity::getFundName, queryDTO.getFundName());
        }
        if (queryDTO.getFundStatus() != null){
            lambdaQueryWrapper.eq(CdsProductInfoEntity::getFundStatus, queryDTO.getFundStatus());
        }
        if (queryDTO.getSunshineFund() != null){
            lambdaQueryWrapper.eq(CdsProductInfoEntity::getSunshineFund, queryDTO.getSunshineFund());
        }
        if (queryDTO.getLiquidation() != null){
            lambdaQueryWrapper.eq(CdsProductInfoEntity::getLiquidation, queryDTO.getLiquidation());
        }
        List<CdsProductInfoEntity> list = cdsProductInfoService.list(lambdaQueryWrapper);
        ArrayList<OverviewOfPrivateFundVO> result = CdsProductInfoToOverviewOfPrivateFundConvertor.convertList(list);
        return DubboResult.newSuccess(result);
    }

    @Override
    public DubboResult syncOverviewOfPrivateFundFromCds(String admin) {
        if (StringUtils.isBlank(admin)) {
            return DubboResult.newFailure(DubboResult.CLIENT_EXCEPTION, "管理人编码不能为空");
        }
        boolean status = cdsProductInfoService.syncFundInfoFromHtscCds(admin);
//        if (status){
//            List<String> adminList = Arrays.asList(admin);
//            chanpinquanjingService.synCustodyData(adminList);
//        }
        return DubboResult.newSuccess(status);
    }

    @Override
    public DubboResult saveTenantMapping(String tenant) {
        try {
            TenantMappingReq req = new TenantMappingReq();
            req.setTenant(tenant);
            R result = custodyTenantMappingService.saveTenantMapping(JSON.toJSONString(req));
            if (((Integer) result.get("code")) != RetCodeEnum.SUCCESS.getCode()) {
                return DubboResult.newFailure(DubboResult.SERVER_EXCEPTION, "保存租户数据失败，原因：" + result.get("msg"));
            }
            HashMap<String, String> dataMap = (HashMap<String, String>) result.get("data");
            return DubboResult.newSuccess(dataMap);
        } catch (Exception e) {
            log.error("保存租户数据失败", e);
            return DubboResult.newFailure(DubboResult.SERVER_EXCEPTION, "保存租户数据失败，原因：接口处理异常！");
        }
    }

    @Override
    public DubboResult updateMJBalanceData(String admin) {
        if (StringUtils.isEmpty(admin)) {
            return DubboResult.newFailure(DubboResult.SERVER_EXCEPTION, "管理人编码不能为空");
        }
        List<TenantEscrowAuthorizationInfoEntity> tenantEscrowAuthorizationInfoEntities = escrowAuthorizationInfoService.queryAuthorizationsByAdmin(admin);
        if (CollectionUtils.isEmpty(tenantEscrowAuthorizationInfoEntities)) {
            return DubboResult.newFailure(DubboResult.SERVER_EXCEPTION, "未接入托管TA接口，请前往系统配置接入");
        }
        for (TenantEscrowAuthorizationInfoEntity entity : tenantEscrowAuthorizationInfoEntities) {
            TenantEscrowAuthorizationInfoDto tenant = entity.transForDto();
            outsourceService.updateMJBalanceData(tenant);
        }
        return DubboResult.newSuccess();
    }

    @Override
    public DubboResult updateMJSeqData(String admin) {
        if (StringUtils.isEmpty(admin)) {
            return DubboResult.newFailure(DubboResult.SERVER_EXCEPTION, "管理人编码不能为空");
        }
        List<TenantEscrowAuthorizationInfoEntity> tenantEscrowAuthorizationInfoEntities = escrowAuthorizationInfoService.queryAuthorizationsByAdmin(admin);
        if (CollectionUtils.isEmpty(tenantEscrowAuthorizationInfoEntities)) {
            return DubboResult.newFailure(DubboResult.SERVER_EXCEPTION, "未接入托管TA接口，请前往系统配置接入");
        }
        for (TenantEscrowAuthorizationInfoEntity entity : tenantEscrowAuthorizationInfoEntities) {
            TenantEscrowAuthorizationInfoDto tenant = entity.transForDto();
            outsourceService.updateMJSeqData(tenant);
        }
        return DubboResult.newSuccess();
    }

    @Override
    public DubboResult updateTGBalanceData(String admin) {
        if (StringUtils.isEmpty(admin)) {
            return DubboResult.newFailure(DubboResult.SERVER_EXCEPTION, "管理人编码不能为空");
        }
        List<TenantEscrowAuthorizationInfoEntity> tenantEscrowAuthorizationInfoEntities = escrowAuthorizationInfoService.queryAuthorizationsByAdmin(admin);
        if (CollectionUtils.isEmpty(tenantEscrowAuthorizationInfoEntities)) {
            return DubboResult.newFailure(DubboResult.SERVER_EXCEPTION, "未接入托管TA接口，请前往系统配置接入");
        }
        for (TenantEscrowAuthorizationInfoEntity entity : tenantEscrowAuthorizationInfoEntities) {
            TenantEscrowAuthorizationInfoDto tenant = entity.transForDto();
            outsourceService.updateTGBalanceData(tenant);
        }
        return DubboResult.newSuccess();
    }

    @Override
    public DubboResult updateTGSeqData(String admin) {
        if (StringUtils.isEmpty(admin)) {
            return DubboResult.newFailure(DubboResult.SERVER_EXCEPTION, "管理人编码不能为空");
        }
        List<TenantEscrowAuthorizationInfoEntity> tenantEscrowAuthorizationInfoEntities = escrowAuthorizationInfoService.queryAuthorizationsByAdmin(admin);
        if (CollectionUtils.isEmpty(tenantEscrowAuthorizationInfoEntities)) {
            return DubboResult.newFailure(DubboResult.SERVER_EXCEPTION, "未接入托管TA接口，请前往系统配置接入");
        }
        for (TenantEscrowAuthorizationInfoEntity entity : tenantEscrowAuthorizationInfoEntities) {
            TenantEscrowAuthorizationInfoDto tenant = entity.transForDto();
            outsourceService.updateTGSeqData(tenant);
        }
        return DubboResult.newSuccess();
    }

}
