package com.yd.csf.service.service.impl;

import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.yd.auth.core.dto.AuthUserDto;
import com.yd.auth.core.utils.SecurityUtil;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yd.common.enums.CommonEnum;
import com.yd.common.enums.ResultCode;
import com.yd.common.exception.BusinessException;
import com.yd.common.utils.RandomStringGenerator;
import com.yd.csf.service.dto.*;
import com.yd.csf.service.enums.CommissionExpectedStatusEnum;
import com.yd.csf.service.enums.CommissionStatusEnum;
import com.yd.csf.service.enums.FortuneStatusEnum;
import com.yd.csf.service.model.*;
import com.yd.csf.service.service.*;
import com.yd.csf.service.dao.CommissionMapper;
import com.yd.csf.service.vo.CommissionStatisticsVO;
import com.yd.csf.service.vo.CommissionVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author Zhang Jianan
 * @description 针对表【commission(保单来佣表)】的数据库操作Service实现
 * @createDate 2025-09-19 16:08:05
 */
@Service
@Slf4j
public class CommissionServiceImpl extends ServiceImpl<CommissionMapper, Commission>
        implements CommissionService {

    @Resource
    private FortuneService fortuneService;
    @Resource
    private PolicyFollowService policyFollowService;
    @Resource
    private PolicyBrokerService policyBrokerService;
    @Resource
    private PolicyService policyService;
    @Resource
    private CommissionExpectedService commissionExpectedService;
    @Resource
    private IExpectedFortuneService iExpectedFortuneService;
    @Resource
    private CommissionEditRecordService commissionEditRecordService;
    @Resource
    private CommissionCompareRecordService commissionCompareRecordService;


    @Override
    public QueryWrapper<Commission> getQueryWrapper(CommissionQueryRequest commissionQueryRequest) {
        QueryWrapper<Commission> queryWrapper = new QueryWrapper<>();
        if (commissionQueryRequest == null) {
            return queryWrapper;
        }

        String status = commissionQueryRequest.getStatus();
        String policyNo = commissionQueryRequest.getPolicyNo();
        String reconciliationCompany = commissionQueryRequest.getReconciliationCompany();
        Date commissionDateStart = commissionQueryRequest.getCommissionDateStart();
        Date commissionDateEnd = commissionQueryRequest.getCommissionDateEnd();
        Date expectedDate = commissionQueryRequest.getExpectedDate();

        queryWrapper.eq(StringUtils.isNotBlank(status), "status", status);
        queryWrapper.like(StringUtils.isNotBlank(policyNo), "policy_no", policyNo);
        queryWrapper.like(StringUtils.isNotBlank(reconciliationCompany), "reconciliation_company", reconciliationCompany);

        if (commissionDateStart != null && commissionDateEnd != null) {
            queryWrapper.between("commission_date", commissionDateStart, commissionDateEnd);
        }
        // 查询预计入账日期及之前的记录, 关联查询 commission_expected 表
        if (expectedDate != null) {
            queryWrapper.apply("EXISTS (SELECT 1 FROM commission_expected ce WHERE ce.commission_expected_biz_id = commission.commission_expected_biz_id AND ce.commission_date <= {0})",
                            expectedDate);
        }

        queryWrapper.orderByDesc("id");
        return queryWrapper;
    }

    @Override
    public Page<CommissionVO> getCommissionVOPage(Page<Commission> commissionPage) {
        List<Commission> commissionList = commissionPage.getRecords();
        Page<CommissionVO> commissionVOPage = new Page<>(commissionPage.getCurrent(), commissionPage.getSize(), commissionPage.getTotal());
        if (CollUtil.isEmpty(commissionList)) {
            return commissionVOPage;
        }

        List<CommissionVO> commissionVOList = commissionList.stream().map(CommissionVO::objToVo).collect(Collectors.toList());

        commissionVOPage.setRecords(commissionVOList);
        return commissionVOPage;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateCommission(CommissionUpdateRequest commissionUpdateRequest) {
        String commissionBizId = commissionUpdateRequest.getCommissionBizId();
        Commission commission = this.getOne(new QueryWrapper<Commission>().eq("commission_biz_id", commissionBizId));
        if (commission == null) {
            throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "未找到该来佣记录");
        }
        // 获取当前登录用户
        AuthUserDto currentLoginUser = SecurityUtil.getCurrentLoginUser();
        String loginUserId = currentLoginUser.getId().toString();

        // 保存修改记录
        saveUpdateCommissionRecord(commission, commissionUpdateRequest, currentLoginUser);

        // 更新属性
        BeanUtils.copyProperties(commissionUpdateRequest, commission, "id", "commissionBizId");
        commission.setUpdaterId(loginUserId);
        commission.setUpdateTime(new Date());

        // 查询预计来佣
        CommissionExpected commissionExpected;
        try {
            commissionExpected = queryByCommission(commission);
            // 对比预计来佣
            compareWithExpected(commission.getPremium(), commission, commissionExpected);
            commissionExpectedService.updateById(commissionExpected);
        } catch (Exception e) {
            // 预计来佣不存在，来佣状态设置为 比对失败
            commission.setStatus(CommissionStatusEnum.COMPARE_FAIL.getItemValue());
            commission.setRemark(e.getMessage());
        }
        return this.updateById(commission);
    }

    private void saveUpdateCommissionRecord(Commission commission, CommissionUpdateRequest commissionUpdateRequest, AuthUserDto currentLoginUser) {
        // 保存修改记录
        List<CommissionEditRecord> commissionEditRecords = new ArrayList<>();

        if (!Objects.equals(commission.getPolicyNo(), commissionUpdateRequest.getPolicyNo())) {
            CommissionEditRecord commissionRecord = getCommissionEditRecord("保单号", commission.getPolicyNo(), commissionUpdateRequest.getPolicyNo(), commission.getCommissionBizId(), currentLoginUser);
            commissionEditRecords.add(commissionRecord);
        }
        if (!Objects.equals(commission.getReconciliationCompany(), commissionUpdateRequest.getReconciliationCompany())) {
            CommissionEditRecord commissionRecord = getCommissionEditRecord("对账公司", commission.getReconciliationCompany(), commissionUpdateRequest.getReconciliationCompany(), commission.getCommissionBizId(), currentLoginUser);
            commissionEditRecords.add(commissionRecord);
        }
        if (!Objects.equals(commission.getCommissionPeriod(), commissionUpdateRequest.getCommissionPeriod())) {
            CommissionEditRecord commissionRecord = getCommissionEditRecord("佣金期数", commission.getCommissionPeriod(), commissionUpdateRequest.getCommissionPeriod(), commission.getCommissionBizId(), currentLoginUser);
            commissionEditRecords.add(commissionRecord);
        }
        if (!Objects.equals(commission.getTotalPeriod(), commissionUpdateRequest.getTotalPeriod())) {
            CommissionEditRecord commissionRecord = getCommissionEditRecord("总来佣期数", commission.getTotalPeriod(), commissionUpdateRequest.getTotalPeriod(), commission.getCommissionBizId(), currentLoginUser);
            commissionEditRecords.add(commissionRecord);
        }
        if (!Objects.equals(commission.getCommissionName(), commissionUpdateRequest.getCommissionName())) {
            CommissionEditRecord commissionRecord = getCommissionEditRecord("来佣名称", commission.getCommissionName(), commissionUpdateRequest.getCommissionName(), commission.getCommissionBizId(), currentLoginUser);
            commissionEditRecords.add(commissionRecord);
        }
        if (commission.getAmount().compareTo(commissionUpdateRequest.getAmount()) != 0) {
            CommissionEditRecord commissionRecord = getCommissionEditRecord("来佣金额", commission.getAmount(), commissionUpdateRequest.getAmount(), commission.getCommissionBizId(), currentLoginUser);
            commissionEditRecords.add(commissionRecord);
        }
        if (!Objects.equals(commission.getCurrency(), commissionUpdateRequest.getCurrency())) {
            CommissionEditRecord commissionRecord = getCommissionEditRecord("币种", commission.getCurrency(), commissionUpdateRequest.getCurrency(), commission.getCommissionBizId(), currentLoginUser);
            commissionEditRecords.add(commissionRecord);
        }
        if (!Objects.equals(commission.getExchangeRate(), commissionUpdateRequest.getExchangeRate())) {
            CommissionEditRecord commissionRecord = getCommissionEditRecord("结算汇率", commission.getExchangeRate(), commissionUpdateRequest.getExchangeRate(), commission.getCommissionBizId(), currentLoginUser);
            commissionEditRecords.add(commissionRecord);
        }
        if (!Objects.equals(commission.getCommissionDate(), commissionUpdateRequest.getCommissionDate())) {
            CommissionEditRecord commissionRecord = getCommissionEditRecord("来佣日期",
                    DateUtil.formatDate(commission.getCommissionDate()),
                    DateUtil.formatDate(commissionUpdateRequest.getCommissionDate()), commission.getCommissionBizId(), currentLoginUser);
            commissionEditRecords.add(commissionRecord);
        }
        if (!Objects.equals(commission.getStatus(), commissionUpdateRequest.getStatus())) {
            CommissionEditRecord commissionRecord = getCommissionEditRecord("来佣比对状态", commission.getStatus(), commissionUpdateRequest.getStatus(), commission.getCommissionBizId(), currentLoginUser);
            commissionEditRecords.add(commissionRecord);
        }
        if (!Objects.equals(commission.getRemark(), commissionUpdateRequest.getRemark())) {
            CommissionEditRecord commissionRecord = getCommissionEditRecord("备注", commission.getRemark(), commissionUpdateRequest.getRemark(), commission.getCommissionBizId(), currentLoginUser);
            commissionEditRecords.add(commissionRecord);
        }

        if (CollectionUtils.isNotEmpty(commissionEditRecords)) {
            // 变更序号从1开始
            commissionEditRecords.forEach(commissionRecord -> commissionRecord.setSeq(commissionEditRecords.indexOf(commissionRecord) + 1));
            commissionEditRecordService.saveBatch(commissionEditRecords);
        }
    }

    private static CommissionEditRecord getCommissionEditRecord(String field, Object commissionPropertyValue, Object requestPropertyValue, String commissionBizId, AuthUserDto currentLoginUser) {
        CommissionEditRecord commissionRecord = new CommissionEditRecord();

        commissionRecord.setField(field);
        commissionRecord.setBeforeChange(commissionPropertyValue);
        commissionRecord.setAfterChange(requestPropertyValue);

        commissionRecord.setCommissionBizId(commissionBizId);
        commissionRecord.setUserBizId(currentLoginUser.getId().toString());
        commissionRecord.setUserName(currentLoginUser.getUsername());
        commissionRecord.setCreateTime(new Date());
        return commissionRecord;
    }

    @Override
    public CommissionExpected queryByCommission(Commission commission) {
        QueryWrapper<CommissionExpected> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("policy_no", commission.getPolicyNo());
        queryWrapper.eq("commission_name", commission.getCommissionName());
        queryWrapper.eq("commission_period", commission.getCommissionPeriod());
        queryWrapper.eq("currency", commission.getCurrency());
        CommissionExpected one = commissionExpectedService.getOne(queryWrapper);
        if (ObjectUtils.isEmpty(one)) {
            String errorMsg = String.format("未找到当前来佣对应的预计来佣，保单号：%s, 来佣名称：%s, 来佣期数：%s, 币种：%s",
                    commission.getPolicyNo(), commission.getCommissionName(), commission.getCommissionPeriod(), commission.getCurrency());
            throw new BusinessException(ResultCode.NULL_ERROR.getCode(), errorMsg);
        }
        return one;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean generateFortune(GenerateFortuneRequest generateFortuneRequest) {
        List<String> commissionBizIdList = generateFortuneRequest.getCommissionBizIdList();
        // 1. 查询选中来佣记录
        List<Commission> commissionList = this.list(new QueryWrapper<Commission>().in("commission_biz_id", commissionBizIdList));

        // 获取所有保单号
        Set<String> policyNoSet = commissionList.stream().map(Commission::getPolicyNo).collect(Collectors.toSet());

        // 2. 查询对应的预计发佣记录
        QueryWrapper<ExpectedFortune> expectedFortuneQueryWrapper = new QueryWrapper<ExpectedFortune>().in("policy_no", policyNoSet);
        List<ExpectedFortune> expectedFortuneList = iExpectedFortuneService.list(expectedFortuneQueryWrapper);

        if (CollectionUtils.isEmpty(expectedFortuneList)) {
            throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "未找到保单对应的预计发佣记录，请先创建预计发佣记录");
        } else {
            Set<String> expectedPolicyNoSet = expectedFortuneList.stream().map(ExpectedFortune::getPolicyNo).collect(Collectors.toSet());
            // 获取没有预计发佣的保单号
            Set<String> notExpectedPolicyNoSet = policyNoSet.stream().filter(policyNo -> !expectedPolicyNoSet.contains(policyNo)).collect(Collectors.toSet());
            if (!CollectionUtils.isEmpty(notExpectedPolicyNoSet)) {
                throw new BusinessException(ResultCode.FAIL.getCode(), "未找到以下保单对应的预计发佣记录，请先创建预计发佣记录：" + String.join(",", notExpectedPolicyNoSet));
            }
        }

        // 构建保单号+期次的复合键集合
        Set<String> commissionPolicyPeriodKeys = commissionList.stream()
                .map(commission -> buildPolicyPeriodKey(commission.getPolicyNo(), commission.getCommissionPeriod()))
                .collect(Collectors.toSet());

        // 3. 根据保单号查询所有发佣记录
        List<Fortune> fortuneList = fortuneService.list(new QueryWrapper<Fortune>().in("policy_no", policyNoSet));

        // 4. 校验，如果有"可发放或已发并关账"的发佣记录，不能重复生成
        for (Fortune item : fortuneList) {
            if (StringUtils.equals(item.getStatus(), FortuneStatusEnum.CAN_SEND.getItemValue()) ||
                    StringUtils.equals(item.getStatus(), FortuneStatusEnum.SENT.getItemValue())) {
                throw new BusinessException(ResultCode.FAIL.getCode(), "该来佣记录已有出帐，不能生成");
            }
        }

        // 5. 筛选匹配的预计发佣记录（优化性能）
        List<ExpectedFortune> filteredExpectedFortuneList = expectedFortuneList.stream()
                .filter(expectedFortune -> commissionPolicyPeriodKeys.contains(
                        buildPolicyPeriodKey(expectedFortune.getPolicyNo(), expectedFortune.getFortunePeriod())))
                .collect(Collectors.toList());

        // 6.删除旧的发佣记录
        fortuneService.remove(new QueryWrapper<Fortune>().in("policy_no", policyNoSet));

        // 7.1 查询所选保单号对应已发薪资记录
        QueryWrapper<Fortune> fortuneQueryWrapper = new QueryWrapper<>();
        fortuneQueryWrapper.in("policy_no", filteredExpectedFortuneList.stream().map(ExpectedFortune::getPolicyNo).collect(Collectors.toList()));
        fortuneQueryWrapper.eq("status", FortuneStatusEnum.SENT.getItemValue());
        List<Fortune> policyPaidFortuneList = fortuneService.list(fortuneQueryWrapper);

        // 7.2 构建实际的初始发佣记录
        List<Fortune> newFortuneList = buildNewFortunes(filteredExpectedFortuneList, commissionList, policyPaidFortuneList);
//        List<Fortune> newFortuneList = new ArrayList<>();
//        for (ExpectedFortune expectedFortune : filteredExpectedFortuneList) {
//            Fortune fortune = new Fortune();
//            BeanUtils.copyProperties(expectedFortune, fortune);
//
//            fortune.setFortuneBizId(RandomStringGenerator.generateBizId16(CommonEnum.UID_TYPE_FORTUNE.getCode()));
//            fortune.setStatus(FortuneStatusEnum.WAIT.getItemValue());
//            // 关联来佣业务ID
//            matchCommission(fortune, commissionList);
//            // 扣减已发薪资
//            calculateCurrentFortune(fortune, policyPaidFortuneList);
//
//            fortune.setCreateTime(new Date());
//            fortune.setUpdateTime(new Date());
//
//            newFortuneList.add(fortune);
//        }

        // 10. 保存发佣记录
        saveNewFortunes(newFortuneList);

        return true;
    }

    /**
     * 保存新的发佣记录
     */
    private void saveNewFortunes(List<Fortune> newFortuneList) {
        if (CollectionUtils.isEmpty(newFortuneList)) {
            throw new BusinessException(ResultCode.FAIL.getCode(), "没有可保存的发佣记录");
        }

        boolean saveSuccess = fortuneService.saveBatch(newFortuneList);
        if (!saveSuccess) {
            throw new BusinessException(ResultCode.FAIL.getCode(), "保存发佣记录失败");
        }
    }

    /**
     * 构建新的发佣记录
     */
    private List<Fortune> buildNewFortunes(List<ExpectedFortune> filteredExpectedFortuneList,
                                           List<Commission> commissionList,
                                           List<Fortune> policyPaidFortuneList) {
        // 构建来佣记录映射，用于快速查找
        Map<String, Commission> commissionByPolicyPeriod = commissionList.stream()
                .collect(Collectors.toMap(
                        commission -> buildPolicyPeriodKey(commission.getPolicyNo(), commission.getCommissionPeriod()),
                        Function.identity()
                ));

        Date now = new Date();
        return filteredExpectedFortuneList.stream()
                .map(expectedFortune -> {
                    Fortune fortune = new Fortune();
                    BeanUtils.copyProperties(expectedFortune, fortune);

                    fortune.setFortuneBizId(RandomStringGenerator.generateBizId16(CommonEnum.UID_TYPE_FORTUNE.getCode()));
                    fortune.setStatus(FortuneStatusEnum.CAN_SEND.getItemValue());

                    // 关联来佣业务ID
                    String key = buildPolicyPeriodKey(expectedFortune.getPolicyNo(), expectedFortune.getFortunePeriod());
                    Commission matchedCommission = commissionByPolicyPeriod.get(key);
                    if (matchedCommission != null) {
                        fortune.setCommissionBizId(matchedCommission.getCommissionBizId());
                    } else {
                        fortune.setStatus(FortuneStatusEnum.MATCH_FAIL.getItemValue());
                        fortune.setRemark("未找到当前预计发佣对应的来佣");
                    }

                    // 扣减已发薪资
                    calculateCurrentFortune(fortune, policyPaidFortuneList);

                    fortune.setCreateTime(now);
                    fortune.setUpdateTime(now);

                    return fortune;
                })
                .collect(Collectors.toList());
    }

    /**
     * 构建保单号+期次的唯一键
     */
    private String buildPolicyPeriodKey(String policyNo, Object period) {
        return (policyNo == null ? "" : policyNo) + "|" + (period == null ? "" : period.toString());
    }

    private void calculateCurrentFortune(Fortune fortune, List<Fortune> policyPaidFortuneList) {
        // 根据转介人分组
        Map<String, List<Fortune>> brokerFortuneMap = policyPaidFortuneList.stream()
                .collect(Collectors.groupingBy(Fortune::getBrokerBizId));
        // 当前转介人已发薪资
        List<Fortune> brokerFortuneList = brokerFortuneMap.getOrDefault(fortune.getBrokerBizId(), new ArrayList<>());
        // 计算当前佣金条目已发薪资
        BigDecimal brokerPaidAmount = brokerFortuneList.stream()
                .filter(item -> StringUtils.equals(item.getFortuneName(), fortune.getFortuneName())
                        && item.getFortunePeriod().equals(fortune.getFortunePeriod()))
                .map(Fortune::getNetAmount)
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        // 计算当前发佣金额，需要扣减已发薪资
        fortune.setAmount(fortune.getAmount().subtract(brokerPaidAmount));
    }

    private void matchCommission(Fortune fortune, List<Commission> commissionList) {
        for (Commission commission : commissionList) {
            if (StringUtils.equals(commission.getPolicyNo(), fortune.getPolicyNo())
                    && commission.getCommissionPeriod().equals(fortune.getFortunePeriod())
                    && commission.getCommissionName().equals(fortune.getFortuneName())
            ) {
                fortune.setCommissionBizId(commission.getCommissionBizId());
            } else {
                fortune.setStatus(FortuneStatusEnum.MATCH_FAIL.getItemValue());
                fortune.setRemark("未找到当前预计发佣对应的来佣");
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean addCommission(CommissionAddRequest commissionAddRequest) {
        // 校验来佣所属保单是否存在
        String policyNo = commissionAddRequest.getPolicyNo();
        Policy policy = policyService.getOne(new QueryWrapper<Policy>().eq("policy_no", policyNo));
        // 校验来佣所属保单跟进是否存在
        boolean policyFollowExists = policyFollowService.exists(new QueryWrapper<PolicyFollow>().eq("policy_no", policyNo));
        if (policy == null && !policyFollowExists) {
            throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "该保单号不存在，不能添加来佣");
        }

        // 获取当前登录用户
        AuthUserDto currentLoginUser = SecurityUtil.getCurrentLoginUser();
        String loginUserId = currentLoginUser.getId().toString();

        Commission commission = new Commission();
        BeanUtils.copyProperties(commissionAddRequest, commission);
        // 生成新单编号
        String commissionBizId = RandomStringGenerator.generateBizId16(CommonEnum.UID_TYPE_COMMISSION.getCode());
        commission.setCommissionBizId(commissionBizId);
        // 保费为空时，查询保单初始保费或支付保费，为空时默认0
        if (ObjectUtils.isEmpty(commission.getPremium())) {
            Object object = policy.getInitialPremium() != null ? policy.getInitialPremium() : policy.getPaymentPremium();
            if (object != null) {
                commission.setPremium(object.toString());
            } else {
                commission.setPremium(BigDecimal.ZERO.toString());
            }
        }
        // 查询预计来佣
        // 查询预计来佣
        CommissionExpected commissionExpected;
        try {
            commissionExpected = queryByCommission(commission);
            // 对比预计来佣
            compareWithExpected(commission.getPremium(), commission, commissionExpected);
            commissionExpectedService.updateById(commissionExpected);
        } catch (Exception e) {
            // 预计来佣不存在，来佣状态设置为 比对失败
            commission.setStatus(CommissionStatusEnum.COMPARE_FAIL.getItemValue());
            commission.setRemark(e.getMessage());
        }

        commission.setCreatorId(loginUserId);
        commission.setCreateTime(new Date());
        commission.setUpdaterId(loginUserId);
        commission.setUpdateTime(new Date());

        return this.save(commission);
    }

    @Override
    public Commission getByCommissionBizId(String commissionBizId) {
        return this.getOne(new QueryWrapper<Commission>().eq("commission_biz_id", commissionBizId));
    }

    /**
     * 比对时，当前来佣比例=当前入账金额/结算汇率/保费 和预计来佣的来佣比例对比
     *
     * @param commission
     * @param expected
     */
    @Override
    public void compareWithExpected(String premium, Commission commission, CommissionExpected expected) {
        if (expected != null) {
            if (ObjectUtils.isEmpty(expected.getCommissionRatio())) {
                log.error("预计来佣的来佣比例不能为空，预计来佣业务id：{}", expected.getCommissionExpectedBizId());
                throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "预计来佣的来佣比例不能为空");
            }
            if (ObjectUtils.isEmpty(expected.getDefaultExchangeRate())) {
                log.error("预计来佣的默认汇率不能为空，预计来佣业务id：{}", expected.getCommissionExpectedBizId());
                throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "预计来佣的默认汇率不能为空");
            }
            if (ObjectUtils.isEmpty(premium)) {
                log.error("保费不能为空，来佣业务id：{}", commission.getCommissionBizId());
                throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "保费不能为空");
            }
            if (ObjectUtils.isEmpty(commission.getAmount())) {
                log.error("当前入账金额不能为空，来佣业务id：{}", commission.getCommissionBizId());
                throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "当前入账金额不能为空");
            }
            if (ObjectUtils.isEmpty(commission.getExchangeRate())) {
                log.error("当前结算汇率不能为空，来佣业务id：{}", commission.getCommissionBizId());
                throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "当前结算汇率不能为空");
            }

            // 当前来佣比例=当前入账金额/结算汇率/保费
            BigDecimal currentCommissionRatio = commission.getAmount()
                    .divide(new BigDecimal(premium), 2, RoundingMode.HALF_UP)
                    .divide(new BigDecimal(commission.getExchangeRate()), 2, RoundingMode.HALF_UP);
            // 预计来佣比例
            BigDecimal expectedCommissionRatio = expected.getCommissionRatio();
            // 预计总金额
            BigDecimal expectedAmount = expected.getExpectedAmount();
            if (expectedAmount == null || BigDecimal.ZERO.compareTo(currentCommissionRatio) == 0) {
                expectedAmount = new BigDecimal(premium)
                        .multiply(expected.getCommissionRatio())
                        .multiply(expected.getDefaultExchangeRate());
                expected.setExpectedAmount(expectedAmount);
            }
            // 已入账金额
            BigDecimal paidAmount = commission.getAmount().add(ObjectUtils.defaultIfNull(expected.getPaidAmount(), BigDecimal.ZERO));

            if (currentCommissionRatio.compareTo(expectedCommissionRatio) == 0) {
                // 一致，来佣状态设置为 比对成功
                commission.setStatus(CommissionStatusEnum.COMPARE_SUCCESS.getItemValue());
                // 预计来佣的状态设置为 已来佣
                expected.setStatus(CommissionExpectedStatusEnum.COMPARED.getItemValue());
            } else {
                // 不一致，来佣状态设置为 比对失败
                commission.setStatus(CommissionStatusEnum.COMPARE_FAIL.getItemValue());
                expected.setStatus(CommissionExpectedStatusEnum.PARTIAL.getItemValue());
            }
            // 设置来佣相关字段
            commission.setCommissionExpectedBizId(expected.getCommissionExpectedBizId());
            commission.setExpectedAmount(expectedAmount.setScale(2, RoundingMode.HALF_UP));
            commission.setPaidAmount(paidAmount.setScale(2, RoundingMode.HALF_UP));
            // 待入账金额 = 预计来佣总金额 - 已入账金额
            commission.setPendingAmount(expectedAmount.subtract(paidAmount).setScale(2, RoundingMode.HALF_UP));
            // 当前来佣比例
            commission.setCurrentCommissionRatio(currentCommissionRatio.setScale(2, RoundingMode.HALF_UP));
            // 当期已入账来佣比例 = 当前来佣比例 + 已入账来佣比例
            commission.setPeriodPaidRatio(currentCommissionRatio.add(ObjectUtils.defaultIfNull(expected.getPaidRatio(), BigDecimal.ZERO)).setScale(2, RoundingMode.HALF_UP));
            // 当期剩余来佣比例 = 预计来佣来佣比例 - 当期已入账来佣比例
            commission.setPeriodPendingRatio(expectedCommissionRatio.subtract(commission.getPeriodPaidRatio()).setScale(2, RoundingMode.HALF_UP));

            // 预计来佣的已入账金额更新为 已入账金额
            expected.setExpectedAmount(expectedAmount.setScale(2, RoundingMode.HALF_UP));
            expected.setPaidAmount(paidAmount.setScale(2, RoundingMode.HALF_UP));
            // 已入账来佣比例 = 当前来佣比例 + 已入账来佣比例
            expected.setPaidRatio(currentCommissionRatio.add(ObjectUtils.defaultIfNull(expected.getPaidRatio(), BigDecimal.ZERO)).setScale(2, RoundingMode.HALF_UP));

            // 达到预计比例时，待入账金额设置为 0
            if (commission.getPeriodPendingRatio().compareTo(BigDecimal.ZERO) == 0) {
                commission.setPendingAmount(BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP));
                expected.setPaidAmount(paidAmount.setScale(2, RoundingMode.HALF_UP));
                expected.setPaidRatio(commission.getPeriodPaidRatio());
            }

            // 保存比对记录
            saveCompareRecord(commission, expected);
        }
    }

    private void saveCompareRecord(Commission commission, CommissionExpected expected) {
        CommissionCompareRecord commissionCompareRecord = new CommissionCompareRecord();
        commissionCompareRecord.setCommissionExpectedBizId(expected.getCommissionExpectedBizId());
        commissionCompareRecord.setCommissionBizId(commission.getCommissionBizId());
        commissionCompareRecord.setCommissionPeriod(commission.getCommissionPeriod());
        commissionCompareRecord.setTotalPeriod(commission.getTotalPeriod());
        commissionCompareRecord.setAmount(commission.getAmount());
        commissionCompareRecord.setCurrency(commission.getCurrency());
        commissionCompareRecord.setExchangeRate(commission.getExchangeRate());
        commissionCompareRecord.setStatus(commission.getStatus());
        commissionCompareRecord.setRemark(commission.getRemark());
        commissionCompareRecord.setCreateTime(commission.getCreateTime());
        commissionCompareRecordService.save(commissionCompareRecord);
    }

    /**
     * 查询列表
     *
     * @param dto
     * @return
     */
    @Override
    public List<Commission> queryList(CommissionDto dto) {
        List<Commission> list = baseMapper.selectList(new LambdaQueryWrapper<Commission>()
                .in(CollectionUtils.isNotEmpty(dto.getCommissionBizIdList()), Commission::getCommissionBizId, dto.getCommissionBizIdList())
        );
        return list;
    }

    /**
     * 查询来佣保单转介人关系信息
     *
     * @param dto
     * @return
     */
    @Override
    public List<CommissionBindPolicyBrokerDto> queryCommissionBindPolicyBrokerList(CommissionDto dto) {
        return baseMapper.queryCommissionBindPolicyBrokerList(dto);
    }

    @Override
    public CommissionStatisticsVO getCommissionStatistics(List<Long> commissionIds) {
        // 自定义统计数据
        CommissionStatisticsVO commissionStatistics = baseMapper.getCommissionStatistics(commissionIds);

        BigDecimal totalAmount = commissionStatistics.getTotalAmount();
        BigDecimal totalPaidAmount = commissionStatistics.getTotalPaidAmount();
        // 计算待入账金额
        commissionStatistics.setPendingPaidAmount(totalAmount.subtract(totalPaidAmount));
        // 计算已入账比例
        BigDecimal divided = BigDecimal.ZERO;
        if (totalAmount.compareTo(BigDecimal.ZERO) > 0) {
            divided = totalPaidAmount.divide(totalAmount, 4, RoundingMode.HALF_UP);
        }
        // 格式化 %
        commissionStatistics.setPaidAmountRatio(String.format("%.2f%%", divided.doubleValue() * 100));

        return commissionStatistics;
    }
}




