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

import cn.hutool.core.convert.Convert;
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.component.CommissionAsyncService;
import com.yd.csf.service.dto.*;
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.collections4.MapUtils;
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 org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.transaction.support.TransactionTemplate;

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;
    @Resource
    private CommissionAsyncService commissionAsyncService;
    @Resource
    private TransactionTemplate transactionTemplate;


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

        String reconciliationYearMonth = commissionQueryRequest.getReconciliationYearMonth();
        List<String> statusList = commissionQueryRequest.getStatusList();
        String policyNo = commissionQueryRequest.getPolicyNo();
        List<String> insuranceCompanyBizIdList = commissionQueryRequest.getInsuranceCompanyBizIdList();
        List<String> reconciliationCompanyBizIdList = commissionQueryRequest.getReconciliationCompanyBizIdList();
        Date commissionDateStart = commissionQueryRequest.getCommissionDateStart();
        Date commissionDateEnd = commissionQueryRequest.getCommissionDateEnd();
        Date expectedDate = commissionQueryRequest.getExpectedDate();

        // 查询对账年月
        queryWrapper.eq(StringUtils.isNotBlank(reconciliationYearMonth), "reconciliation_year_month", reconciliationYearMonth);

        queryWrapper.in(CollectionUtils.isNotEmpty(statusList), "status", statusList);
        queryWrapper.like(StringUtils.isNotBlank(policyNo), "policy_no", policyNo);
        queryWrapper.in(CollectionUtils.isNotEmpty(insuranceCompanyBizIdList), "insurance_company_biz_id", insuranceCompanyBizIdList);
        queryWrapper.in(CollectionUtils.isNotEmpty(reconciliationCompanyBizIdList), "reconciliation_company_biz_id", reconciliationCompanyBizIdList);

        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;
        }

        // 1.关联查询保单信息
        Set<String> policyNoSet = commissionList.stream().map(Commission::getPolicyNo).collect(Collectors.toSet());
        QueryWrapper<Policy> queryWrapper = new QueryWrapper<Policy>();
        queryWrapper.select("policy_no", "payment_premium", "product_name", "insurance_company", "reconciliation_company");
        queryWrapper.in("policy_no", policyNoSet);
        List<Policy> policyList = policyService.list(queryWrapper);
        Map<String, Policy> policyMap = policyList.stream().collect(Collectors.toMap(Policy::getPolicyNo, a -> a, (oldValue, newValue) -> newValue));

        // 2.关联查询预计入账信息
        Set<String> commissionExpectedBizIdSet = commissionList.stream().map(Commission::getCommissionExpectedBizId).collect(Collectors.toSet());
        List<CommissionExpected> commissionExpectedList = commissionExpectedService.lambdaQuery()
                .select(CommissionExpected::getCommissionExpectedBizId, CommissionExpected::getReceivableNo)
                .in(CommissionExpected::getCommissionExpectedBizId, commissionExpectedBizIdSet)
                .list();
        Map<String, CommissionExpected> commissionExpectedMap = commissionExpectedList.stream().collect(Collectors.toMap(CommissionExpected::getCommissionExpectedBizId, a -> a, (oldValue, newValue) -> newValue));

        // 填充信息
        List<CommissionVO> commissionVOList = commissionList.stream().map(commission -> {
            CommissionVO commissionVO = CommissionVO.objToVo(commission);
            Policy policy = policyMap.get(commission.getPolicyNo());
            if (policy != null) {
                // 填充保费、产品名称、保险公司、对账公司
                commissionVO.setPremium(policy.getPaymentPremium());
                commissionVO.setProductName(policy.getProductName());
                commissionVO.setInsuranceCompany(policy.getInsuranceCompany());
                commissionVO.setReconciliationCompany(policy.getReconciliationCompany());
            }
            CommissionExpected commissionExpected = commissionExpectedMap.get(commission.getCommissionExpectedBizId());
            if (commissionExpected != null) {
                // 填充应收账款编号
                commissionVO.setReceivableNo(commissionExpected.getReceivableNo());
                commissionVO.setCommissionExpectedStatus(commissionExpected.getStatus());
            }
            return commissionVO;
        }).collect(Collectors.toList());

        commissionVOPage.setRecords(commissionVOList);
        return commissionVOPage;
    }

    @Override
    public List<CommissionVO> getCommissionList(List<Commission> commissionList) {
        if (CollUtil.isEmpty(commissionList)) {
            return Collections.emptyList();
        }

        // 1.关联查询保单信息
        Set<String> policyNoSet = commissionList.stream().map(Commission::getPolicyNo).collect(Collectors.toSet());
        QueryWrapper<Policy> queryWrapper = new QueryWrapper<Policy>();
        queryWrapper.in("policy_no", policyNoSet);
        queryWrapper.select(
                "policy_no", "payment_premium",
                "product_launch_biz_id", "product_name",
                "insurance_company_biz_id", "insurance_company",
                "reconciliation_company", "reconciliation_company_code", "reconciliation_company_biz_id");
        List<Policy> policyList = policyService.list(queryWrapper);
        Map<String, Policy> policyMap = policyList.stream().collect(Collectors.toMap(Policy::getPolicyNo, a -> a, (oldValue, newValue) -> newValue));

        // 填充信息
        List<CommissionVO> commissionVOList = commissionList.stream().map(commission -> {
            CommissionVO commissionVO = CommissionVO.objToVo(commission);
            Policy policy = policyMap.get(commission.getPolicyNo());
            if (policy != null) {
                // 填充保费、产品名称、保险公司、对账公司
                commissionVO.setPremium(policy.getPaymentPremium());
                commissionVO.setProductName(policy.getProductName());
                commissionVO.setProductLaunchBizId(policy.getProductLaunchBizId());
                commissionVO.setInsuranceCompanyBizId(policy.getInsuranceCompanyBizId());
                commissionVO.setInsuranceCompany(policy.getInsuranceCompany());
                commissionVO.setReconciliationCompany(policy.getReconciliationCompany());
                commissionVO.setReconciliationCompanyCode(policy.getReconciliationCompanyCode());
                commissionVO.setReconciliationCompanyBizId(policy.getReconciliationCompanyBizId());
            }
            return commissionVO;
        }).collect(Collectors.toList());

        return commissionVOList;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateCommission(CommissionUpdateRequest commissionUpdateRequest) {
        String commissionBizId = commissionUpdateRequest.getCommissionBizId();

        // 查询旧数据
        Commission commission = this.getByCommissionBizId(commissionBizId);
        if (commission == null) {
            throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "未找到该来佣记录");
        }

        BigDecimal amount = commission.getAmount();
        BigDecimal requestAmount = commissionUpdateRequest.getAmount();

        // 计算当前来佣比例
        BigDecimal currentCommissionRatio = this.calculateCurrentCommissionRatio(
                commission.getPremium(),
                requestAmount,
                commissionUpdateRequest.getCurrency(),
                commissionUpdateRequest.getExchangeRate());

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

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

        // 更新属性
        BeanUtils.copyProperties(commissionUpdateRequest, commission, "commissionBizId");
        commission.setCurrentCommissionRatio(currentCommissionRatio);
        commission.setUpdaterId(loginUserId);
        commission.setUpdateTime(new Date());
        // 执行更新操作（这个方法将在当前事务中执行）
        this.updateById(commission);

        // 没改金额，则不比对
        if (amount.compareTo(requestAmount) != 0) {
            // 2. 注册事务同步器，在主事务提交后执行比对
            TransactionSynchronizationManager.registerSynchronization(
                    new TransactionSynchronization() {
                        @Override
                        public void afterCommit() {
                            try {
                                // 重新查询最新的数据，获取已提交的数据
                                commissionAsyncService.commissionCompare(commission);
                            } catch (Exception e) {
                                // 比对失败不影响主事务，记录日志即可
                                log.error("主事务提交后，比对操作执行失败，commissionBizId: {}",
                                        commissionUpdateRequest.getCommissionBizId(), e);
                            }
                        }
                    }
            );
        }
        return true;
    }

    @Override
    public void validateCommissionUpdateRequest(CommissionUpdateRequest commissionUpdateRequest) {
        // 校验入参
        if (ObjectUtils.isEmpty(commissionUpdateRequest.getCommissionBizId())) {
            log.error("来佣业务id不能为空：{}", commissionUpdateRequest.getCommissionBizId());
            throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "来佣业务id不能为空");
        }
//        if (ObjectUtils.isEmpty(commissionUpdateRequest.getAmount())) {
//            log.error("当前入账金额不能为空，来佣业务id：{}", commissionUpdateRequest.getCommissionBizId());
//            throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "当前入账金额不能为空");
//        }
//        if (ObjectUtils.isEmpty(commissionUpdateRequest.getExchangeRate())) {
//            log.error("当前结算汇率不能为空，来佣业务id：{}", commissionUpdateRequest.getCommissionBizId());
//            throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "当前结算汇率不能为空");
//        }
    }


    @Override
    public 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);
        }
        String commissionDate = DateUtil.formatDate(commission.getCommissionDate());
        String requestCommissionDate = DateUtil.formatDate(commissionUpdateRequest.getCommissionDate());
        if (!Objects.equals(commissionDate, requestCommissionDate)) {
            CommissionEditRecord commissionRecord = getCommissionEditRecord("来佣日期", commissionDate, requestCommissionDate, 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(String policyNo, String commissionName, Integer commissionPeriod, String currency, String premium) {
        QueryWrapper<CommissionExpected> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("policy_no", policyNo);
        queryWrapper.eq("commission_name", commissionName);
        queryWrapper.eq("commission_period", commissionPeriod);
        queryWrapper.eq("currency", currency);
        CommissionExpected one = commissionExpectedService.getOne(queryWrapper);
        if (ObjectUtils.isEmpty(one)) {
            String errorMsg = String.format("未找到当前来佣对应的预计来佣，保单号：%s, 来佣名称：%s, 来佣期数：%s, 币种：%s",
                    policyNo, commissionName, commissionPeriod, currency);
            throw new BusinessException(ResultCode.NULL_ERROR.getCode(), errorMsg);
        }
        // 计算预计来佣金额 (统一试算币种：HKD)
        if (one.getExpectedAmount() == null) {
            BigDecimal expectedAmount = new BigDecimal(premium)
                    .multiply(one.getCommissionRatio());
            if ("USD".equals(one.getCurrency())) {
                expectedAmount = expectedAmount.multiply(one.getDefaultExchangeRate());
            }
            one.setExpectedAmount(expectedAmount.divide(BigDecimal.valueOf(100), 4, RoundingMode.HALF_UP));
        }
        return one;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean generateFortune(GenerateFortuneRequest generateFortuneRequest) {
        List<String> commissionBizIdList = generateFortuneRequest.getCommissionBizIdList();
        List<Commission> commissions = this.lambdaQuery().in(Commission::getCommissionBizId, commissionBizIdList).list();
        // 根据保单号，期数建立映射关系
        Map<String, Commission> policyNoPeriodMap = commissions.stream()
                .collect(Collectors.toMap(i -> i.getPolicyNo() + "_" + i.getCommissionPeriod(), commission -> commission));

        // 校验来佣记录是否存在
        if (CollectionUtils.isEmpty(commissions)) {
            throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "未找到对应的来佣记录，请先创建来佣记录");
        }

        for (Commission commission : commissions) {
            if ("U".equals(commission.getCommissionBizType())) {
                throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "非关联保单应收单，不能点击生成可出账记录");
            }
            if (StringUtils.isBlank(commission.getPolicyNo())) {
                throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "保单号不能为空");
            }
        }

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

        // 1.1 根据保单号查询的预计发佣记录
        List<ExpectedFortune> expectedFortuneList = iExpectedFortuneService.lambdaQuery()
                .in(ExpectedFortune::getPolicyNo, policyNoSet)
                .list();
        // 1.2 根据保单号和期数筛选符合的预计发佣记录
        List<ExpectedFortune> filteredExpectedFortuneList1 = new ArrayList<>();
        for (Commission commission : commissions) {
            String policyNo = commission.getPolicyNo();
            Integer commissionPeriod = commission.getCommissionPeriod();
            for (ExpectedFortune expectedFortune : expectedFortuneList) {
                if (expectedFortune.getPolicyNo().equals(policyNo) && expectedFortune.getFortunePeriod().equals(commissionPeriod)) {
                    filteredExpectedFortuneList1.add(expectedFortune);
                }
            }
        }
        if (CollectionUtils.isEmpty(filteredExpectedFortuneList1)) {
            throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "未找到保单对应的预计发佣记录，请先创建预计发佣记录");
        }

        // 2. 根据本次发佣期数，查询是否有已出账的记录
        List<Fortune> fortuneList = fortuneService.lambdaQuery()
                .in(Fortune::getExpectedFortuneBizId, filteredExpectedFortuneList1.stream().map(ExpectedFortune::getExpectedFortuneBizId).collect(Collectors.toList()))
                .list();
        // 2.1 根据保单号和期数建立映射关系
        Map<String, Fortune> fortuneMap = fortuneList.stream()
                .collect(Collectors.toMap(i -> i.getPolicyNo() + "_" + i.getFortunePeriod(), fortune -> fortune));
        // 2.2 校验是否有已出账的记录
        List<ExpectedFortune> filteredExpectedFortuneList2 = new ArrayList<>();
        for (ExpectedFortune expectedFortune : filteredExpectedFortuneList1) {
            String policyNo = expectedFortune.getPolicyNo();
            Integer fortunePeriod = expectedFortune.getFortunePeriod();
            // 如果有已出账记录，跳过，表示此次该预计出账已出账
            if (fortuneMap.get(policyNo + "_" + fortunePeriod) != null) {
                continue;
            }
            filteredExpectedFortuneList2.add(expectedFortune);
        }

        // 2.2 过滤掉 is_part = 1 的 fortune 记录
//        List<Fortune> filteredFortuneList = fortuneList.stream()
//                .filter(fortune -> Integer.valueOf(0).equals(fortune.getIsPart()))
//                .collect(Collectors.toList());

        // 5. 构建实际的初始发佣记录
        List<Fortune> newFortuneList = buildNewFortunes(filteredExpectedFortuneList2, commissions);
//        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> expectedFortuneList,
                                           List<Commission> commissionList) {
        if (CollectionUtils.isEmpty(expectedFortuneList)) {
            return new ArrayList<>();
        }
        // 构建来佣记录映射，用于快速查找
        Map<String, Commission> commissionByPolicyPeriod = commissionList.stream()
                .collect(Collectors.toMap(
                        commission -> buildPolicyPeriodKey(commission.getPolicyNo(), commission.getCommissionPeriod()),
                        Function.identity()
                ));

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

                    fortune.setFortuneBizId(RandomStringGenerator.generateBizId16(CommonEnum.UID_TYPE_FORTUNE.getCode()));
                    fortune.setFortuneBizType("R");
                    fortune.setAmount(expectedFortune.getAmount());
                    fortune.setExpectedFortuneBizId(expectedFortune.getExpectedFortuneBizId());
                    fortune.setStatus(FortuneStatusEnum.CAN_SEND.getItemValue());
                    fortune.setIsPart(0);

                    // 关联来佣业务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("未找到当前预计发佣对应的来佣");
                    }

                    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
    public Commission getByCommissionBizId(String commissionBizId) {
        return this.getOne(new QueryWrapper<Commission>().eq("commission_biz_id", commissionBizId));
    }

    public BigDecimal calculateCurrentCommissionRatio(String premium, BigDecimal amount, String exchangeRate, String currency) {
        if (ObjectUtils.isEmpty(premium)) {
            throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "保单保费不能为空");
        }
        if (ObjectUtils.isEmpty(amount)) {
            throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "当前入账金额不能为空");
        }
        if (ObjectUtils.isEmpty(exchangeRate)) {
            throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "当前结算汇率不能为空");
        }
        // 当前来佣比例=当前入账金额/结算汇率/保费 * 100
        return amount.divide(new BigDecimal(premium), 4, RoundingMode.HALF_UP)
                .divide(new BigDecimal(exchangeRate), 4, RoundingMode.HALF_UP)
                .multiply(new BigDecimal(100));
    }

    @Override
    public void saveCompareRecord(Commission commission, CommissionExpected expected, AuthUserDto currentLoginUser) {
        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.setCurrentCommissionRatio(commission.getCurrentCommissionRatio());
        commissionCompareRecord.setCurrency(commission.getCurrency());
        commissionCompareRecord.setExchangeRate(commission.getExchangeRate());
        commissionCompareRecord.setStatus(commission.getStatus());
        commissionCompareRecord.setRemark(commission.getRemark());
        commissionCompareRecord.setCreateTime(commission.getCreateTime());
        commissionCompareRecordService.save(commissionCompareRecord);
    }

    @Override
    public CommissionCompareRecord getNewCompareRecord(Commission commission, CommissionExpected expected, AuthUserDto currentLoginUser) {
        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.setOperatorName(currentLoginUser.getUsername());
        commissionCompareRecord.setCreateTime(commission.getCreateTime());
        return commissionCompareRecord;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<Commission> addCommissionBatch(List<CommissionAddRequest> customerAddRequestList) {
        if (CollectionUtils.isEmpty(customerAddRequestList)) {
            throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "入账数据不能为空");
        }
        validateAddCommissionBatch(customerAddRequestList);

        Set<String> policyNoSet = customerAddRequestList.stream()
                .map(CommissionAddRequest::getPolicyNo)
                .filter(StringUtils::isNotBlank).collect(Collectors.toSet());

        // 关联查询保单信息、预计入账信息
        Map<String, Policy> policyMap = new HashMap<>();
        List<CommissionExpected> commissionExpectedList = new ArrayList<>();
        if (CollUtil.isNotEmpty(policyNoSet)) {
            // 查询保单信息
            List<Policy> policyList = policyService.lambdaQuery().in(Policy::getPolicyNo, policyNoSet).list();
            // 保单映射
            policyMap = policyList.stream().collect(Collectors.toMap(Policy::getPolicyNo, Function.identity()));
            // 查询预计入账信息
            commissionExpectedList = commissionExpectedService.lambdaQuery().in(CommissionExpected::getPolicyNo, policyNoSet).list();
        }

        List<Commission> commissionList = new ArrayList<>();
        for (CommissionAddRequest request : customerAddRequestList) {
            Commission commission = new Commission();
            BeanUtils.copyProperties(request, commission);
            // 入账业务id
            commission.setCommissionBizId(RandomStringGenerator.generateBizId16(CommonEnum.UID_TYPE_COMMISSION.getCode()));
            // 关联业务id
            if (MapUtils.isNotEmpty(policyMap)) {
                Policy policy = policyMap.get(request.getPolicyNo());
                if (policy != null) {
                    commission.setReconciliationCompany(policy.getReconciliationCompany());
                    commission.setReconciliationCompanyBizId(policy.getReconciliationCompanyBizId());
                    commission.setProductLaunchBizId(policy.getProductLaunchBizId());
                    commission.setInsuranceCompanyBizId(policy.getInsuranceCompanyBizId());
                    commission.setPremium(Convert.toStr(policy.getPaymentPremium()));
                }
            }
            // 关联预计来佣信息
            if (CollectionUtils.isNotEmpty(commissionExpectedList)) {
                // 根据保单号、期数、入账名称、币种查询预计来佣记录
                CommissionExpected expected = commissionExpectedList.stream()
                        .filter(item -> item.getPolicyNo().equals(request.getPolicyNo())
                                && item.getCommissionPeriod().equals(request.getCommissionPeriod())
                                && item.getCommissionName().equals(request.getCommissionName())
                                && item.getCurrency().equals(request.getCurrency()))
                        .findFirst()
                        .orElse(null);
                if (expected != null) {
                    commission.setCommissionExpectedBizId(expected.getCommissionExpectedBizId());
                } else {
                    log.warn("新增入账：未查询到预计来佣记录, policyNo: {}, commissionPeriod: {}, commissionName: {}, currency: {}",
                            request.getPolicyNo(), request.getCommissionPeriod(), request.getCommissionName(), request.getCurrency());
                    commission.setRemark("未查询到预计来佣记录");
                    commission.setStatus(CommissionStatusEnum.MATCH_FAILED.getItemValue());
                }
            }
            commissionList.add(commission);
        }
        boolean b = this.saveOrUpdateBatch(commissionList);

        // 开启新事务，比对数据
        transactionTemplate.execute(status -> {
            try {
                commissionAsyncService.commissionCompareBatch(commissionList);
            } catch (Exception e) {
                // 比对失败不影响主事务，记录日志即可
                log.error("批量新增, 比对操作执行失败, error: {}", e.getMessage());
            }
            return null;
        });

        return commissionList;
    }

    private void validateAddCommissionBatch(List<CommissionAddRequest> customerAddRequestList) {
        for (CommissionAddRequest request : customerAddRequestList) {
            // 校验数据
            if (StringUtils.isBlank(request.getCommissionType())) {
                throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "入账项目类型不能为空");
            }
            // commissionType 只能是数字
            if (!StringUtils.isNumeric(request.getCommissionType())) {
                throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "入账项目类型只能是字典值");
            }
            // commissionName 不能为空
            if (StringUtils.isBlank(request.getCommissionName())) {
                throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "入账项目名称不能为空");
            }
        }
    }

    @Override
    public Boolean addToExpected(AddToExpectedCommissionRequest addToExpectedCommissionRequest) {
        if (StringUtils.isBlank(addToExpectedCommissionRequest.getCommissionBizId())) {
            throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "来佣业务id不能为空");
        }
        Commission commission = this.getByCommissionBizId(addToExpectedCommissionRequest.getCommissionBizId());
        if (commission == null) {
            throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "来佣记录不存在");
        }

        if (commission.getCommissionExpectedBizId() != null) {
            throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "预计来佣已存在");
        }

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

        CommissionExpected expected = new CommissionExpected();
        BeanUtils.copyProperties(commission, expected);
        expected.setCommissionExpectedBizId(RandomStringGenerator.generateBizId16("commission_expected"));
        // 设置预计入账金额、已来佣金额、待入账金额
        expected.setExpectedAmount(commission.getAmount());
        expected.setPaidAmount(BigDecimal.ZERO);
        expected.setPaidRatio(BigDecimal.valueOf(100));
        expected.setDefaultExchangeRate(new BigDecimal(commission.getExchangeRate()));
        expected.setCommissionDate(new Date());

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

        return commissionExpectedService.save(expected);
    }

    @Override
    public int updateStatusBatchById(List<Commission> existingCommissions) {
        return this.baseMapper.updateStatusBatchById(existingCommissions);
    }

    /**
     * 查询列表
     *
     * @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) {
        if (CollectionUtils.isEmpty(commissionIds)) {
            CommissionStatisticsVO commissionStatisticsVO = new CommissionStatisticsVO();
            commissionStatisticsVO.setTotalPaidAmount(BigDecimal.ZERO);
            commissionStatisticsVO.setExpectePaidAmount(BigDecimal.ZERO);
            commissionStatisticsVO.setPendingPaidAmount(BigDecimal.ZERO);
            commissionStatisticsVO.setDifferenceAmount(BigDecimal.ZERO);
            commissionStatisticsVO.setTotalPolicyCount(0);
            commissionStatisticsVO.setTotalPremium(BigDecimal.ZERO);
            commissionStatisticsVO.setReconciliationCompanyCount(0);
            commissionStatisticsVO.setTotalCompareCommissionCount(0);
            commissionStatisticsVO.setSuccessCompareCommissionCount(0);
            commissionStatisticsVO.setFailedCompareCommissionCount(0);
            return commissionStatisticsVO;
        }
        // 自定义统计数据
        CommissionStatisticsVO commissionStatistics = baseMapper.getCommissionStatistics(commissionIds);

        // 确保所有字段都有值，避免null值
        if (commissionStatistics.getTotalPaidAmount() == null) {
            commissionStatistics.setTotalPaidAmount(BigDecimal.ZERO);
        }
        if (commissionStatistics.getExpectePaidAmount() == null) {
            commissionStatistics.setExpectePaidAmount(BigDecimal.ZERO);
        }
        if (commissionStatistics.getPendingPaidAmount() == null) {
            commissionStatistics.setPendingPaidAmount(BigDecimal.ZERO);
        }
        if (commissionStatistics.getDifferenceAmount() == null) {
            commissionStatistics.setDifferenceAmount(BigDecimal.ZERO);
        }
        if (commissionStatistics.getTotalPremium() == null) {
            commissionStatistics.setTotalPremium(BigDecimal.ZERO);
        }

        // 计算差额（估-实）
        BigDecimal differenceAmount = commissionStatistics.getExpectePaidAmount()
                .subtract(commissionStatistics.getTotalPaidAmount());
        commissionStatistics.setDifferenceAmount(differenceAmount);

        // 如果待入账金额为0，重新计算（预计入账金额 - 实际入账金额）
        if (commissionStatistics.getPendingPaidAmount().compareTo(BigDecimal.ZERO) == 0) {
            commissionStatistics.setPendingPaidAmount(differenceAmount);
        }

        return commissionStatistics;
    }
}




