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

import com.alibaba.dubbo.common.utils.CollectionUtils;
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.dao.FundValuationDao;
import com.friday.custody.entity.FundInfoEntity;
import com.friday.custody.entity.FundValuationEntity;
import com.friday.custody.enums.RetCodeEnum;
import com.friday.custody.exception.RRException;
import com.friday.custody.req.FundValuationReq;
import com.friday.custody.req.QueryDataReq;
import com.friday.custody.service.basicService.FundValuationService;
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.FundValuationVo;
import lombok.extern.slf4j.Slf4j;
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.util.*;
import java.util.stream.Collectors;


@Service("fundValuationService")
@Slf4j
public class FundValuationServiceImpl extends ServiceImpl<FundValuationDao, FundValuationEntity>
        implements FundValuationService , DataProcessService<FundValuationEntity> {


    @Autowired
    private FundInfoServiceImpl fundInfoService;
    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<FundValuationEntity> page = this.page(
                new Query<FundValuationEntity>().getPage(params),
                new QueryWrapper<FundValuationEntity>()
        );

        return new PageUtils(page);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public R saveData(String type, List<FundValuationEntity> fundValuationEntities) {
        if (CollectionUtils.isEmpty(fundValuationEntities)){
            return R.ok();
        }

        fundValuationEntities = this.handleFundValuation(fundValuationEntities);

        List<String> rawUniqueKeyList = fundValuationEntities.stream().map(FundValuationEntity::getUniqueKey).collect(Collectors.toList());
        String ukList = String.join("--", rawUniqueKeyList);
        if (CollectionUtils.isNotEmpty(rawUniqueKeyList)) {
            Set<String> uniqueKeySet = baseMapper.queryUniqueKeyList(rawUniqueKeyList);
            if (!CollectionUtils.isEmpty(uniqueKeySet)) {
                baseMapper.deleteByUniqueKeys(uniqueKeySet);
            }

        }
        boolean saveStatus = this.saveBatch(fundValuationEntities);
        if (!saveStatus){
            log.error("保存基金估值表FundValuationInfo失败:{}",ukList);
        }
        return R.ok();
    }

    /**
     * 处理补全fundCode/fundName  设置组合主键
     * @param fundValuationEntities
     * @return
     */
    private List<FundValuationEntity> handleFundValuation(List<FundValuationEntity> fundValuationEntities) {
        for (FundValuationEntity entity : fundValuationEntities) {
            //如果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);
                }
            }
            if("36".equals(entity.getTrustNo())){
                entity.setUniqueKey(entity.getAdmin() + entity.getInnerFundCode() + entity.getFundName() + entity.getValueDate() + entity.getKmCode());
            } else {
                entity.setUniqueKey(entity.getAdmin() + entity.getFundCode() + entity.getFundName() + entity.getValueDate() + entity.getKmCode());
            }
        }
        return fundValuationEntities;
    }

    @Override
    public R queryData(QueryDataReq vo) {
        try {
            log.info("开始查询基金估值报表信息表...,租户信息为:{}", JSON.toJSONString(vo));
            //1 封装查询参数
            FundValuationReq fundValuationReq = JSON.parseObject(vo.getParams(), FundValuationReq.class);
            //1.1 封装分页查询参数
            Map<String, Object> pageParams = PageUtil.getPageParams(fundValuationReq);
            //1.2 封装查询参数
            QueryWrapper<FundValuationEntity> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("admin", vo.getTenantName());
            if (StringUtils.isNotBlank(fundValuationReq.getFundCode())) {
                queryWrapper.eq("fund_code", fundValuationReq.getFundCode());
            }
            if (StringUtils.isNotBlank(fundValuationReq.getInnerFundCode())){
                queryWrapper.eq("inner_fund_code",fundValuationReq.getInnerFundCode());
            }
            if (StringUtils.isNotBlank(fundValuationReq.getValueDate())) {
                queryWrapper.eq("value_date", fundValuationReq.getValueDate());
            }
            //建议km_code like 取值去掉左通配符%，左通配符%会导致索引失效，在此基础上建议创建联合索引（km_code,value_date,admin）
            if (StringUtils.isNotBlank(fundValuationReq.getKmCode())) {
                queryWrapper.likeRight("km_code", fundValuationReq.getKmCode());
            }
            //（按估值表日期valueDate（若存在）、基金备案编码fundCode（若存在）、基金内部代码innerFundCode（若存在）、科目编码kmCode（若存在）、托管人编码trustNo逆序排列）
            queryWrapper.orderBy(true,false, "value_date","fund_code","inner_fund_code","km_code","trust_no");
            //2 执行检索
            IPage<FundValuationEntity> page = this.page(
                    new Query<FundValuationEntity>().getPage(pageParams),
                    queryWrapper
            );
            //封装数据
            PageUtils pageUtils = new PageUtils(page);
            List<FundValuationEntity> entities = page.getRecords();
            //entities 转vo
            ArrayList<FundValuationVo> vos = new ArrayList<>();
            for (FundValuationEntity entity : entities) {
                vos.add(FundValuationVo.builder()
                        .id(entity.getId())
                        .fundCode(entity.getFundCode())
                        .innerFundCode(entity.getInnerFundCode())
                        .fundName(entity.getFundName())
                        .valueDate(entity.getValueDate())
                        .netValue(entity.getNetValue())
                        .kmCode(entity.getKmCode())
                        .kmName(entity.getKmName())
                        .currency(entity.getCurrency())
                        .vaRate(Objects.isNull(entity.getVaRate())?"":entity.getVaRate().toString())
                        .amount(Objects.isNull(entity.getAmount())?"":entity.getAmount().toString())
                        .perCost(Objects.isNull(entity.getPerCost())?"":entity.getPerCost().toString())
                        .origCost(Objects.isNull(entity.getOrigCost())?"":entity.getOrigCost().toString())
                        .portCost(Objects.isNull(entity.getPortCost())?"":entity.getPortCost().toString())
                        .costBi(Objects.isNull(entity.getCostBi())?"":entity.getCostBi().toString())
                        .vapPrice(Objects.isNull(entity.getVapPrice())?"":entity.getVapPrice().toString())
                        .origMv(Objects.isNull(entity.getOrigMv())?"":entity.getOrigMv().toString())
                        .portMv(Objects.isNull(entity.getPortMv())?"":entity.getPortMv().toString())
                        .mvBl(Objects.isNull(entity.getMvBl())?"":entity.getMvBl().toString())
                        .origIv(Objects.isNull(entity.getOrigIv())?"":entity.getOrigIv().toString())
                        .portIv(Objects.isNull(entity.getPortIv())?"":entity.getPortIv().toString())
                        .suspension(entity.getSuspension())
                        .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 FundValuationInfoServiceImpl RRException is :", rrException);
            return R.error(RetCodeEnum.OPERATION_ERROR.getCode(), rrException.getMsg());
        } catch (Exception e) {
            log.error("the QueryDataVo is :" + JSON.toJSONString(vo) + ".the FundValuationInfoServiceImpl Exception is :", e);
            return R.error(RetCodeEnum.OPERATION_ERROR.getCode(), "查询数据失败!");
        }
    }

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


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