package com.friday.custody.service.trustService.yinhe.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONPath;
import com.friday.base.common.response.DubboResult;
import com.friday.custody.entity.*;
import com.friday.custody.service.basicService.impl.*;
import com.friday.custody.service.trustService.yinhe.common.YHContants;
import com.friday.custody.common.CustodyContants;
import com.friday.custody.dto.TenantEscrowAuthorizationInfoDto;
import com.friday.custody.enums.DataDictionaryTypeEnum;
import com.friday.custody.service.basicService.DataDictionaryTypeCertificateCsdcService;
import com.friday.custody.service.logicService.impl.DataDictionaryBasicServiceImpl;
import com.friday.custody.service.trustService.OutsourceService;
import com.friday.custody.service.trustService.yinhe.utils.FmpUtils;
import com.friday.custody.utils.BigDecimalUtil;
import com.friday.custody.utils.MatchDataDictionaryKeyUtil;
import com.friday.custody.utils.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;

@Slf4j
@Service
public class OutSourceYinHeServiceImpl implements OutsourceService {

    @Autowired
    FmpUtils fmpUtils;
    @Autowired
    private FundNetValueInfoServiceImpl fundNetValueInfoService;
    @Autowired
    private FundInfoServiceImpl fundInfoService;
    @Autowired
    private InvestorInfoServiceImpl investorInfoService;
    @Autowired
    private DataDictionaryBasicServiceImpl dataDictionaryBasicService;
    @Autowired
    private FundTradeInfoServiceImpl fundTradeInfoService;
    @Autowired
    private DataDictionarySellerServiceImpl sellerService;
    @Autowired
    private FundProfitInfoServiceImpl fundProfitInfoService;
    @Autowired
    private DataDictionaryTypeCertificateCsdcService certificateCsdcService;
    @Autowired
    private CustShareInfoServiceImpl custShareInfoService;
    @Autowired
    private FundOpenInfoServiceImpl fundOpenInfoService;
    @Autowired
    private DataDictionaryOpenStateServiceImpl openStateService;

    @Autowired
    @Lazy
    OutSourceYinHeServiceImpl outSourceYinHeService;


    @Override
    public R initTenantData(List<TenantEscrowAuthorizationInfoDto> tenants) {
        return null;
    }

    @Override
    public R initTenantDataSingle(TenantEscrowAuthorizationInfoDto tenant) {
        int loopTime = CustodyContants.INIT_BY_MONTH_LOOP_TIME;
        getDataFromYinHe(tenant, loopTime);
        return R.ok("初始化银河证券成功！");
    }

    private void getDataFromYinHe(TenantEscrowAuthorizationInfoDto tenant, int loopTime) {
        String trustNo = "33";
        //基金净值信息表 (fund_net_value_info)
        processFundNetValueInfoData(tenant, trustNo, loopTime);
        //基金出资人信息表（investor_info)
        processInvestorInfoData(tenant, trustNo);
        //基金交易确认信息表（fund_trade_info)
        processFundTradeInfoData(tenant, trustNo, loopTime);
        //业绩报酬信息表（fund_profit_info)
        processFundProfitInfoData(tenant, trustNo);
        //基金持有份额明细表（cust_share_detail_info）
        processCustShareInfoData(tenant, trustNo);
        //基金产品开放信息表-fund_open_info
        processFundOpenInfoData(tenant, trustNo, loopTime);
    }
    private void getUpdateDataFromYinHe(TenantEscrowAuthorizationInfoDto tenant, int loopTime) {
        String trustNo = "33";
        //基金出资人信息表（investor_info)
        processInvestorInfoData(tenant, trustNo);
        //基金交易确认信息表（fund_trade_info)
        processFundTradeInfoData(tenant, trustNo, loopTime);
        //业绩报酬信息表（fund_profit_info)
        processFundProfitInfoData(tenant, trustNo);
        //基金持有份额明细表（cust_share_detail_info）
        processCustShareInfoData(tenant, trustNo);
        //基金产品开放信息表-fund_open_info
        processFundOpenInfoData(tenant, trustNo, loopTime);
    }

    public void processFundOpenInfoData(TenantEscrowAuthorizationInfoDto tenant, String trustNo, int loopTime) {
        String startDate;
        String endDate;
        LocalDate localDate = LocalDate.now();
        LocalDate lastMonth;
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMdd");
        endDate = dateTimeFormatter.format(localDate);
        for (int i = 0; i < loopTime; i++) {
            lastMonth = localDate.minusMonths(1);
            startDate = dateTimeFormatter.format(lastMonth);
            String finalStartDate = startDate;
            String finalEndDate = endDate;
            try {
                int pageIndex = 0;
                int pageSize = 500;
                for (; ; ) {
                    pageIndex++;
                    //封装请求参数
                    Map<String, Object> paramMap = new HashMap<>();
                    //分页参数
                    paramMap.put("paging", "1");
                    paramMap.put("pageLength", pageSize);
                    paramMap.put("pageNo", pageIndex);
                    //其他参数
                    paramMap.put("bizOccurDateQ", finalStartDate);
                    paramMap.put("bizOccurDateH", finalEndDate);
                    JSONObject params = JSONObject.parseObject(JSONObject.toJSONString(paramMap));
                    JSONObject result = fmpUtils.sendMessage(tenant, YHContants.FUND_OPEN_INFO, params);
                    log.info("yinHe: processFundOpenInfoData : params = {} ,result = {}", params, result);
                    int totalCount = 0;
                    if (!ObjectUtils.isEmpty(result) && "0000".equals(JSONPath.extract(JSONObject.toJSONString(result), "$.meta.code"))) {
                        totalCount = Integer.parseInt(JSONPath.extract(JSONObject.toJSONString(result), "$.pageInfo.Total").toString());
                        log.info("yinHe: processFundOpenInfoData : totalCount = {} ", totalCount);
                        Object data = result.get("data");
                        if (!ObjectUtils.isEmpty(data)) {
                            List<JSONObject> remoteData = JSONObject.parseArray(JSONObject.toJSONString(data), JSONObject.class);
                            log.info("yinHe: processFundOpenInfoData : dataSize = {}", remoteData.size());
                            List<FundOpenInfoEntity> fundOpenInfoEntities = getFundOpenInfo(tenant, trustNo, remoteData);
                            log.info("yinHe: processFundOpenInfoData : 转义后FundOpenInfo dataSize = {}", fundOpenInfoEntities.size());
                            fundOpenInfoService.saveData(null, fundOpenInfoEntities);
                        }
                    }
                    if (pageSize * pageIndex >= totalCount){
                        break;
                    }
                }
            } catch (Exception e) {
                log.error("获取fundOpenInfoData失败！", e);
            }
            localDate = lastMonth;
            endDate = startDate;
        }
    }

    private List<FundOpenInfoEntity> getFundOpenInfo(TenantEscrowAuthorizationInfoDto tenant, String trustNo, List<JSONObject> remoteData) {
        //获取数据字典
        Map<String, String> typeOfOpenDayDic = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.TYPE_OF_OPEN_DAY_SERVICE, trustNo);//开放日类型
        //开放状态
        Map<String, Map<String, String>> openStateDic = openStateService.queryOpenStateWithDetail(trustNo);
        //封装数据
        List<FundOpenInfoEntity> entityList = new ArrayList<>();
        Map<String, String> dataMap;
        for (JSONObject data : remoteData){
            dataMap = JSONObject.toJavaObject(data, Map.class);
            //将openDayType转义为对应的keyStr
            String openType = MatchDataDictionaryKeyUtil.getKey(typeOfOpenDayDic, dataMap.get("trdDailyType"));
            //上游数据格式a;b  将上游数据以;劈开，并将上游开放状态转义为标准数据字典并以,隔开
            List<String> bizTypeKeys = Arrays.asList(dataMap.get("bizTypeKey").split(";"));
            String openStateStr = "";
            if (!ObjectUtils.isEmpty(bizTypeKeys)){
                for (String bizType : bizTypeKeys) {
                    String openState = MatchDataDictionaryKeyUtil.getKey(openType, openStateDic, bizType);
                    openStateStr += openState + ",";
                }
                openStateStr = openStateStr.substring(0, openStateStr.length() - 1);//去掉最后一个逗号
            }
            entityList.add(FundOpenInfoEntity.builder()
                    .fundOpenDate(dataMap.get("bizOccurDate").replaceAll("-",""))
                    .innerFundCode(dataMap.get("prdId"))
                    .fundName(dataMap.get("prdName"))
                    .fundCode(dataMap.get("prdCode"))
                    .openStatus(openStateStr)
                    .openType(openType)
                    .trustNo(trustNo)
                    .admin(tenant.getTenantName())
                    .createTime(new Date())
                    .updateTime(new Date())
                    .build());
        }
        return entityList;
    }

    public void processCustShareInfoData(TenantEscrowAuthorizationInfoDto tenant, String trustNo) {
        try {
            int pageIndex = 0;
            int pageSize = 500;
            List<CustShareInfoEntity> entityList = new ArrayList<>();
            for (; ; ) {
                pageIndex++;
                //封装请求参数
                Map<String, Object> paramMap = new HashMap<>();
                //分页参数
                paramMap.put("paging", "1");
                paramMap.put("pageLength", pageSize);
                paramMap.put("pageNo", pageIndex);
                //其他参数
                JSONObject params = JSONObject.parseObject(JSONObject.toJSONString(paramMap));
                JSONObject result = fmpUtils.sendMessage(tenant, YHContants.CUST_SHARE_INFO, params);
                log.info("yinHe: processCustShareInfoData : params = {} ,result = {}", params, result);
                int totalCount = 0;
                if (!ObjectUtils.isEmpty(result) && "0000".equals(JSONPath.extract(JSONObject.toJSONString(result), "$.meta.code"))) {
                    totalCount = Integer.parseInt(JSONPath.extract(JSONObject.toJSONString(result), "$.pageInfo.Total").toString());
                    log.info("yinHe: processCustShareInfoData : totalCount = {} ", totalCount);
                    Object data = result.get("data");
                    if (!ObjectUtils.isEmpty(data)) {
                        List<JSONObject> remoteData = JSONObject.parseArray(JSONObject.toJSONString(data), JSONObject.class);
                        log.info("yinHe: processCustShareInfoData : dataSize = {}", remoteData.size());
                        List<CustShareInfoEntity> custShareInfoEntities = getCustShareInfo(tenant, trustNo, remoteData);
                        log.info("yinHe: processCustShareInfoData : 转义后custShareInfo dataSize = {}", custShareInfoEntities.size());
                        entityList.addAll(custShareInfoEntities);
                    }
                }
                if (pageSize * pageIndex >= totalCount) {
                    break;
                }
            }
            custShareInfoService.saveData(null, entityList);
        } catch (Exception e) {
            log.error("批量保存investInfo失败！", e);
        }
    }
    private List<CustShareInfoEntity> getCustShareInfo(TenantEscrowAuthorizationInfoDto tenant, String trustNo, List<JSONObject> remoteData) {
        //获取数据字典
        //封装数据
        List<CustShareInfoEntity> entityList = new ArrayList<>();
        Map<String, String> dataMap;
        for (JSONObject data : remoteData){
            dataMap = JSONObject.toJavaObject(data, Map.class);
            String agencyNo = sellerService.queryAgencyNo("银河证券", dataMap.get("retailer"));
            //获得fundNetValue中的Shares
            FundNetValueInfoEntity fundNetValueInfoEntity = FundNetValueInfoEntity.builder()
                    .admin(tenant.getTenantName())
                    .fundCode(dataMap.get("fundCode"))
                    .fundName(dataMap.get("prdFullName"))
                    .netValueDate(dataMap.get("updDate").replaceAll("-","")).build();
            BigDecimal shares = fundNetValueInfoService.getSharesByFundInfo(fundNetValueInfoEntity);
            BigDecimal lastHoldShares = BigDecimalUtil.obj2BigDecimalTrunToZero(dataMap.get("shareBal").replaceAll(",",""));
            BigDecimal frozenShare = BigDecimalUtil.obj2BigDecimalTrunToZero(dataMap.get("frzShare").replaceAll(",",""));
            entityList.add(CustShareInfoEntity.builder()
                    .fundName(dataMap.get("prdFullName"))
                    .fundCode(dataMap.get("fundCode"))
                    .fundAcco(dataMap.get("fundAcct"))
                    .tradeAcco(dataMap.get("trdAcct"))
                    .lastHoldShares(lastHoldShares)
                    .frozenShares(frozenShare)
                    .netValueDate(dataMap.get("updDate").replaceAll("-",""))
                    .agencyName(dataMap.get("retailer"))
                    .agencyNo(agencyNo)
                    .shareRatio(BigDecimalUtil.getShareRatio(shares, lastHoldShares))
                    .enableShares(BigDecimalUtil.obj2BigDecimalTrunToZero(lastHoldShares.subtract(frozenShare)))
                    .trustNo(trustNo)
                    .admin(tenant.getTenantName())
                    .createTime(new Date())
                    .updateTime(new Date())
                    .build());
        }
        return entityList;
    }

    public void processFundProfitInfoData(TenantEscrowAuthorizationInfoDto tenant, String trustNo) {
        try {
            int pageIndex = 0;
            int pageSize = 500;
            for (; ; ) {
                pageIndex++;
                //封装请求参数
                Map<String, Object> paramMap = new HashMap<>();
                //分页参数
                paramMap.put("paging", "1");
                paramMap.put("pageLength", pageSize);
                paramMap.put("pageNo", pageIndex);
                //其他参数
                JSONObject params = JSONObject.parseObject(JSONObject.toJSONString(paramMap));
                JSONObject result = fmpUtils.sendMessage(tenant, YHContants.FUND_PROFIT_INFO, params);
                log.info("yinHe: processFundProfitInfoData : params = {} ,result = {}", params, result);
                int totalCount = 0;
                if (!ObjectUtils.isEmpty(result)) {
                    totalCount = Integer.parseInt(JSONPath.extract(JSONObject.toJSONString(result), "$.pageInfo.Total").toString());
                    log.info("yinHe: processFundProfitInfoData : totalCount = {} ", totalCount);
                    Object data = result.get("data");
                    if (!ObjectUtils.isEmpty(data) && "0000".equals(JSONPath.extract(JSONObject.toJSONString(result), "$.meta.code"))) {
                        List<JSONObject> remoteData = JSONObject.parseArray(JSONObject.toJSONString(data), JSONObject.class);
                        log.info("yinHe: processFundProfitInfoData : dataSize = {}, data = {}", remoteData.size(), remoteData);
                        List<FundProfitInfoEntity> fundProfitInfoEntities = getFundProfitInfo(tenant, trustNo, remoteData);
                        log.info("yinHe: processFundProfitInfoData : 转义后FundProfitInfoData dataSize = {}, data = {}", fundProfitInfoEntities.size(), fundProfitInfoEntities);
                        fundProfitInfoService.saveData(null, fundProfitInfoEntities);
                    }
                }
                if (pageSize * pageIndex >= totalCount) {
                    break;
                }
            }
        } catch (Exception e) {
            log.error("批量保存investInfo失败！", e);
        }
    }

    private List<FundProfitInfoEntity> getFundProfitInfo(TenantEscrowAuthorizationInfoDto tenant, String trustNo, List<JSONObject> remoteData) {
        //获取字典
        Map<String, String> sellerDic = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.SELLER_SERVICE, "银河证券");//销售商
        Map<String, String> paymentWayDic = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.PAYMENT_WAY_SERVICE, trustNo);//支付方式
        Map<String, String> accrualWayDic = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.ACCRUAL_WAY_SERVICE, trustNo);
        //封装数据
        List<FundProfitInfoEntity> entityList = new ArrayList<>();
        Map<String, String> dataMap;
        for(JSONObject data : remoteData){
            dataMap = JSONObject.toJavaObject(data, Map.class);
            //根据agencyNo找到对应的agencyName
            String agencyName = sellerService.queryAgencyName("银河证券", dataMap.get("retailerCode"));
            entityList.add(FundProfitInfoEntity.builder()
                    .cserialNo(dataMap.get("taConfirmSnNo").length() > 32 ? dataMap.get("taConfirmSnNo").substring(0, 32) : dataMap.get("taConfirmSnNo"))
                    .requestDate(dataMap.get("clearDate").replaceAll("-", ""))
                    .confirmDate(dataMap.get("trdConfirmDate").replaceAll("-",""))
                    .fundAcco(dataMap.get("fundAcct"))
                    .fundCode(dataMap.get("fundCode"))
                    .fundName(dataMap.get("prdName"))
                    .agencyNo(MatchDataDictionaryKeyUtil.getKey(sellerDic, dataMap.get("retailerCode")))
                    .tradeAcco(dataMap.get("trdAcct"))
                    .branchCode(dataMap.get("orgNo"))
                    .shareType(MatchDataDictionaryKeyUtil.getKey(paymentWayDic, dataMap.get("collectFeeMode")))
                    .triggerType(MatchDataDictionaryKeyUtil.getKey(accrualWayDic, dataMap.get("triggerMode")))
                    .oriCserialNo(dataMap.get("taConfirmPursSnNo").length() > 32 ? dataMap.get("taConfirmPursSnNo").substring(0, 32) : dataMap.get("taConfirmPursSnNo"))
                    .shares(BigDecimalUtil.obj2BigDecimalTrunToZero(dataMap.get("joinInProvisionShare").replaceAll(",","")))
                    .oriDate(dataMap.get("bgngDate").replaceAll("-",""))
                    .oriTotalNav(BigDecimalUtil.obj2BigDecimalTrunToZero(dataMap.get("bgngAggrNetVal").replaceAll(",",""), 4))
                    .oriNav(BigDecimalUtil.obj2BigDecimalTrunToZero(dataMap.get("bgngUnitNetVal").replaceAll(",",""), 4))
                    .nav(BigDecimalUtil.obj2BigDecimalTrunToZero(dataMap.get("provisionUnitNetVal").replaceAll(",",""), 4))
                    .totalNav(BigDecimalUtil.obj2BigDecimalTrunToZero(dataMap.get("provisionAggrNetVal").replaceAll(",",""), 4))
                    .factBalance(BigDecimalUtil.obj2BigDecimalTrunToZero(dataMap.get("provisionAmt").replaceAll(",","")))
                    .agencyName(agencyName)
                    .trustNo(trustNo)
                    .admin(tenant.getTenantName())
                    .createTime(new Date())
                    .updateTime(new Date())
                    .build());
        }
        return entityList;
    }


    public void processFundTradeInfoData(TenantEscrowAuthorizationInfoDto tenant, String trustNo, int loopTime) {
        String startDate;
        String endDate;
        LocalDate localDate = LocalDate.now();
        LocalDate lastMonth;
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMdd");
        endDate = dateTimeFormatter.format(localDate);
        for (int i = 0; i < loopTime; i++) {
            lastMonth = localDate.minusMonths(1);
            startDate = dateTimeFormatter.format(lastMonth);
            String finalStartDate = startDate;
            String finalEndDate = endDate;
            try {
                int pageIndex = 0;
                int pageSize = 500;
                for (; ; ) {
                    pageIndex++;
                    //封装请求参数
                    Map<String, Object> paramMap = new HashMap<>();
                    //分页参数
                    paramMap.put("paging", "1");
                    paramMap.put("pageLength", pageSize);
                    paramMap.put("pageNo", pageIndex);
                    //其他参数
                    paramMap.put("startDate", finalStartDate);
                    paramMap.put("endDate", finalEndDate);
                    JSONObject params = JSONObject.parseObject(JSONObject.toJSONString(paramMap));
                    JSONObject result = fmpUtils.sendMessage(tenant, YHContants.FUND_TRADE_INFO, params);
                    log.info("yinHe: processFundTradeInfoData : params = {} ,result = {}", params, result);
                    int totalCount = 0;
                    if (!ObjectUtils.isEmpty(result) && "0000".equals(JSONPath.extract(JSONObject.toJSONString(result), "$.meta.code"))) {
                        totalCount = Integer.parseInt(JSONPath.extract(JSONObject.toJSONString(result), "$.pageInfo.Total").toString());
                        log.info("yinHe: processFundTradeInfoData : totalCount = {} ", totalCount);
                        Object data = result.get("data");
                        if (!ObjectUtils.isEmpty(data)) {
                            List<JSONObject> remoteData = JSONObject.parseArray(JSONObject.toJSONString(data), JSONObject.class);
                            log.info("yinHe: processFundTradeInfoData : dataSize = {}", remoteData.size());
                            List<FundTradeInfoEntity> fundTradeInfoEntities = getFundTradeInfo(tenant, trustNo, remoteData);
                            log.info("yinHe: processFundTradeInfoData : 转义后FundTradeInfo dataSize = {}", fundTradeInfoEntities.size());
                            fundTradeInfoService.saveData(null, fundTradeInfoEntities);
                        }
                    }
                    if (pageSize * pageIndex >= totalCount){
                        break;
                    }
                }
            } catch (Exception e) {
                log.error("批量保存fundTradeInfo失败！", e);
            }
            localDate = lastMonth;
            endDate = startDate;
        }
    }

    private List<FundTradeInfoEntity> getFundTradeInfo(TenantEscrowAuthorizationInfoDto tenant, String trustNo, List<JSONObject> remoteData) {
        //获取字典
        Map<String, String> businessNameDic = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.BUSINESS_NAME_SERVICE, trustNo);//业务类型
        Map<String, String> sellerDic = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.SELLER_SERVICE, "银河证券");//销售商
        //封装数据
        List<FundTradeInfoEntity> entityList = new ArrayList<>();
        Map<String, String> dataMap;
        for (JSONObject data : remoteData){
            dataMap = JSONObject.toJavaObject(data, Map.class);
            entityList.add(FundTradeInfoEntity.builder()
                    .applyBalance(BigDecimalUtil.obj2BigDecimalTrunToZero(dataMap.get("appAmt").replaceAll(",","")))
                    .applyShares(BigDecimalUtil.obj2BigDecimalTrunToZero(dataMap.get("appShare").replaceAll(",","")))
                    .businessName(MatchDataDictionaryKeyUtil.getKey(businessNameDic, dataMap.get("bizCode")))
                    .tradeFare(BigDecimalUtil.obj2BigDecimalTrunToZero(dataMap.get("chrg").replaceAll(",","")))
                    .profitBalance(BigDecimalUtil.obj2BigDecimalTrunToZero(dataMap.get("perforReward").replaceAll(",","")))
                    .confirmShares(BigDecimalUtil.obj2BigDecimalTrunToZero(dataMap.get("confirmCopies").replaceAll(",","")))
                    .confirmDate(dataMap.get("confirmDate").replaceAll("-",""))
                    .confirmBalance(BigDecimalUtil.obj2BigDecimalTrunToZero(dataMap.get("confrimAmt").replaceAll(",","")))
                    .netValue(BigDecimalUtil.obj2BigDecimalTrunToZero(dataMap.get("price").replaceAll(",",""), 4))
                    .summary(dataMap.get("digestRemk"))
                    .agio(BigDecimalUtil.obj2BigDecimalTrunToZero(dataMap.get("discRate").replaceAll(",",""),4))
                    .fundAcco(dataMap.get("fundAcct"))
                    .fundCode(dataMap.get("fundCode"))
                    .fundName(dataMap.get("prdName"))
                    .agencyNo(MatchDataDictionaryKeyUtil.getKey(sellerDic, dataMap.get("retailer")))
                    .agencyName(dataMap.get("salerAbbr"))
                    .tradeAcco(dataMap.get("trdAcct"))
                    .cserialNo(dataMap.get("taConfirmSnNo").length() > 32 ? dataMap.get("taConfirmSnNo").substring(0,32) : dataMap.get("taConfirmSnNo"))
                    .requestDate(dataMap.get("occurDate").replaceAll("-",""))
                    .trustNo(trustNo)
                    .admin(tenant.getTenantName())
                    .createTime(new Date())
                    .updateTime(new Date())
                    .build());
        }
        return entityList;
    }


    public void processInvestorInfoData(TenantEscrowAuthorizationInfoDto tenant, String trustNo) {
        try {
            int pageIndex = 0;
            int pageSize = 500;
            for (; ; ) {
                pageIndex++;
                //封装请求参数
                Map<String, Object> paramMap = new HashMap<>();
                //分页参数
                paramMap.put("paging", "1");
                paramMap.put("pageLength", pageSize);
                paramMap.put("pageNo", pageIndex);
                //其他参数
                JSONObject params = JSONObject.parseObject(JSONObject.toJSONString(paramMap));
                JSONObject result = fmpUtils.sendMessage(tenant, YHContants.INVESTOR_INFO, params);
                log.info("yinHe: processInvestorInfoData : params = {} ,result = {}", params, result);
                int totalCount = 0;
                if (!ObjectUtils.isEmpty(result) && "0000".equals(JSONPath.extract(JSONObject.toJSONString(result), "$.meta.code"))) {
                    totalCount = Integer.parseInt(JSONPath.extract(JSONObject.toJSONString(result), "$.pageInfo.Total").toString());
                    log.info("yinHe: processInvestorInfoData : totalCount = {} ", totalCount);
                    Object data = result.get("data");
                    if (!ObjectUtils.isEmpty(data)) {
                        List<JSONObject> remoteData = JSONObject.parseArray(JSONObject.toJSONString(data), JSONObject.class);
                        log.info("yinHe: processInvestorInfoData : dataSize = {}", remoteData.size());
                        List<InvestorInfoEntity> investorInfoEntities = getInvestInfo(tenant, trustNo, remoteData);
                        log.info("yinHe: processInvestorInfoData : 转义后InvertorInfo dataSize = {}", investorInfoEntities.size());
                        investorInfoService.saveData(null, investorInfoEntities);
                    }
                }
                if (pageSize * pageIndex >= totalCount) {
                    break;
                }
            }
        } catch (Exception e) {
            log.error("批量保存investInfo失败！", e);
        }

    }

    private List<InvestorInfoEntity> getInvestInfo(TenantEscrowAuthorizationInfoDto tenant, String trustNo, List<JSONObject> remoteData) {
        //获取字典 
        //数据字典：证件类型 中登
        Map<String, Map<String, String>> identityTypeCsdcDic = certificateCsdcService.queryCertificateWithDetail(trustNo);
        //数据字典：客户类型 中登
        Map<String, String> custTypeDic = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.CUST_TYPE_CSDC_SERVICE, trustNo);
        //封装数据
        List<InvestorInfoEntity> entityList = new ArrayList<>();
        Map<String, String> dataMap;
        for (JSONObject data : remoteData){
            dataMap = JSONObject.toJavaObject(data, Map.class);
            String custType = MatchDataDictionaryKeyUtil.getKey(custTypeDic, dataMap.get("investorType"));
            entityList.add(InvestorInfoEntity.builder()
                    .fundAcco(dataMap.get("fundAcct"))
                    .custName(dataMap.get("custName"))
                    .identityType(MatchDataDictionaryKeyUtil.getKey(custType, identityTypeCsdcDic, dataMap.get("credentialsType")))
                    .identityNo(dataMap.get("idNo"))
                    .custType(custType)
                    .accoOpenDate(dataMap.get("opAcctDate").replaceAll("-",""))
                    .address(dataMap.get("comAddr"))
                    .mobileNo(dataMap.get("mob"))
                    .email(dataMap.get("email"))
                    .trustNo(trustNo)
                    .admin(tenant.getTenantName())
                    .createTime(new Date())
                    .updateTime(new Date())
                    .build());
        }
        return entityList;
    }

    public void processFundNetValueInfoData(TenantEscrowAuthorizationInfoDto tenant, String trustNo, int loopTime) {
        String startDate;
        String endDate;
        LocalDate localDate = LocalDate.now();
        LocalDate lastMonth;
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMdd");
        endDate = dateTimeFormatter.format(localDate);
        for (int i = 0; i < loopTime; i++) {
            lastMonth = localDate.minusMonths(1);
            startDate = dateTimeFormatter.format(lastMonth);
            String finalStartDate = startDate;
            String finalEndDate = endDate;
            try {
                int pageIndex = 0;
                int pageSize = 500;
                for (; ; ) {
                    pageIndex++;
                   //封装请求参数
                    Map<String, Object> paramMap = new HashMap<>();
                    //分页参数
                    paramMap.put("paging", "1");
                    paramMap.put("pageLength", pageSize);
                    paramMap.put("pageNo", pageIndex);
                    //其他参数
                    paramMap.put("startDate", finalStartDate);
                    paramMap.put("endDate", finalEndDate);
                    JSONObject params = JSONObject.parseObject(JSONObject.toJSONString(paramMap));
                    JSONObject result = fmpUtils.sendMessage(tenant, YHContants.FUND_NET_VALUE_INFO, params);
                    log.info("yinHe: processNetValueInfoData : params = {} ,result = {}", params, result);
                    int totalCount = 0;
                    if (!ObjectUtils.isEmpty(result) && "0000".equals(JSONPath.extract(JSONObject.toJSONString(result), "$.meta.code"))) {
                        totalCount = Integer.parseInt(JSONPath.extract(JSONObject.toJSONString(result), "$.pageInfo.Total").toString());
                        log.info("yinHe: processNetValueInfoData : totalCount = {} ", totalCount);
                        Object data = result.get("data");
                        if (!ObjectUtils.isEmpty(data)) {
                            List<JSONObject> remoteData = JSONObject.parseArray(JSONObject.toJSONString(data), JSONObject.class);
                            log.info("yinHe: processNetValueInfoData : dataSize = {}", remoteData.size());
                            List<FundNetValueInfoEntity> netValueInfoEntities = getFundNetValueData(tenant, trustNo, remoteData);
                            log.info("yinHe: processNetValueInfoData : 转义后FundNetValueData dataSize = {}", netValueInfoEntities.size());
                            fundNetValueInfoService.saveData(null, netValueInfoEntities);
                            List<FundInfoEntity> fundInfoEntities = getFundInfo(tenant, trustNo, remoteData);
                            fundInfoService.saveData(null, fundInfoEntities);
                            log.info("yinHe: processNetValueInfoData : 转义后FundInfoEntity dataSize = {}", fundInfoEntities.size());
                        }
                    }
                    if (pageSize * pageIndex >= totalCount){
                        break;
                    }
                }
            } catch (Exception e) {
                log.error("批量保存fundNetValueInfo失败！", e);
            }
            localDate = lastMonth;
            endDate = startDate;
        }
    }

    private List<FundInfoEntity> getFundInfo(TenantEscrowAuthorizationInfoDto tenant, String trustNo, List<JSONObject> remoteData) {
        //获取字典
        //封装数据
        List<FundInfoEntity> entityList = new ArrayList<>();
        Map<String, String> dataMap;
        for (JSONObject data : remoteData) {
            dataMap = JSONObject.toJavaObject(data, Map.class);
            entityList.add(FundInfoEntity.builder()
                    .innerFundCode(dataMap.get("prdId"))
                    .fundName(dataMap.get("prdName"))
                    .fundCode(dataMap.get("prdCode"))
                    .trustNo(trustNo)
                    .admin(tenant.getTenantName())
                    .createTime(new Date())
                    .updateTime(new Date())
                    .build());
        }
        return entityList;
    }

    private List<FundNetValueInfoEntity> getFundNetValueData(TenantEscrowAuthorizationInfoDto tenant,String trustNo, List<JSONObject> remoteData) {
        //获取字典
        //封装数据
        List<FundNetValueInfoEntity> entityList = new ArrayList<>();
        Map<String, String> dataMap;
        for (JSONObject data : remoteData){
            dataMap = JSONObject.toJavaObject(data, Map.class);
            entityList.add(FundNetValueInfoEntity.builder()
                    .innerFundCode(dataMap.get("prdId"))
                    .fundName(dataMap.get("prdName"))
                    .fundCode(dataMap.get("prdCode"))
                    .netValueDate(dataMap.get("valDate").replaceAll("-",""))
                    .netValue(BigDecimalUtil.obj2BigDecimalTrunToZero(dataMap.get("detlVal").replaceAll(",",""), 4))
                    .totalNetValue(BigDecimalUtil.obj2BigDecimalTrunToZero(dataMap.get("aggrNet").replaceAll(",",""), 4))
                    .assetValue(BigDecimalUtil.obj2BigDecimalTrunToZero(dataMap.get("assetNet").replaceAll(",","")))
                    .trustNo(trustNo)
                    .admin(tenant.getTenantName())
                    .createTime(new Date())
                    .updateTime(new Date())
                    .build());
        }
        return entityList;
    }

    @Override
    public R updateDataDaily(List<TenantEscrowAuthorizationInfoDto> tenants) {
        return null;
    }

    @Override
    public R updateSingleDataDaily(TenantEscrowAuthorizationInfoDto tenant) {
        log.info("更新银河证券托管数据开始......");
        int loopTime = CustodyContants.UPDATE_BY_MONTH_DAILY_LOOP_TIME;
        getUpdateDataFromYinHe(tenant, loopTime);
        log.info("更新银河证券托管数据完成......");
        return R.ok("更新银河证券托管成功！");
    }

    @Override
    public R PullRemoteDataFirstQueueJob() {
        return null;
    }

    @Override
    public R initLaterTenantData(String versionStr, List<TenantEscrowAuthorizationInfoDto> tenants) {
        return null;
    }

    @Override
    public R initLaterSingleTenantData(String versionStr, TenantEscrowAuthorizationInfoDto tenant) {
        log.info("xy:initLaterSingleTenantData is begin...the versionStr is {} ,the tenant is {}", versionStr, JSON.toJSONString(tenant));
        String trustNo = tenant.getTrustNo();
        Integer loopNum = CustodyContants.INIT_BY_MONTH_LOOP_TIME;
        switch (versionStr) {
            case CustodyContants.R_PT_S_CUSTODY_3_1_8_PATCH01:
                initTenantDataBy318patch01(tenant, trustNo, loopNum);
                break;
        }
        return null;
    }

    private void initTenantDataBy318patch01(TenantEscrowAuthorizationInfoDto tenant, String trustNo, Integer loopNum) {
        log.info("yinhe:initTenantDataBy318oatch01 is run...");
        try {
            processFundOpenInfoData(tenant, trustNo, loopNum);
            log.info("yinhe:initTenantDataBy318oatch01 is end...");
        } catch (Exception e) {
            log.error("yinhe:initTenantDataBy318oatch01 is error:", e);
        }
    }

    @Override
    public R initByAppointedTrustNoAndMouth(TenantEscrowAuthorizationInfoDto tenant, int mouth) {
        getDataFromYinHe(tenant, mouth);
        return R.ok("初始化银河证券成功！");
    }

    @Override
    public R updateData20min(List<TenantEscrowAuthorizationInfoDto> data) {
        return null;
    }

    @Override
    public R updateSingleData20min(TenantEscrowAuthorizationInfoDto tenant) {
        return null;
    }

    @Override
    public R updateData1h(List<TenantEscrowAuthorizationInfoDto> data) {
        return null;
    }

    @Override
    public R updateSingleData1h(TenantEscrowAuthorizationInfoDto tenant) {
        return null;
    }

    @Override
    public R updateDataCJ(String date, String flag, TenantEscrowAuthorizationInfoDto tenant) {
        return null;
    }

    @Override
    public R updateNetValueData(List<TenantEscrowAuthorizationInfoDto> tenants) {
        return null;
    }

    @Override
    public R updateSingleNetValueData(TenantEscrowAuthorizationInfoDto tenant) {
        log.info("银河证券每8点、12点、20点更新数据开始~");
        String trustNo = "33";
        int loopTime = CustodyContants.UPDATE_BY_MONTH_DAILY_LOOP_TIME;
        try {
            //3 基金净值信息表（fund_net_value_info）
            outSourceYinHeService.processFundNetValueInfoData(tenant, trustNo, loopTime);
            log.info("银河证券每8点、12点、20点更新数据结束~");
        }catch (Exception e){
            log.error("银河证券每8点、12点、20点更新数据异常！");
        }
        return R.ok("银河证券每8点、12点、20点更新数据完成！");
    }

    @Override
    public DubboResult updateMJBalanceData(TenantEscrowAuthorizationInfoDto tenant) {
        try {

            return DubboResult.newFailure(DubboResult.SERVER_EXCEPTION, "暂不支持");
        } catch (Exception e) {
            log.error("手动更新募集户余额失败", e);
            return DubboResult.newFailure(DubboResult.SERVER_EXCEPTION, "手动更新募集户余额失败" + e.getMessage());
        }
    }

    @Override
    public DubboResult updateMJSeqData(TenantEscrowAuthorizationInfoDto tenant) {
        try {

            return DubboResult.newFailure(DubboResult.SERVER_EXCEPTION, "暂不支持");
        } catch (Exception e) {
            log.error("手动更新募集户流水失败", e);
            return DubboResult.newFailure(DubboResult.SERVER_EXCEPTION, "手动更新募集户流水失败" + e.getMessage());
        }
    }

    @Override
    public DubboResult updateTGBalanceData(TenantEscrowAuthorizationInfoDto tenant) {
        try {

            return DubboResult.newFailure(DubboResult.SERVER_EXCEPTION, "暂不支持");
        } catch (Exception e) {
            log.error("手动更新托管户余额失败", e);
            return DubboResult.newFailure(DubboResult.SERVER_EXCEPTION, "手动更新托管户余额失败" + e.getMessage());
        }
    }

    @Override
    public DubboResult updateTGSeqData(TenantEscrowAuthorizationInfoDto tenant) {
        try {

            return DubboResult.newFailure(DubboResult.SERVER_EXCEPTION, "暂不支持");
        } catch (Exception e) {
            log.error("手动更新托管户流水失败", e);
            return DubboResult.newFailure(DubboResult.SERVER_EXCEPTION, "手动更新托管户流水失败" + e.getMessage());
        }
    }
}
