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.service.trustService.zx.utils.SearchReturnClass;
import com.friday.custody.dao.FundInfoDao;
import com.friday.custody.dto.TenantEscrowAuthorizationInfoDto;
import com.friday.custody.entity.FundInfoEntity;
import com.friday.custody.enums.RetCodeEnum;
import com.friday.custody.exception.RRException;
import com.friday.custody.req.FundInfoReq;
import com.friday.custody.req.QueryDataReq;
import com.friday.custody.service.basicService.FundInfoService;
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.FundInfoVo;
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 org.springframework.util.ObjectUtils;

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

/**
 * 基金产品基本信息
 */
@Service("fundInfoService")
@Slf4j
public class FundInfoServiceImpl extends ServiceImpl<FundInfoDao, FundInfoEntity>
        implements FundInfoService, DataProcessService<FundInfoEntity> {

    @Autowired
    FundInfoDao fundInfoDao;
    @Autowired
    SearchReturnClass searchReturnClass;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public R saveData(String type, List<FundInfoEntity> datas) {
        if (CollectionUtils.isEmpty(datas)){
            return R.ok();
        }
        List<FundInfoEntity> fundInfoEntities = handleData(datas);
        List<FundInfoEntity> uniqueFundInfoList = fundInfoEntities.stream().collect(Collectors.collectingAndThen
                (Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing
                        (FundInfoEntity::getUniqueKey))), ArrayList::new));

        List<String> rawUniqueKeyList = uniqueFundInfoList
                .stream()
                .map(FundInfoEntity::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(uniqueFundInfoList);
        if (!saveStatus) {
            log.error("保存FundInfo失败:{}", ukList);
        }
        return R.ok();
    }
    private List<FundInfoEntity> handleData(List<FundInfoEntity> fundInfoEntities) {
        List<FundInfoEntity> fundInfoEntityList = new ArrayList<>();
        //查询出当前管理人下的基金信息
        List<Map<String, Object>> prtList = searchReturnClass.queryPrtInfo(fundInfoEntities.get(0).getAdmin());
        log.info("查询到基金信息：{}", prtList);
        for (FundInfoEntity entity : fundInfoEntities) {
            try {
                if (StringUtils.isBlank(entity.getFundCode()) || StringUtils.isBlank(entity.getFundName())) {
                    if (prtList != null) {
                        for (Map<String, Object> prt : prtList) {
                            if (prt.get("REGCODE").equals(entity.getFundCode()) || prt.get("FUNDFULLNAME").equals(entity.getFundName())) {
                                entity.setFundCode(prt.get("REGCODE").toString());
                                entity.setFundName(prt.get("FUNDFULLNAME").toString());
                                break;
                            }
                        }
                    }
                }
            } catch (Exception e) {
                log.error("设置fundCode,fundName失败！", e);
            }
            //如果fundCOde\fundName其中一个没有补全,则不落库
            if (StringUtils.isBlank(entity.getFundCode()) || StringUtils.isBlank(entity.getFundName())) {
                continue;
            }
            if ("36".equals(entity.getTrustNo()) || "30".equals(entity.getTrustNo())) {
                entity.setUniqueKey(entity.getAdmin() + entity.getInnerFundCode() + entity.getFundName());
            } else if ("42".equals(entity.getTrustNo())) {
                entity.setUniqueKey(entity.getAdmin() + entity.getTrustNo() + entity.getInnerFundCode());
            } else if ("33".equals(entity.getTrustNo()) || "41".equals(entity.getTrustNo())) {
                entity.setUniqueKey(entity.getAdmin() + entity.getTrustNo() + entity.getFundCode());
            } else if ("43".equals(entity.getTrustNo())) {
                entity.setUniqueKey(entity.getAdmin() + entity.getTrustNo() + entity.getFundCode() + entity.getFundName());
            } else {
                entity.setUniqueKey(entity.getAdmin() + entity.getFundCode() + entity.getFundName());
            }
            fundInfoEntityList.add(entity);
        }
        return fundInfoEntityList;
    }

    @Override
    public R queryData(QueryDataReq vo) {
        try {
            log.info("开始查询基金产品信息表...,租户信息为:{}", JSON.toJSONString(vo));
            //1 封装查询参数
            FundInfoReq fundInfoReq = JSON.parseObject(vo.getParams(), FundInfoReq.class);
            //1.1 封装分页查询参数
            Map<String, Object> pageParams = PageUtil.getPageParams(fundInfoReq);
            //1.2 封装查询参数
            QueryWrapper<FundInfoEntity> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("admin", vo.getTenantName());
            if (StringUtils.isNotBlank(fundInfoReq.getFundCode())) {
                queryWrapper.eq("fund_code", fundInfoReq.getFundCode());
            }
            if (StringUtils.isNotBlank(fundInfoReq.getFundName())) {
                queryWrapper.likeRight("fund_name", fundInfoReq.getFundName());
            }
            if (StringUtils.isNotBlank(fundInfoReq.getFundLevel())) {
                queryWrapper.eq("fund_level", fundInfoReq.getFundLevel());
            }
            //新增innerFundCode查询条件
            if (StringUtils.isNotBlank(fundInfoReq.getInnerFundCode())) {
                queryWrapper.eq("inner_fund_code", fundInfoReq.getInnerFundCode());
            }
            queryWrapper.orderBy(true, false, "create_date", "fund_code", "inner_fund_code", "trust_no");
            //2 执行检索
            IPage<FundInfoEntity> page = this.page(
                    new Query<FundInfoEntity>().getPage(pageParams),
                    queryWrapper
            );
            //封装数据
            PageUtils pageUtils = new PageUtils(page);
            List<FundInfoEntity> entities = page.getRecords();
            //entities 转vo
            ArrayList<FundInfoVo> vos = new ArrayList<>();
            for (FundInfoEntity entity : entities) {
                vos.add(FundInfoVo.builder()
                        .id(entity.getId())
                        .fundCode(StringUtils.isBlank(entity.getFundCode()) ? "" : entity.getFundCode())
                        .innerFundCode(entity.getInnerFundCode())
                        .fundName(entity.getFundName())
                        .orgForm(entity.getOrgForm())
                        .fundType(entity.getFundType())
                        .peType(entity.getPeType())
                        .fundStatus(entity.getFundStatus())
                        .operationMethod(entity.getOperationMethod())
                        .durationType(entity.getDurationType())
                        .durationPeriod(entity.getDurationPeriod())
                        .settlementType(entity.getSettlementType())
                        .serviceMode(entity.getServiceMode())
                        .confDays(entity.getConfDays())
                        .createDate(entity.getCreateDate())
                        .fundLevel(entity.getFundLevel())
                        .trustNo(entity.getTrustNo())
                        .trustPersonNo(entity.getTrustPersonNo())
                        .build());
            }
            pageUtils.setList(vos);
            log.info("基金产品基本信息查询成功...");
            return R.ok("基金产品基本信息查询成功").put("data", pageUtils);
        } catch (RRException rrException) {
            log.error("the QueryDataVo is :" + JSON.toJSONString(vo) + ".the FundInfoServiceImpl RRException is :", rrException);
            return R.error(RetCodeEnum.OPERATION_ERROR.getCode(), rrException.getMsg());
        } catch (Exception e) {
            log.error("the QueryDataVo is :" + JSON.toJSONString(vo) + ".the FundInfoServiceImpl Exception is :", e);
            return R.error(RetCodeEnum.OPERATION_ERROR.getCode(), "查询数据失败!");
        }
    }


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

    public String getFundCodeByFundCode(String fundCode) {
        return fundInfoDao.getFundCodeByFundCode(fundCode);
    }

    public List<String> getFundCodeList(String trustNo, String tenantName) {
        return fundInfoDao.getFundCodeList(trustNo, tenantName);
    }


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

    @Autowired
    private DataDictionaryBasicService dataDictionaryBasicService;
    public static final int BATCH_LIST_SIZE = 500;


    @Override
    public R updateStatus(ArrayList<FundInfoEntity> fundInfoEntities) {
        for (FundInfoEntity entity : fundInfoEntities) {
            try {
                entity.setUniqueKey(entity.getAdmin() + entity.getFundCode() + entity.getFundName());
                if (baseMapper.updateStatus(entity)) {
                    continue;
                }
            } catch (Exception e) {
                log.error("FundInfoServiceImpl:updateStatus:", e);
            }
            //todo 需要写一个记录失败的表
        }
        return R.ok();
    }

    @Override
    public List<FundInfoEntity> getListByTrustNoAndAdmin(TenantEscrowAuthorizationInfoDto tenant) {
        String trustNo = tenant.getTrustNo();
        String admin = tenant.getTenantName();
        QueryWrapper<FundInfoEntity> wrapper = new QueryWrapper<FundInfoEntity>().eq("trust_no", trustNo).eq("admin", admin);
        List<FundInfoEntity> list = this.list(wrapper);
        log.debug("getListByTrustNoAndAdmin:{}", JSON.toJSONString(list));
        return list;
    }

    public String getFundNameByInnerFundCode(String innerFundCode, String trustNo) {
        return fundInfoDao.selectFundNameByInnerFundCode(innerFundCode, trustNo);
    }

    public String getFundNameByFundCode(String fundCode, String trustNo, String admin) {
        return fundInfoDao.selectFundNameByFundCode(fundCode, trustNo, admin);
    }

    public String getInnerFundCodeByName(String fundName, String trustNo, String admin) {
        return fundInfoDao.selectInnerFundCodeByFundName(fundName, trustNo, admin);
    }

    public List<FundInfoEntity> getDataByFundCode(String fundCode, String trustNo, String admin) {
        return fundInfoDao.getDataByFundCode(fundCode, trustNo, admin);
    }

    public List<FundInfoEntity> getListByFundCode(String fundCode, String trustNo) {
        QueryWrapper<FundInfoEntity> wrapper = new QueryWrapper<FundInfoEntity>().
                eq("fund_code", fundCode)
                .eq("trust_no", trustNo);

        List<FundInfoEntity> fundInfoEntities = baseMapper.selectList(wrapper);
        log.info("getListByFundCode_fundCode={},trustNo={},result={}", fundCode, trustNo, JSON.toJSONString(fundInfoEntities));
        return fundInfoEntities;
    }

    public List<FundInfoEntity> getDataByTrustNo(String trustNo) {
        return fundInfoDao.getDataByTrustNo(trustNo);
    }

    public List<String> getInnerFundCode(String trustNo, String tenantName) {
        return fundInfoDao.getInnerFundCode(trustNo, tenantName);
    }

    public String getInnerFundCodeByInnerFundCode(String innerFundCode) {
        return fundInfoDao.getInnerFundCodeByInnerFundCode(innerFundCode);
    }

    public String getFundCodeByName(String fundName, String trustNo) {
        return fundInfoDao.getFundCodeByName(fundName, trustNo);
    }

    public String getFundCodeByFundName(String fundName, String trustNo, String tenantName) {
        return fundInfoDao.getFundCodeByFundName(fundName, trustNo, tenantName);
    }

    public FundInfoEntity queryByInnerFundCode(String innerFundCode) {
        QueryWrapper<FundInfoEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("inner_fund_code", innerFundCode);
        return baseMapper.selectOne(queryWrapper);
    }

    public List<FundInfoEntity> getFundCodeAndFundNameAndInnerFundCodeFromFundInfo(String admin, String trustNo) {
        QueryWrapper<FundInfoEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("trust_no", trustNo);
        queryWrapper.eq("admin", admin);

        queryWrapper.select("DISTINCT fund_code,fund_name,inner_fund_code");
        queryWrapper.orderByDesc("id");

        List<FundInfoEntity> fundInfoEntities = this.baseMapper.selectList(queryWrapper);
        return fundInfoEntities;
    }

    public List<FundInfoEntity> getInnerFundCodeAsKeyFundCodeAsValueMap(String trustNo, String admin) {
        QueryWrapper<FundInfoEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("trust_no", trustNo);
        queryWrapper.eq("admin", admin);

        queryWrapper.select("DISTINCT fund_code,inner_fund_code");
        List<FundInfoEntity> fundInfoEntities = this.baseMapper.selectList(queryWrapper);

        return fundInfoEntities;
    }

    public FundInfoEntity queryByInnerFundCode(String trustNo, String admin, String innerFundCode){
        QueryWrapper<FundInfoEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("trust_no", trustNo);
        queryWrapper.eq("admin", admin);
        queryWrapper.eq("inner_fund_code", innerFundCode);
        FundInfoEntity fundInfoEntity = baseMapper.selectOne(queryWrapper);
        return fundInfoEntity;
    }

    public FundInfoEntity queryByFundName(String trustNo, String admin, String fundName){
        FundInfoEntity fundInfoEntity = baseMapper.selectByFundName(trustNo, admin, fundName);
        if (ObjectUtils.isEmpty(fundInfoEntity)){
            log.info("fundName={}查询为空!", fundName);
        }
        return fundInfoEntity;
    }
}