package com.friday.custody.service.basicService.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.friday.custody.dao.FundProfitInfoDao;
import com.friday.custody.entity.FundInfoEntity;
import com.friday.custody.entity.FundProfitInfoEntity;
import com.friday.custody.enums.RetCodeEnum;
import com.friday.custody.exception.RRException;
import com.friday.custody.req.FundProfitInfoReq;
import com.friday.custody.req.QueryDataReq;
import com.friday.custody.service.basicService.FundProfitInfoService;
import com.friday.custody.service.logicService.DataDictionaryBasicService;
import com.friday.custody.service.logicService.DataProcessService;
import com.friday.custody.utils.PageUtil;
import com.friday.custody.utils.PageUtils;
import com.friday.custody.utils.Query;
import com.friday.custody.utils.R;
import com.friday.custody.vo.FundProfitInfoVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;


@Service("fundProfitInfoService")
@Slf4j
public class FundProfitInfoServiceImpl extends ServiceImpl<FundProfitInfoDao, FundProfitInfoEntity>
        implements FundProfitInfoService , DataProcessService<FundProfitInfoEntity> {
    @Autowired
    private FundInfoServiceImpl fundInfoService;

    @Autowired
    private DataDictionaryBasicService dataDictionaryBasicService;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public R saveData(String type, List<FundProfitInfoEntity> datas) {
        String trustNo = null;
        int count = 0;
        for (FundProfitInfoEntity entity : datas) {
            //如果fundCode，fundName为null，innerFundCode不为null则通过innerFundCode查询fundName，fundCode
            if (StringUtils.isBlank(entity.getFundCode()) && StringUtils.isBlank(entity.getFundName()) && StringUtils.isNotBlank(entity.getInnerFundCode())){
                FundInfoEntity fundInfoEntity = fundInfoService.queryByInnerFundCode(entity.getTrustNo(), entity.getAdmin(), entity.getInnerFundCode());
                if (fundInfoEntity != null) {
                    entity.setFundCode(fundInfoEntity.getFundCode());
                    entity.setFundName(fundInfoEntity.getFundName());
                }
            }else {
                //如果fundCode为null，fundName不为null，则通过fundName查询fundCode
                if (StringUtils.isBlank(entity.getFundCode()) && StringUtils.isNotBlank(entity.getFundName())){
                    String fundCode = fundInfoService.getFundCodeByFundName(entity.getFundName(), entity.getTrustNo(), entity.getAdmin());
                    entity.setFundCode(fundCode);
                }
                //如果fundCode不为null，fundName为null，则通过fundCode查询fundName
                if (StringUtils.isNotBlank(entity.getFundCode()) && StringUtils.isBlank(entity.getFundName())){
                    String fundName = fundInfoService.getFundNameByFundCode(entity.getFundCode(), entity.getTrustNo(), entity.getAdmin());
                    entity.setFundName(fundName);
                }
            }
            trustNo = entity.getTrustNo();

                if("36".equals(entity.getTrustNo())){
                    entity.setUniqueKey(entity.getInnerFundCode() +entity.getFundAcco()+entity.getTradeAcco()+
                            entity.getRequestDate()+entity.getRegistDate()+entity.getTrustNo() + entity.getAdmin());
                } else if ("41".equals(entity.getTrustNo())){
                    entity.setUniqueKey(entity.getAdmin() + entity.getTrustNo() + entity.getFundAcco() + entity.getFundCode()
                             +  entity.getRequestDate()  + entity.getRegistDate() + entity.getTradeAcco());
                } else{
                    entity.setUniqueKey(entity.getCserialNo() + entity.getTrustNo() + entity.getAdmin());
                }
        }

        //根据主键去重
        List<FundProfitInfoEntity> uniqueFundProfitInfoList = datas.stream().collect(Collectors.collectingAndThen
                (Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing
                        (FundProfitInfoEntity::getUniqueKey))), ArrayList::new));

        List<String> rawUniqueKeyList = uniqueFundProfitInfoList.stream().map(FundProfitInfoEntity::getUniqueKey).collect(Collectors.toList());

        String ukList = String.join("--", rawUniqueKeyList);
        if (CollectionUtils.isNotEmpty(rawUniqueKeyList)) {
            Set<String> uniqueKeySet = baseMapper.queryUniqueKeyList(rawUniqueKeyList);
            if (CollectionUtils.isNotEmpty(uniqueKeySet)) {
                baseMapper.deleteByUniqueKeys(uniqueKeySet);
            }

        }
        boolean saveStatus = this.saveBatch(uniqueFundProfitInfoList);
        if (!saveStatus) {
            log.error("保存 FundProfitInfo失败:{}", ukList);
        }

        log.info("trustNo = {}保存fundProfitInfo数据{}条", trustNo, count);
        return R.ok();
    }

    @Override
    public R queryData(QueryDataReq vo) {
        try {
            log.info("开始查询业绩报酬数据表...,租户信息为:{}", JSON.toJSONString(vo));
            //1 封装查询参数
            FundProfitInfoReq req = JSON.parseObject(vo.getParams(), FundProfitInfoReq.class);
            //1.1 封装分页查询参数
            Map<String, Object> pageParams = PageUtil.getPageParams(req);
            //1.2 封装查询参数
            QueryWrapper<FundProfitInfoEntity> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("admin", vo.getTenantName());
            if (StringUtils.isNotBlank(req.getFundCode())) {
                queryWrapper.eq("fund_code", req.getFundCode());
            }
            if (StringUtils.isNotBlank(req.getBusinessName())) {
                queryWrapper.eq("business_name", req.getBusinessName());
            }
            if (StringUtils.isNotBlank(req.getFundAcco())) {
                queryWrapper.eq("fund_acco", req.getFundAcco());
            }
            if (StringUtils.isNotBlank(req.getTradeAcco())) {
                queryWrapper.eq("trade_acco", req.getTradeAcco());
            }
            if (StringUtils.isNotBlank(req.getInnerFundCode())){
                queryWrapper.eq("inner_fund_code",req.getInnerFundCode());
            }
            SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
            Calendar c = Calendar.getInstance();
            //开始和结束时间都为空，默认为一年
            if (StringUtils.isBlank(req.getBeginDate())&&StringUtils.isBlank(req.getEndDate())) {
                c.setTime(new Date());
                c.add(Calendar.YEAR, -1);
                Date m = c.getTime();
                String beginYear = format.format(m);
                req.setBeginDate(beginYear);
                req.setEndDate(format.format(new Date()));
            }
            //开始不为空和结束时间为空，默认当天
            if (StringUtils.isBlank(req.getEndDate())&&StringUtils.isNotBlank(req.getBeginDate())) {
                c.setTime(format.parse(req.getBeginDate()));
                c.add(Calendar.YEAR, 1);
                Date m = c.getTime();
                String endYear = format.format(m);
                req.setBeginDate(req.getBeginDate());
                req.setEndDate(endYear);
            }
            //开始为空和结束时间不为空，默认结束时间往前推一年
            if (StringUtils.isNotBlank(req.getEndDate())&&StringUtils.isBlank(req.getBeginDate())) {
                c.setTime(format.parse(req.getEndDate()));
                c.add(Calendar.YEAR,-1);
                Date m = c.getTime();
                String beginYear = format.format(m);
                req.setBeginDate(beginYear);
            }
            try {
                LocalDate beginDate = LocalDate.parse(req.getBeginDate(), DateTimeFormatter.ofPattern("yyyyMMdd"));
                LocalDate endDate = LocalDate.parse(req.getEndDate(), DateTimeFormatter.ofPattern("yyyyMMdd"));
                Duration duration = Duration.between(beginDate.atTime(0, 0, 0),endDate.atTime(0, 0, 0));
                long days = duration.toDays(); //相差的天数
                if (days < 0) {
                    return R.error(RetCodeEnum.PARAM_ERROR.getCode(),"endDate早于beginDate");
                }
                if (days > 366) {
                    return R.error(RetCodeEnum.PARAM_ERROR.getCode(),"beginDate与endDate间隔的天数不能超过365天");
                }
            } catch (Exception e) {
                log.error("参数有误：beginDate :{"+ req.getBeginDate() + "}, endDate :{"+ req.getEndDate() +"}",e);
                return R.error(RetCodeEnum.PARAM_ERROR.getCode(),"beginDate或endDate格式不正确");
            }
            queryWrapper.ge("confirm_date", req.getBeginDate());
            queryWrapper.le("confirm_date",req.getEndDate());
            //（按业绩报酬确认日期confirmDate（若存在）、交易账号tradeAcco（若存在）、基金账号fundAcco（若存在）、托管人编码trustNo逆序排列）
            queryWrapper.orderBy(true,false, "confirm_date","trade_acco","fund_acco","trust_no");

            //2 执行检索
            IPage<FundProfitInfoEntity> page = this.page(
                    new Query<FundProfitInfoEntity>().getPage(pageParams),
                    queryWrapper
            );
            //封装数据
            PageUtils pageUtils = new PageUtils(page);
            List<FundProfitInfoEntity> entities = page.getRecords();
            //entities 转vo
            ArrayList<FundProfitInfoVo> vos = new ArrayList<>();
            for (FundProfitInfoEntity entity : entities) {
                vos.add(FundProfitInfoVo.builder()
                        .id(entity.getId())
                        .cserialNo(entity.getCserialNo())
                        .oriCserialNo(entity.getOriCserialNo())
                        .fundCode(entity.getFundCode())
                        .innerFundCode(entity.getInnerFundCode())
                        .fundName(entity.getFundName())
                        .agencyNo(entity.getAgencyNo())
                        .agencyName(entity.getAgencyName())
                        .branchCode(entity.getBranchCode())
                        .fundAcco(entity.getFundAcco())
                        .tradeAcco(entity.getTradeAcco())
                        .businessName(entity.getBusinessName())
                        .requestDate(entity.getRequestDate())
                        .confirmDate(entity.getConfirmDate())
                        .sortFlag(entity.getSortFlag())
                        .oriBalance(Objects.isNull(entity.getOriBalance())?null:entity.getOriBalance().toString())
                        .factBalance(Objects.isNull(entity.getFactBalance())?null:entity.getFactBalance().toString())
                        .factShares(Objects.isNull(entity.getFactShares())?null:entity.getFactShares().toString())
                        .shareLevel(entity.getShareLevel())
                        .shareType(entity.getShareType())
                        .triggerType(entity.getTriggerType())
                        .registDate(entity.getRegistDate())
                        .oriDate(entity.getOriDate())
                        .holdDay(entity.getHoldDay())
                        .shares(Objects.isNull(entity.getShares())?null:entity.getShares().toString())
                        .oriNav(Objects.isNull(entity.getOriNav())?null:entity.getOriNav().toString())
                        .oriTotalNav(Objects.isNull(entity.getOriTotalNav())?null:entity.getOriTotalNav().toString())
                        .nav(Objects.isNull(entity.getNav())?null:entity.getNav().toString())
                        .totalNav(Objects.isNull(entity.getTotalNav())?null:entity.getTotalNav().toString())
                        .currRatio(Objects.isNull(entity.getCurrRatio())?null:entity.getCurrRatio().toString())
                        .yearRatio(Objects.isNull(entity.getYearRatio())?null:entity.getYearRatio().toString())
                        .standardRatio(Objects.isNull(entity.getStandardRatio())?null:entity.getStandardRatio().toString())
                        .returnFare(Objects.isNull(entity.getReturnFare())?null:entity.getReturnFare().toString())
                        .bonusBalance(Objects.isNull(entity.getBonusBalance())?null:entity.getBonusBalance().toString())
                        .income(Objects.isNull(entity.getIncome())?null:entity.getIncome().toString())
                        .deductRatio(Objects.isNull(entity.getDeductRatio())?null:entity.getDeductRatio().toString())
                        .valueAddedFare(Objects.isNull(entity.getValueAddedFare())?null:entity.getValueAddedFare().toString())
                        .costPrice(Objects.isNull(entity.getCostPrice())?null:entity.getCostPrice().toString())
                        .totalUnitBonus(Objects.isNull(entity.getTotalUnitBonus())?null:entity.getTotalUnitBonus().toString())
                        .trustNo(entity.getTrustNo())
                        .build());
            }
            pageUtils.setList(vos);
            log.info("业绩报酬数据查询成功...");
            return R.ok("业绩报酬数据查询成功").put("data",pageUtils);
        } catch (RRException rrException) {
            log.error("the QueryDataVo is :" + JSON.toJSONString(vo) + ".the FundProfitInfoServiceImpl RRException is :", rrException);
            return R.error(RetCodeEnum.OPERATION_ERROR.getCode(), rrException.getMsg());
        } catch (Exception e) {
            log.error("the QueryDataVo is :" + JSON.toJSONString(vo) + ".the FundProfitInfoServiceImpl Exception is :", e);
            return R.error(RetCodeEnum.OPERATION_ERROR.getCode(), "查询数据失败!");
        }
    }

    @Override
    public R updateData(String type, List<FundProfitInfoEntity> datas) {
        return null;
    }

    public void saveGjdfShareType(List<FundProfitInfoEntity> list){
        int i=0;
        for (FundProfitInfoEntity entity : list) {
            ++i;
            UpdateWrapper<FundProfitInfoEntity> updateWrapper = new UpdateWrapper<>();
            updateWrapper.eq("admin", entity.getAdmin());
            updateWrapper.eq("trust_no", entity.getTrustNo());
            updateWrapper.eq("inner_fund_code", entity.getInnerFundCode());
            updateWrapper.set("share_type",entity.getShareType());
            //updateWrapper.set("ori_cserial_no",entity.getCserialNo());
            int update = baseMapper.update(null, updateWrapper);
            System.out.println(update);
        }
    }
}