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.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.friday.custody.service.logicService.impl.DataDictionaryBasicServiceImpl;
import com.friday.custody.dao.FundTradeInfoDao;
import com.friday.custody.entity.FundInfoEntity;
import com.friday.custody.entity.FundTradeInfoEntity;
import com.friday.custody.enums.RetCodeEnum;
import com.friday.custody.exception.RRException;
import com.friday.custody.req.FundTradeInfoReq;
import com.friday.custody.req.QueryDataReq;
import com.friday.custody.service.basicService.FundTradeInfoService;
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.FundTradeInfoVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.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;

/**
 * 8 基⾦交易确认信息表（fund_trade_info）
 */
@Service("fundTradeInfoService")
@Slf4j
public class FundTradeInfoServiceImpl extends ServiceImpl<FundTradeInfoDao, FundTradeInfoEntity>
        implements FundTradeInfoService, DataProcessService<FundTradeInfoEntity> {

    @Autowired
    private DataDictionaryBasicServiceImpl dataDictionaryBasicService;
    @Autowired
    private FundInfoServiceImpl fundInfoService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public R saveData(String type, List<FundTradeInfoEntity> datas) {
        List<FundTradeInfoEntity> insertList = new ArrayList<>();
        List<FundTradeInfoEntity> updateList = new ArrayList<>();
        if (CollectionUtils.isEmpty(datas)){
            return R.ok();
        }
        for (FundTradeInfoEntity entity : datas) {
            //如果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);
            }
            //如果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());
                }
            }

            if ("33".equals(entity.getTrustNo())) {
                entity.setUniqueKey(entity.getTrustNo() + entity.getAdmin() + entity.getCserialNo());
            } else if ("41".equals(entity.getTrustNo())) {
                entity.setUniqueKey(entity.getAdmin() + entity.getTrustNo() + entity.getFundAcco() + entity.getBusinessName() + entity.getRequestDate() + entity.getFundCode()
                        + entity.getApplyShares() + entity.getApplyBalance() + entity.getTradeAcco());
            } else {
                entity.setUniqueKey(entity.getAdmin() + entity.getCserialNo());
            }
        }
        List<String> rawUniqueKeyList = datas.stream().map(FundTradeInfoEntity::getUniqueKey).collect(Collectors.toList());
        String ukList = String.join("--", rawUniqueKeyList);
        Set<String> uniqueKeySet = new HashSet<>();
        if (CollectionUtils.isNotEmpty(rawUniqueKeyList)) {
            uniqueKeySet = baseMapper.queryUniqueKeyList(rawUniqueKeyList);
        }
        for (FundTradeInfoEntity entity : datas) {
            if (uniqueKeySet.contains(entity.getUniqueKey())) {
                //update
                updateList.add(entity);
            } else {
                //insert
                insertList.add(entity);
            }
        }
        if (CollectionUtils.isNotEmpty(insertList)) {
            boolean saveStatus = this.saveBatch(insertList);
            if (!saveStatus){
                log.error("保存交易表失败:{}",ukList);
            }
        }
        this.batchUpdateByUniqueKey(updateList);
        return R.ok();
    }

    private void batchUpdateByUniqueKey(List<FundTradeInfoEntity> updateList) {
        for (FundTradeInfoEntity entity : updateList) {
            LambdaUpdateWrapper<FundTradeInfoEntity> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(FundTradeInfoEntity::getUniqueKey,entity.getUniqueKey());
            this.update(entity, updateWrapper);
        }
    }

    @Override
    public R queryData(QueryDataReq vo) {
        try {
            log.info("开始查询基金交易确认信息表...,租户信息为:{}", JSON.toJSONString(vo));
            //1 封装查询参数
            FundTradeInfoReq fundTradeInfoReq = JSON.parseObject(vo.getParams(), FundTradeInfoReq.class);
            //1.1 封装分页查询参数
            Map<String, Object> pageParams = PageUtil.getPageParams(fundTradeInfoReq);
            //1.2 封装查询参数
            QueryWrapper<FundTradeInfoEntity> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("admin", vo.getTenantName());
            if (StringUtils.isNotBlank(fundTradeInfoReq.getFundCode())) {
                queryWrapper.eq("fund_code", fundTradeInfoReq.getFundCode());
            }
            if (StringUtils.isNotBlank(fundTradeInfoReq.getBusinessName())) {
                queryWrapper.eq("business_name", fundTradeInfoReq.getBusinessName());
            }
            if (StringUtils.isNotBlank(fundTradeInfoReq.getFundAcco())) {
                queryWrapper.eq("fund_acco", fundTradeInfoReq.getFundAcco());
            }
            if (StringUtils.isNotBlank(fundTradeInfoReq.getTradeAcco())) {
                queryWrapper.eq("trade_acco", fundTradeInfoReq.getTradeAcco());
            }
            if (StringUtils.isNotBlank(fundTradeInfoReq.getInnerFundCode())){
                queryWrapper.eq("inner_fund_code",fundTradeInfoReq.getInnerFundCode());
            }
            SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
            Calendar c = Calendar.getInstance();
            //开始和结束时间都为空，默认为一年
            if (StringUtils.isBlank(fundTradeInfoReq.getRequestBeginDate())&&StringUtils.isBlank(fundTradeInfoReq.getRequestEndDate())) {
                c.setTime(new Date());
                c.add(Calendar.YEAR, -1);
                Date m = c.getTime();
                String beginYear = format.format(m);
                fundTradeInfoReq.setRequestBeginDate(beginYear);
                fundTradeInfoReq.setRequestEndDate(format.format(new Date()));
            }
            //开始不为空和结束时间为空，默认当天
            if (StringUtils.isBlank(fundTradeInfoReq.getRequestEndDate())&&StringUtils.isNotBlank(fundTradeInfoReq.getRequestBeginDate())) {
                c.setTime(format.parse(fundTradeInfoReq.getRequestBeginDate()));
                c.add(Calendar.YEAR, 1);
                Date m = c.getTime();
                String endYear = format.format(m);
                fundTradeInfoReq.setRequestBeginDate(fundTradeInfoReq.getRequestBeginDate());
                fundTradeInfoReq.setRequestEndDate(endYear);
            }
            //开始为空和结束时间不为空，默认结束时间往前推一年
            if (StringUtils.isNotBlank(fundTradeInfoReq.getRequestEndDate())&&StringUtils.isBlank(fundTradeInfoReq.getRequestBeginDate())) {
                c.setTime(format.parse(fundTradeInfoReq.getRequestEndDate()));
                c.add(Calendar.YEAR,-1);
                Date m = c.getTime();
                String beginYear = format.format(m);
                fundTradeInfoReq.setRequestBeginDate(beginYear);
            }
            try {
                LocalDate beginDate = LocalDate.parse(fundTradeInfoReq.getRequestBeginDate(), DateTimeFormatter.ofPattern("yyyyMMdd"));
                LocalDate endDate = LocalDate.parse(fundTradeInfoReq.getRequestEndDate(), 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(),"requestEndDate早于requestBeginDate");
                }
                if (days > 366) {
                    return R.error(RetCodeEnum.PARAM_ERROR.getCode(),"requestBeginDate与requestEndDate间隔的天数不能超过365天");
                }
            } catch (Exception e) {
                log.error("参数有误：requestBeginDate :{"+ fundTradeInfoReq.getRequestBeginDate() + "}, requestEndDate :{"+ fundTradeInfoReq.getRequestEndDate() +"}",e);
                return R.error(RetCodeEnum.PARAM_ERROR.getCode(),"beginDate或endDate格式不正确");
            }
            queryWrapper.ge("request_date", fundTradeInfoReq.getRequestBeginDate());
            queryWrapper.le("request_date",fundTradeInfoReq.getRequestEndDate());
            //开始和结束时间都为空，默认为一年
            if (StringUtils.isBlank(fundTradeInfoReq.getConfirmBeginDate())&&StringUtils.isBlank(fundTradeInfoReq.getConfirmEndDate())) {
                c.setTime(new Date());
                c.add(Calendar.YEAR, -1);
                Date m = c.getTime();
                String beginYear = format.format(m);
                fundTradeInfoReq.setConfirmBeginDate(beginYear);
                fundTradeInfoReq.setConfirmEndDate(format.format(new Date()));
            }
            //开始不为空和结束时间为空，默认当天
            if (StringUtils.isBlank(fundTradeInfoReq.getConfirmEndDate())&&StringUtils.isNotBlank(fundTradeInfoReq.getConfirmBeginDate())) {
                c.setTime(format.parse(fundTradeInfoReq.getConfirmBeginDate()));
                c.add(Calendar.YEAR, 1);
                Date m = c.getTime();
                String endYear = format.format(m);
                fundTradeInfoReq.setConfirmBeginDate(fundTradeInfoReq.getConfirmBeginDate());
                fundTradeInfoReq.setConfirmEndDate(endYear);
            }
            //开始为空和结束时间不为空，默认结束时间往前推一年
            if (StringUtils.isNotBlank(fundTradeInfoReq.getConfirmEndDate())&&StringUtils.isBlank(fundTradeInfoReq.getConfirmBeginDate())) {
                c.setTime(format.parse(fundTradeInfoReq.getConfirmEndDate()));
                c.add(Calendar.YEAR,-1);
                Date m = c.getTime();
                String beginYear = format.format(m);
                fundTradeInfoReq.setConfirmBeginDate(beginYear);
            }
            try {
                LocalDate confirmBeginDate = LocalDate.parse(fundTradeInfoReq.getConfirmBeginDate(), DateTimeFormatter.ofPattern("yyyyMMdd"));
                LocalDate confirmEndDate = LocalDate.parse(fundTradeInfoReq.getConfirmEndDate(), DateTimeFormatter.ofPattern("yyyyMMdd"));
                Duration duration = Duration.between(confirmBeginDate.atTime(0, 0, 0),confirmEndDate.atTime(0, 0, 0));
                long days = duration.toDays(); //相差的天数
                if (days < 0) {
                    return R.error(RetCodeEnum.PARAM_ERROR.getCode(),"confirmEndDate早于confirmBeginDate");
                }
                if (days > 366) {
                    return R.error(RetCodeEnum.PARAM_ERROR.getCode(),"confirmBeginDate与confirmEndDate间隔的天数不能超过365天");
                }
            } catch (Exception e) {
                log.error("参数有误：confirmBeginDate :{"+ fundTradeInfoReq.getConfirmBeginDate() + "}, confirmEndDate :{"+ fundTradeInfoReq.getConfirmEndDate() +"}",e);
                return R.error(RetCodeEnum.PARAM_ERROR.getCode(),"confirmBeginDate或confirmEndDate格式不正确");
            }
            queryWrapper.ge("confirm_date", fundTradeInfoReq.getConfirmBeginDate());
            queryWrapper.le("confirm_date",fundTradeInfoReq.getConfirmEndDate());
            //按交易确认日期confirmDate（若存在）、交易账号tradeAcco（若存在）、基金账号fundAcco（若存在）、托管人编码trustNo逆序排列
            queryWrapper.orderBy(true,false, "confirm_date","trade_acco","fund_acco","trust_no");
            //2 执行检索
            IPage<FundTradeInfoEntity> page = this.page(
                    new Query<FundTradeInfoEntity>().getPage(pageParams),
                    queryWrapper
            );
            //封装数据
            PageUtils pageUtils = new PageUtils(page);
            List<FundTradeInfoEntity> entities = page.getRecords();
            //entities 转vo
            ArrayList<FundTradeInfoVo> vos = new ArrayList<>();
            for (FundTradeInfoEntity entity : entities) {
                vos.add(FundTradeInfoVo.builder()
                        .id(entity.getId())
                        .cserialNo(entity.getCserialNo())
                        .requestNo(StringUtils.isBlank(entity.getRequestNo())?"":entity.getRequestNo())
                        .fundAcco(entity.getFundAcco())
                        .fundCode(StringUtils.isBlank(entity.getFundCode())?"":entity.getFundCode())
                        .innerFundCode(entity.getInnerFundCode())
                        .fundName(entity.getFundName())
                        .agencyNo(entity.getAgencyNo())
                        .agencyName(entity.getAgencyName())
                        .taFlag(StringUtils.isBlank(entity.getTaFlag())?"":entity.getTaFlag())
                        .tradeAcco(entity.getTradeAcco())
                        .requestDate(entity.getRequestDate())
                        .confirmDate(entity.getConfirmDate())
                        .businessName(StringUtils.isBlank(entity.getBusinessName())?"":entity.getBusinessName())
                        .currency(entity.getCurrency())
                        .netValue(Objects.isNull(entity.getNetValue())?null:entity.getNetValue().toString())
                        .applyBalance(Objects.isNull(entity.getApplyBalance())?null:entity.getApplyBalance().toString())
                        .applyShares(Objects.isNull(entity.getApplyShares())?null:entity.getApplyShares().toString())
                        .confirmBalance(Objects.isNull(entity.getConfirmBalance())?null:entity.getConfirmBalance().toString())
                        .confirmShares(Objects.isNull(entity.getConfirmShares())?null:entity.getConfirmShares().toString())
                        .interest(Objects.isNull(entity.getInterest())?null:entity.getInterest().toString())
                        .interestShare(Objects.isNull(entity.getInterestShare())?null:entity.getInterestShare().toString())
                        .interestTax(Objects.isNull(entity.getInterestTax())?null:entity.getInterestTax().toString())
                        .unShares(Objects.isNull(entity.getUnShares())?null:entity.getUnShares().toString())
                        .frozenBalance(Objects.isNull(entity.getFrozenBalance())?null:entity.getFrozenBalance().toString())
                        .unfrozenBalance(Objects.isNull(entity.getUnfrozenBalance())?null:entity.getUnfrozenBalance().toString())
                        .confirmStatus(entity.getConfirmStatus())
                        .profitBalance(Objects.isNull(entity.getProfitBalance())?null:entity.getProfitBalance().toString())
                        .profitBalanceAgt(Objects.isNull(entity.getProfitBalanceAgt())?null:entity.getProfitBalanceAgt().toString())
                        .totalFare(Objects.isNull(entity.getTotalFare())?null:entity.getTotalFare().toString())
                        .tradeFare(Objects.isNull(entity.getTradeFare())?null:entity.getTradeFare().toString())
                        .agio(Objects.isNull(entity.getAgio())?null:entity.getAgio().toString())
                        .agencyFare(Objects.isNull(entity.getAgencyFare())?null:entity.getAgencyFare().toString())
                        .registFare(Objects.isNull(entity.getRegistFare())?null:entity.getRegistFare().toString())
                        .fundFare(Objects.isNull(entity.getFundFare())?null:entity.getFundFare().toString())
                        .taFare(Objects.isNull(entity.getTaFare())?null:entity.getTaFare().toString())
                        .stampTax(Objects.isNull(entity.getStampTax())?null:entity.getStampTax().toString())
                        .backFare(Objects.isNull(entity.getBackFare())?null:entity.getBackFare().toString())
                        .breachFare(Objects.isNull(entity.getBreachFare())?null:entity.getBreachFare().toString())
                        .breachFareAgt(Objects.isNull(entity.getBreachFareAgt())?null:entity.getBreachFareAgt().toString())
                        .breachFareFund(Objects.isNull(entity.getBreachFareFund())?null:entity.getBreachFareFund().toString())
                        .unfrozenBalance(Objects.isNull(entity.getUnfrozenBalance())?null:entity.getUnfrozenBalance().toString())
                        .bonusMethod(Objects.isNull(entity.getBonusMethod())?"":entity.getBonusMethod())
                        .summary(entity.getSummary())
                        .adjustCause(entity.getAdjustCause())
                        .confirmNavVol(Objects.isNull(entity.getConfirmNavVol())?"":entity.getConfirmNavVol().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 FundTradeInfoServiceImpl RRException is :", rrException);
            return R.error(RetCodeEnum.OPERATION_ERROR.getCode(), rrException.getMsg());
        } catch (Exception e) {
            log.error("the QueryDataVo is :" + JSON.toJSONString(vo) + ".the FundTradeInfoServiceImpl Exception is :", e);
            return R.error(RetCodeEnum.OPERATION_ERROR.getCode(), "查询数据失败!");
        }
    }

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

    private String getFundCodeByFundCode(String fundCode) {
        return fundInfoService.getFundCodeByFundCode(fundCode);
    }
}