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.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.friday.custody.common.CustodyContants;
import com.friday.custody.dao.CustShareInfoDao;
import com.friday.custody.dto.TenantEscrowAuthorizationInfoDto;
import com.friday.custody.entity.CustShareInfoEntity;
import com.friday.custody.entity.FundInfoEntity;
import com.friday.custody.entity.FundNetValueInfoEntity;
import com.friday.custody.enums.RetCodeEnum;
import com.friday.custody.exception.RRException;
import com.friday.custody.req.CustShareInfoReq;
import com.friday.custody.req.QueryDataReq;
import com.friday.custody.service.basicService.CustShareInfoService;
import com.friday.custody.service.logicService.DataProcessService;
import com.friday.custody.utils.*;
import com.friday.custody.vo.CustShareInfoVo;
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.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Service("custShareInfoService")
@Slf4j
public class CustShareInfoServiceImpl extends ServiceImpl<CustShareInfoDao, CustShareInfoEntity>
        implements CustShareInfoService, DataProcessService<CustShareInfoEntity> {

    @Autowired
    private FundNetValueInfoServiceImpl fundNetValueInfoService;//c
    @Autowired
    private CustShareInfoDao custShareInfoDao;//c
    @Autowired
    private FundInfoServiceImpl fundInfoService;
    @Autowired
    DataSourceTransactionManager dataSourceTransactionManager;
    @Autowired
    TransactionDefinition transactionDefinition;



    /**
     * 不需要做更新处理的托管方:
     * 中泰: 41
     * 邮件解析:
     * 54	4.00	长江
     * 98	3.72	国金道富
     * 97	4.00	第一创业
     * 39	4.00	中金
     * 14	4.00	平安银行
     * 53	3.72	长城证券
     * 44	4.00	东方证券
     */
    private static final List<String> NO_NEED_HANDLE_TRUSTNO = Arrays.asList("41","54","98","97","39","14","53","44");
    @Override
    public R saveData(String type, List<CustShareInfoEntity> datas) {
        TransactionStatus transaction = dataSourceTransactionManager.getTransaction(transactionDefinition);
        if (CollectionUtils.isEmpty(datas)) {
            return R.ok();
        }
        TenantEscrowAuthorizationInfoDto tenant = TenantEscrowAuthorizationInfoDto.builder().trustNo(datas.get(0).getTrustNo())
                .tenantName(datas.get(0).getAdmin()).build();
        try {
            List<CustShareInfoEntity> newDatas = handleData(datas);
            if (!NO_NEED_HANDLE_TRUSTNO.contains(tenant.getTrustNo())) {
                //查询出当前租户库里的数据
                List<CustShareInfoEntity> oldEntities = queryByTenant(tenant);
                //要添加数据的租户主键
                List<String> newUniqueKeyList = newDatas.stream().map(entity -> entity.getUniqueKey()).collect(Collectors.toList());
                //根据组合主键筛选出已存库里,但此次上游数据没有的数据,并将其份额更新为0
                List<CustShareInfoEntity> toUpdateZeroList = oldEntities.stream().filter(entity -> {
                    if (!newUniqueKeyList.contains(entity.getUniqueKey())) {
                        return true;
                    }
                    return false;
                }).collect(Collectors.toList());
                if (!CollectionUtils.isEmpty(toUpdateZeroList)) {
                    updateDataToZero(toUpdateZeroList);
                }
            }
            List<CustShareInfoEntity> unqiueCustShareInfoList = newDatas.stream().collect(Collectors.collectingAndThen
                    (Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing
                            (CustShareInfoEntity::getUniqueKey))), ArrayList::new));

            List<String> rawUniqueKeyList = unqiueCustShareInfoList
                    .stream()
                    .map(CustShareInfoEntity::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(unqiueCustShareInfoList);
            if (!saveStatus) {
                log.error("保存 CustShareInfo失败:{}", ukList);
            }
            dataSourceTransactionManager.commit(transaction);
        } catch (Exception e) {
            log.error("CustShareInfo插入失败!", e);
            dataSourceTransactionManager.rollback(transaction);
            return R.error();
        }
        return R.ok();
    }

    private List<CustShareInfoEntity> handleData(List<CustShareInfoEntity> datas){
        List<CustShareInfoEntity> newDatas = new ArrayList<>();
        Map<String, BigDecimal> map = new HashMap<>();
        for (CustShareInfoEntity entity : datas) {
            try {//如果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 ("36".equals(entity.getTrustNo())) {
                    entity.setUniqueKey(entity.getAdmin() + entity.getInnerFundCode() + entity.getFundName()
                            + entity.getFundAcco() + entity.getTradeAcco());
                } else if ("30".equals(entity.getTrustNo())) {
                    entity.setUniqueKey(entity.getAdmin() + entity.getInnerFundCode() + entity.getFundName()
                            + entity.getFundAcco() + entity.getTradeAcco());
                    if (!map.containsKey(entity.getUniqueKey())) {
                        map.put(entity.getUniqueKey(), entity.getLastHoldShares());
                    } else {
                        map.put(entity.getUniqueKey(), entity.getLastHoldShares().add(map.get(entity.getUniqueKey())));
                    }
                    entity.setLastHoldShares(map.get(entity.getUniqueKey()));
                    //计算shareratio
                    BigDecimal shares = fundNetValueInfoService.getSharesByFundInfo(FundNetValueInfoEntity.builder().admin(entity.getAdmin()).innerFundCode(entity.getInnerFundCode()).fundName(entity.getFundName()).build());
                    entity.setShareRatio(BigDecimalUtil.getShareRatio(shares, map.get(entity.getUniqueKey())));
                } else if ("42".equals(entity.getTrustNo())) {
                    entity.setUniqueKey(entity.getAdmin() + entity.getTrustNo() + entity.getFundCode() + entity.getFundName() + entity.getFundAcco() + entity.getAgencyName());
                } else if ("33".equals(entity.getTrustNo())) {
                    entity.setUniqueKey(entity.getAdmin() + entity.getTrustNo() + entity.getFundCode() + entity.getFundAcco() + entity.getTradeAcco());
                } else if ("41".equals(entity.getTrustNo())) {
                    entity.setUniqueKey(entity.getAdmin() + entity.getTrustNo() + entity.getFundCode() + entity.getFundName() + entity.getFundAcco() + entity.getTradeAcco());
                } else {
                    entity.setUniqueKey(entity.getAdmin() + entity.getFundCode() + entity.getFundName()
                            + entity.getFundAcco() + entity.getTradeAcco());
                }
                newDatas.add(entity);
            } catch (Exception e) {
                log.error("处理数据失败!", e);
                throw new RuntimeException("");
            }
        }
        return newDatas;
    }

    private void  setUniqueKeyForList(List<CustShareInfoEntity> datas){
        Map<String, BigDecimal> map = new HashMap<>();
        if(!CollectionUtils.isEmpty(datas)){
            datas.forEach(entity->{
                if ("36".equals(entity.getTrustNo())) {
                    entity.setUniqueKey(entity.getAdmin() + entity.getInnerFundCode() + entity.getFundName()
                            + entity.getFundAcco() + entity.getTradeAcco());
                } else if ("30".equals(entity.getTrustNo())) {
                    entity.setUniqueKey(entity.getAdmin() + entity.getInnerFundCode() + entity.getFundName()
                            + entity.getFundAcco() + entity.getTradeAcco());
                    if (!map.containsKey(entity.getUniqueKey())) {
                        map.put(entity.getUniqueKey(), entity.getLastHoldShares());
                    } else {
                        map.put(entity.getUniqueKey(), entity.getLastHoldShares().add(map.get(entity.getUniqueKey())));
                    }
                    entity.setLastHoldShares(map.get(entity.getUniqueKey()));
                    //计算shareratio
                    BigDecimal shares = fundNetValueInfoService.getSharesByFundInfo(FundNetValueInfoEntity.builder().admin(entity.getAdmin()).innerFundCode(entity.getInnerFundCode()).fundName(entity.getFundName()).build());
                    entity.setShareRatio(BigDecimalUtil.getShareRatio(shares, map.get(entity.getUniqueKey())));
                } else if ("42".equals(entity.getTrustNo())) {
                    entity.setUniqueKey(entity.getAdmin() + entity.getTrustNo() + entity.getFundCode() + entity.getFundName() + entity.getFundAcco() + entity.getAgencyName());
                } else if ("33".equals(entity.getTrustNo())) {
                    entity.setUniqueKey(entity.getAdmin() + entity.getTrustNo() + entity.getFundCode() + entity.getFundAcco() + entity.getTradeAcco());
                } else {
                    entity.setUniqueKey(entity.getAdmin() + entity.getFundCode() + entity.getFundName()
                            + entity.getFundAcco() + entity.getTradeAcco());
                }
            });
        }
    }

    @Override
    public R queryData(QueryDataReq vo) {
        try {
            log.info("开始查询基金持有信息表...,租户信息为:{}", JSON.toJSONString(vo));
            //1 封装查询参数
            CustShareInfoReq req = JSON.parseObject(vo.getParams(), CustShareInfoReq.class);
            //1.1 封装分页查询参数
            Map<String, Object> pageParams = PageUtil.getPageParams(req);
            //1.2 封装查询参数
            QueryWrapper<CustShareInfoEntity> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("admin", vo.getTenantName());
            if (StringUtils.isNotBlank(req.getFundCode())) {
                queryWrapper.eq("fund_code", req.getFundCode());
            }
            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.getFundName())) {
                queryWrapper.likeRight("fund_name", req.getFundName());
            }
            if (StringUtils.isNotBlank(req.getInnerFundCode())){
                queryWrapper.eq("inner_fund_code",req.getInnerFundCode());
            }
            queryWrapper.orderBy(true,false, "update_date","fund_code","inner_fund_code","trust_no");

            //2 执行检索
            IPage<CustShareInfoEntity> page = this.page(
                    new Query<CustShareInfoEntity>().getPage(pageParams),
                    queryWrapper
            );
            //封装数据
            PageUtils pageUtils = new PageUtils(page);
            List<CustShareInfoEntity> entities = page.getRecords();
            //entities 转vo
            ArrayList<CustShareInfoVo> vos = new ArrayList<>();
            for (CustShareInfoEntity entity : entities) {
                vos.add(CustShareInfoVo.builder()
                        .id(entity.getId())
                        .fundCode(entity.getFundCode())
                        .innerFundCode(entity.getInnerFundCode())
                        .fundName(entity.getFundName())
                        .agencyNo(entity.getAgencyNo())
                        .agencyName(entity.getAgencyName())
                        .fundAcco(entity.getFundAcco())
                        .tradeAcco(entity.getTradeAcco())
                        .netValueDate(DateFormaterUtil.formatterDateTime(entity.getNetValueDate(), CustodyContants.DATE_SHORT_ACROSS_FORMAT,CustodyContants.DATE_FORMAT))
                        .lastHoldShares(Objects.isNull(entity.getLastHoldShares())?null:entity.getLastHoldShares().toString())
                        .shareRatio(Objects.isNull(entity.getShareRatio())?null:entity.getShareRatio().toString())
                        .enableShares(Objects.isNull(entity.getEnableShares())?null:entity.getEnableShares().toString())
                        .frozenShares(Objects.isNull(entity.getFrozenShares())?null:entity.getFrozenShares().toString())
                        .bonusMethod(entity.getBonusMethod())
                        .totalProfit(Objects.isNull(entity.getTotalProfit())?null:entity.getTotalProfit().toString())
                        .income(Objects.isNull(entity.getIncome())?null:entity.getIncome().toString())
                        .realShares(Objects.isNull(entity.getRealShares())?null:entity.getRealShares().toString())
                        .currency(entity.getCurrency())
                        .updateDate(Objects.isNull(entity.getUpdateDate()) ? "" : entity.getUpdateDate())
                        .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 CustShareInfoServiceImpl RRException is :", rrException);
            return R.error(RetCodeEnum.OPERATION_ERROR.getCode(), rrException.getMsg());
        } catch (Exception e) {
            log.error("the QueryDataVo is :" + JSON.toJSONString(vo) + ".the CustShareInfoServiceImpl Exception is :", e);
            return R.error(RetCodeEnum.OPERATION_ERROR.getCode(), "查询数据失败!");
        }
    }

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

    public String getFundCodeByInnerFundCode(String innerFundCode,String trustNo,String admin){
        return   custShareInfoDao.getFundCodeByInnerFundCode(innerFundCode,trustNo,admin);
    }


    @Override
    public List<CustShareInfoEntity> queryByFundInfo(CustShareInfoEntity entity) {
        try {
            return baseMapper.queryByFundInfo(entity);
        } catch (Exception e) {
            log.error("queryByFundInfo：： :", e);
        }
        return null;
    }

    @Override
    public void updateShares(List<CustShareInfoEntity> custShareInfoEntities) {
        try {
            baseMapper.updateShares(custShareInfoEntities);
        } catch (Exception e) {
            log.error("updateShares：： :", e);
        }
    }

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

    @Override
    public List<CustShareInfoEntity> queryByTenant(TenantEscrowAuthorizationInfoDto tenant){
        QueryWrapper queryWrapper = new QueryWrapper<CustShareInfoEntity>();
        queryWrapper.eq("admin", tenant.getTenantName());
        queryWrapper.eq("trust_no", tenant.getTrustNo());
        return baseMapper.selectList(queryWrapper);
    }

    @Override
    public void updateDataToZero(List<CustShareInfoEntity> toUpdateZeroList) {
        if (CollectionUtils.isNotEmpty(toUpdateZeroList)){
            baseMapper.updateDataToZero(toUpdateZeroList);
        }

    }
}