package com.yd.csf.service.service.impl;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yd.auth.core.dto.AuthUserDto;
import com.yd.auth.core.utils.SecurityUtil;
import com.yd.common.enums.CommonEnum;
import com.yd.common.enums.ResultCode;
import com.yd.common.exception.BusinessException;
import com.yd.common.result.Result;
import com.yd.common.utils.ChineseTextConverter;
import com.yd.common.utils.EnglishTextUtil;
import com.yd.common.utils.RandomStringGenerator;
import com.yd.csf.feign.response.policyfollow.ApiPolicyFollowDetailResponse;
import com.yd.csf.service.common.ErrorCode;
import com.yd.csf.service.dto.*;
import com.yd.csf.service.enums.FnaStatusEnum;
import com.yd.csf.service.enums.PolicyFollowStatusEnum;
import com.yd.csf.service.enums.PolicyStatusEnum;
import com.yd.csf.service.model.*;
import com.yd.csf.service.service.*;
import com.yd.csf.service.dao.PolicyFollowMapper;
import com.yd.csf.service.utils.AsyncQueryUtil;
import com.yd.csf.service.vo.PolicyAdditionalVO;
import com.yd.csf.service.vo.PolicyFollowDetailVO;
import com.yd.csf.service.vo.PolicyFollowVO;
import com.yd.csf.service.vo.PolicyNumberResponseVO;
import com.yd.insurance.base.feign.client.insurancereconciliationcompany.ApiInsuranceReconciliationCompanyFeignClient;
import com.yd.insurance.base.feign.request.insurancereconciliationcompany.ApiInsuranceReconciliationCompanyPageRequest;
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.beans.factory.annotation.Autowired;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

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

/**
* @author Zhang Jianan
* @description 针对表【policy_follow(新单跟进表)】的数据库操作Service实现
* @createDate 2025-09-16 18:18:06
*/
@Service
@Slf4j
public class PolicyFollowServiceImpl extends ServiceImpl<PolicyFollowMapper, PolicyFollow>
    implements PolicyFollowService{

    @Resource
    private PolicyBrokerService policyBrokerService;
    @Resource
    private PolicyService policyService;
    @Resource
    private PolicyFollowService policyFollowService;
    @Resource
    private PolicyFollowRecordService policyFollowRecordService;
    @Resource
    private PolicyFollowFileService policyFollowFileService;
    @Resource
    private AsyncQueryUtil asyncQueryUtil;
    @Resource
    private PolicyPolicyholderService policyPolicyholderService;
    @Resource
    private PolicyInsurantService policyInsurantService;
    @Resource
    private PolicyBeneficiaryService policyBeneficiaryService;
    @Resource
    private PolicySecondHolderService policySecondHolderService;
    @Resource
    private PolicyAdditionalService policyAdditionalService;
    @Resource
    private PolicyAppointmentFileService policyAppointmentFileService;
    @Resource
    private IExpectedFortuneService expectedFortuneService;
    @Autowired
    private CommissionExpectedService commissionExpectedService;
    @Resource
    private IAppointmentService appointmentService;
    @Resource
    private FnaService fnaService;
    @Resource
    private ApiInsuranceReconciliationCompanyFeignClient apiInsuranceReconciliationCompanyFeignClient;
    @Resource
    private CustomerService customerService;


    @Override
    public PolicyFollow getByPolicyBizId(String policyBizId) {
        return this.getOne(new QueryWrapper<PolicyFollow>().eq("policy_biz_id", policyBizId));
    }

    @Override
    public QueryWrapper<PolicyFollow> getQueryWrapper(PolicyFollowQueryRequest policyFollowQueryRequest) {
        QueryWrapper<PolicyFollow> queryWrapper = new QueryWrapper<>();
        if (policyFollowQueryRequest == null) {
            return queryWrapper;
        }

        String policyNo = policyFollowQueryRequest.getPolicyNo();
        String status = policyFollowQueryRequest.getStatus();
        String appointmentNo = policyFollowQueryRequest.getAppointmentNo();
        Date signDateStart = policyFollowQueryRequest.getSignDateStart();
        Date signDateEnd = policyFollowQueryRequest.getSignDateEnd();
        String latestPaymentDate = policyFollowQueryRequest.getLatestPaymentDate();
        List<String> insuranceCompanyBizIdList = policyFollowQueryRequest.getInsuranceCompanyBizIdList();
        List<String> productLaunchBizIdList = policyFollowQueryRequest.getProductLaunchBizIdList();
        Integer issueNumber = policyFollowQueryRequest.getIssueNumber();

        queryWrapper.like(ObjectUtils.isNotEmpty(policyNo), "policy_no", policyNo);
        queryWrapper.eq(ObjectUtils.isNotEmpty(status), "status", status);
        queryWrapper.eq(ObjectUtils.isNotEmpty(appointmentNo), "appointment_no", appointmentNo);
        queryWrapper.ge(ObjectUtils.isNotEmpty(signDateStart), "sign_date", signDateStart);
        queryWrapper.le(ObjectUtils.isNotEmpty(signDateEnd), "sign_date", signDateEnd);
        queryWrapper.eq(ObjectUtils.isNotEmpty(latestPaymentDate), "latest_payment_date", latestPaymentDate);
        //保單持有人（投保人）
        if (StringUtils.isNotEmpty(policyFollowQueryRequest.getPolicyHolder())) {
            List<PolicyPolicyholder> policyHolderList = policyPolicyholderService.queryList(policyFollowQueryRequest.getPolicyHolder());
            List<String> policyBizIdList = null;
            if (CollectionUtils.isNotEmpty(policyHolderList)) {
                policyBizIdList = policyHolderList.stream()
                        .map(PolicyPolicyholder::getPolicyBizId)
                        .filter(StringUtils::isNotBlank)
                        .distinct()
                        .collect(Collectors.toList());
            }
            if (CollectionUtils.isNotEmpty(policyBizIdList)) {
                queryWrapper.in("policy_biz_id", policyBizIdList);
            } else {
                // 没有匹配的投保人，直接让查询结果为空
                queryWrapper.apply("1=0");
            }
        }
        //受保人
        if (StringUtils.isNotEmpty(policyFollowQueryRequest.getInsured())) {
            List<PolicyInsurant> policyHolderList = policyInsurantService.queryList(policyFollowQueryRequest.getInsured());
            List<String> policyBizIdList = null;
            if (CollectionUtils.isNotEmpty(policyHolderList)) {
                policyBizIdList = policyHolderList.stream()
                        .map(PolicyInsurant::getPolicyBizId)
                        .filter(StringUtils::isNotBlank)
                        .distinct()
                        .collect(Collectors.toList());
            }
            if (CollectionUtils.isNotEmpty(policyBizIdList)) {
                queryWrapper.in("policy_biz_id", policyBizIdList);
            } else {
                // 没有匹配的受保人，直接让查询结果为空
                queryWrapper.apply("1=0");
            }
        }
        if (StringUtils.isNotEmpty(policyFollowQueryRequest.getInsured())) queryWrapper.like("insured", policyFollowQueryRequest.getInsured());
        //签单人
        if (StringUtils.isNotEmpty(policyFollowQueryRequest.getSigner())) queryWrapper.like("signer", policyFollowQueryRequest.getSigner());
        //转介人（保单转介人表）
        if (StringUtils.isNotEmpty(policyFollowQueryRequest.getBrokerName())) {
            List<PolicyBroker> policyBrokerList = policyBrokerService.queryList(QueryPolicyBrokerDto.builder().brokerName(policyFollowQueryRequest.getBrokerName()).build());
            if (!CollectionUtils.isEmpty(policyBrokerList)) {
                //新单跟进唯一业务ID
                List<String> policyBizIdList = policyBrokerList.stream().map(PolicyBroker::getPolicyBizId).collect(Collectors.toList());
                queryWrapper.in("policy_biz_id", policyBizIdList);
            }else {
                // 没有匹配的转介人，直接让查询结果为空
                queryWrapper.apply("1=0");
            }
        }

        if (CollectionUtils.isNotEmpty(insuranceCompanyBizIdList)) {
            queryWrapper.in("insurance_company_biz_id", insuranceCompanyBizIdList);
        }
        if (CollectionUtils.isNotEmpty(productLaunchBizIdList)) {
            queryWrapper.in("product_launch_biz_id", productLaunchBizIdList);
        }
        queryWrapper.eq(ObjectUtils.isNotEmpty(issueNumber), "issue_number", issueNumber);
        // 排序：按创建时间倒序
        queryWrapper.orderByDesc("id");

        return queryWrapper;
    }

    @Override
    public Page<PolicyFollowVO> getPolicyFollowVOPage(Page<PolicyFollow> policyFollowPage) {
        List<PolicyFollow> policyFollowList = policyFollowPage.getRecords();
        Page<PolicyFollowVO> policyFollowVOPage = new Page<>(
                policyFollowPage.getCurrent(), policyFollowPage.getSize(), policyFollowPage.getTotal());
        if (CollUtil.isEmpty(policyFollowList)) {
            return policyFollowVOPage;
        }

        // 对象列表 => 封装对象列表
        List<PolicyFollowVO> voList = policyFollowList.stream()
                .map(PolicyFollowVO::objToVo)
                .collect(Collectors.toList());

        // 批量填充所需字段
        fillFiledNames(voList);

        policyFollowVOPage.setRecords(voList);
        return policyFollowVOPage;
    }

    /**
     * 批量填充所需字段
     */
    private void fillFiledNames(List<PolicyFollowVO> voList) {
        // 提取所有 policyBizId
        List<String> bizIds = voList.stream()
                .map(PolicyFollowVO::getPolicyBizId)
                .filter(StringUtils::isNotBlank)
                .distinct()
                .collect(Collectors.toList());
        if (CollUtil.isEmpty(bizIds)) {
            return;
        }

        // 批量查询转介人（取第一个 brokerName）
        List<PolicyBroker> allBrokers = policyBrokerService.lambdaQuery()
                .in(PolicyBroker::getPolicyBizId, bizIds)
                .eq(PolicyBroker::getIsDeleted, 0)
                .orderByAsc(PolicyBroker::getId)
                .list();
        Map<String, String> brokerNameMap = allBrokers.stream()
                .collect(Collectors.groupingBy(
                        PolicyBroker::getPolicyBizId,
                        LinkedHashMap::new,
                        Collectors.collectingAndThen(
                                Collectors.toList(),
                                list -> list.get(0).getBrokerName()
                        )
                ));

        // 批量查询投保人（取第一条的中文名、英文名）
        List<PolicyPolicyholder> allPolicyholders = policyPolicyholderService.lambdaQuery()
                .in(PolicyPolicyholder::getPolicyBizId, bizIds)
                .eq(PolicyPolicyholder::getIsDeleted, 0)
                .orderByAsc(PolicyPolicyholder::getId)
                .list();
        Map<String, String> holderNameMap = allPolicyholders.stream()
                .collect(Collectors.groupingBy(
                        PolicyPolicyholder::getPolicyBizId,
                        LinkedHashMap::new,
                        Collectors.collectingAndThen(
                                Collectors.toList(),
                                list -> list.get(0).getName()          // 中文名
                        )
                ));
        Map<String, String> holderNameEnMap = allPolicyholders.stream()
                .collect(Collectors.groupingBy(
                        PolicyPolicyholder::getPolicyBizId,
                        LinkedHashMap::new,
                        Collectors.collectingAndThen(
                                Collectors.toList(),
                                list -> list.get(0).getNameEn()        // 英文名
                        )
                ));

        // 批量查询受保人（取第一条的中文名、英文名）
        List<PolicyInsurant> allInsurants = policyInsurantService.lambdaQuery()
                .in(PolicyInsurant::getPolicyBizId, bizIds)
                .eq(PolicyInsurant::getIsDeleted, 0)
                .orderByAsc(PolicyInsurant::getId)
                .list();
        Map<String, String> insurantNameMap = allInsurants.stream()
                .collect(Collectors.groupingBy(
                        PolicyInsurant::getPolicyBizId,
                        LinkedHashMap::new,
                        Collectors.collectingAndThen(
                                Collectors.toList(),
                                list -> list.get(0).getName()          // 中文名
                        )
                ));
        Map<String, String> insurantNameEnMap = allInsurants.stream()
                .collect(Collectors.groupingBy(
                        PolicyInsurant::getPolicyBizId,
                        LinkedHashMap::new,
                        Collectors.collectingAndThen(
                                Collectors.toList(),
                                list -> list.get(0).getNameEn()        // 英文名
                        )
                ));

        // 统一填充 VO
        voList.forEach(vo -> {
            vo.setBrokerName(brokerNameMap.get(vo.getPolicyBizId()));
            vo.setPolicyHolder(holderNameMap.get(vo.getPolicyBizId()));
            vo.setPolicyHolderEn(holderNameEnMap.get(vo.getPolicyBizId()));
            vo.setInsured(insurantNameMap.get(vo.getPolicyBizId()));
            vo.setInsuredEn(insurantNameEnMap.get(vo.getPolicyBizId()));
        });
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updatePolicyFollow(PolicyFollowUpdateRequest policyFollowUpdateRequest) {
        // 校验参数
        if (StringUtils.isBlank(policyFollowUpdateRequest.getPolicyBizId())) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR.getCode(), "policyBizId不能为空");
        }
        String policyBizId = policyFollowUpdateRequest.getPolicyBizId();
        PolicyFollow policyFollow = getByPolicyBizId(policyBizId);
        if (policyFollow == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR.getCode(), ErrorCode.NOT_FOUND_ERROR.getMessage());
        }
        // 跟进信息
        PolicyFollowUpdateDto policyFollowUpdateDto = policyFollowUpdateRequest.getPolicyFollowUpdateDto();
        if (policyFollowUpdateDto != null) {
            BeanUtils.copyProperties(policyFollowUpdateDto, policyFollow, "id", "policyBizId");

            // 计算冷却期结束日期
            if (policyFollowUpdateDto.getCoolingOffDays() != null && policyFollowUpdateDto.getEffectiveDate() != null) {
                policyFollow.setCoolingOffEndDate(DateUtil.offset(policyFollowUpdateDto.getEffectiveDate(), DateField.DAY_OF_MONTH, policyFollowUpdateDto.getCoolingOffDays()));
            }
            // 获取币种字典值
            policyFollow.setPolicyCurrency(this.getCurrencyValue(policyFollowUpdateDto.getPolicyCurrency()));
        }
        // 设置核保信息
        setValidPolicyInfo(policyFollow, policyFollowUpdateRequest.getVerifyPolicyInfo());
        // 设置保单邮寄
        setPolicyMailing(policyFollow, policyFollowUpdateRequest.getPolicyMailing());

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

        return updateById(policyFollow);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updatePolicyFollowDto(PolicyFollowDto policyFollowDto) {
        // 校验参数
        if (StringUtils.isBlank(policyFollowDto.getPolicyBizId())) {
            throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "policyBizId不能为空");
        }
        String policyBizId = policyFollowDto.getPolicyBizId();
        PolicyFollow policyFollow = getByPolicyBizId(policyBizId);
        if (policyFollow == null) {
            throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "新单跟进记录不存在");
        }

        // 复制属性，排除系统字段
        BeanUtils.copyProperties(policyFollowDto, policyFollow, "id", "policyBizId", "brokerList");
        if (StringUtils.isNotBlank(policyFollowDto.getReconciliationCode())) {
            policyFollow.setReconciliationCompanyCode(policyFollowDto.getReconciliationCode());
        }

        // 检查保单号是否从空变为有值
        String oldPolicyNo = policyFollow.getPolicyNo();
        String newPolicyNo = policyFollowDto.getPolicyNo();
        boolean isPolicyNoUpdated = StringUtils.isBlank(oldPolicyNo) && StringUtils.isNotBlank(newPolicyNo);

        // 计算冷却期结束日期
//        if (policyFollowDto.getCoolingOffDays() != null && policyFollowDto.getEffectiveDate() != null) {
//            policyFollow.setCoolingOffEndDate(DateUtil.offset(policyFollowDto.getEffectiveDate(), DateField.DAY_OF_MONTH, policyFollowDto.getCoolingOffDays()));
//        }

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

        try {
            boolean result = updateById(policyFollow);
        } catch (DataIntegrityViolationException e) {
            log.info("修改跟进信息失败：{}", e.getMessage());
            // 判断是否为唯一索引冲突
            String message = e.getMessage();
            if (StringUtils.isNotBlank(message) && message.contains("idx_policy_no")) {
                throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "保单号已存在，请勿重复添加");
            } else {
                throw new BusinessException(ResultCode.FAIL.getCode(), "修改跟进信息失败");
            }
        } catch (Exception e) {
            log.info("修改跟进信息失败：{}", e.getMessage());
            throw new BusinessException(ResultCode.FAIL.getCode(), "修改跟进信息失败");
        }

        // 如果保单号从空变为有值，更新关联的FNA状态为"签单完成"
        if (isPolicyNoUpdated) {
            fnaService.lambdaUpdate()
                    .eq(Fna::getFnaBizId, policyFollow.getFnaBizId())
                    .set(Fna::getStatus, FnaStatusEnum.SIGNED_COMPLETED.getItemValue())
                    .update();
        }

        //更新新单投保人表和新单受保人表的中文名和简体中文名
        //更新新单投保人表信息
        policyPolicyholderService.updateName(policyBizId,policyFollowDto.getPolicyHolder());
        //更新新单受保人表信息
        policyInsurantService.updateName(policyBizId,policyFollowDto.getPolicyHolder());
        return true;
    }

    private void setPolicyMailing(PolicyFollow policyFollow, PolicyMailing policyMailing) {
        if (policyMailing == null) {
            return;
        }
        policyFollow.setMailingMethod(policyMailing.getMailingMethod());
//        policyFollow.setBrokerSignDate(policyMailing.getBrokerSignDate());
//        policyFollow.setInsurerMailingDate(policyMailing.getInsurerMailingDate());
//        policyFollow.setCustomerSignDate(policyMailing.getCustomerSignDate());
    }

    private void setValidPolicyInfo(PolicyFollow policyFollow, VerifyPolicyInfo verifyPolicyInfo) {
        if (verifyPolicyInfo == null) {
            return;
        }
        policyFollow.setSubmitDate(verifyPolicyInfo.getSubmitDate());
        policyFollow.setSignDate(verifyPolicyInfo.getSignDate());
        policyFollow.setIssueDate(verifyPolicyInfo.getIssueDate());
        policyFollow.setEffectiveDate(verifyPolicyInfo.getEffectiveDate());
//        policyFollow.setIsPrepaid(verifyPolicyInfo.getIsPrepaid());
        policyFollow.setPrepaidAmount(verifyPolicyInfo.getPrepaidAmount());
        policyFollow.setPrepaidAmountAfterDiscount(verifyPolicyInfo.getPrepaidAmountAfterDiscount());
        policyFollow.setPolicyExpirationDate(verifyPolicyInfo.getPolicyExpirationDate());
    }

    @Override
    public PolicyFollowVO getPolicyFollowVO(PolicyFollow policyFollow) {
        if (policyFollow == null) {
            return null;
        }
        PolicyFollowVO policyFollowVO = PolicyFollowVO.objToVo(policyFollow);
        // 关联查询转介人
        QueryWrapper<PolicyBroker> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("policy_biz_id", policyFollow.getPolicyBizId());

        return policyFollowVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> addPolicyFollow(PolicyFollowAddRequest policyFollowAddRequest) {
        PolicyFollow policyFollow = new PolicyFollow();
        BeanUtils.copyProperties(policyFollowAddRequest, policyFollow);
        // 生成新单编号
        String policyBizId = RandomStringGenerator.generateBizId16(CommonEnum.UID_TYPE_POLICY.getCode());
        policyFollow.setPolicyBizId(policyBizId);

        // 计算冷却期结束日期
        if (policyFollowAddRequest.getCoolingOffDays() != null) {
            policyFollow.setCoolingOffEndDate(DateUtil.offset(policyFollowAddRequest.getEffectiveDate(), DateField.DAY_OF_MONTH, policyFollowAddRequest.getCoolingOffDays()));
        }
        // 获取币种字典值
        policyFollow.setPolicyCurrency(this.getCurrencyValue(policyFollowAddRequest.getCurrency()));


        // 保存转介人
        List<PolicyBroker> policyBrokerList = policyFollowAddRequest.getBrokerList();
        if (CollUtil.isNotEmpty(policyBrokerList)) {
            policyBrokerList.forEach(policyBroker -> {
                policyBroker.setPolicyBizId(policyBizId);
            });
        }

        this.save(policyFollow);
        policyBrokerService.saveBatch(policyBrokerList);

        // 保险产品相关字段不为空，则查询获取保单预计来佣
//        String policyNo = policyFollowAddRequest.getPolicyNo();
//        String productLaunchBizId = policyFollowAddRequest.getProductLaunchBizId();
//        String insuranceCompanyBizId = policyFollowAddRequest.getInsuranceCompanyBizId();
//        String reconciliationCompany = policyFollowAddRequest.getReconciliationCompany();
//        String reconciliationCompanyCode = policyFollowAddRequest.getReconciliationCompanyCode();
//        String reconciliationCompanyBizId = policyFollowAddRequest.getReconciliationCompanyBizId();
//        // 保存保单预计来佣
//        commissionExpectedService.getExpectedCommissionByProductlaunchId(policyNo, productLaunchBizId, insuranceCompanyBizId, reconciliationCompany, reconciliationCompanyCode, reconciliationCompanyBizId);

        // 返回新单跟进唯一业务ID
        return Collections.singletonMap("policyBizId", policyBizId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> addPolicyFollowDto(PolicyFollowDto policyFollowDto) {
        PolicyFollow policyFollow = new PolicyFollow();
        // 复制属性，排除系统字段
        BeanUtils.copyProperties(policyFollowDto, policyFollow, "id", "policyBizId", "brokerList", "signerList");

        // 生成新单编号
        String policyBizId = RandomStringGenerator.generateBizId16(CommonEnum.UID_TYPE_POLICY.getCode());
        policyFollow.setPolicyBizId(policyBizId);

        // 计算冷却期结束日期
        if (policyFollowDto.getCoolingOffDays() != null && policyFollowDto.getEffectiveDate() != null) {
            policyFollow.setCoolingOffEndDate(DateUtil.offset(policyFollowDto.getEffectiveDate(), DateField.DAY_OF_MONTH, policyFollowDto.getCoolingOffDays()));
        }

        // 获取当前登录用户
        AuthUserDto currentLoginUser = SecurityUtil.getCurrentLoginUser();
        String loginUserId = currentLoginUser.getId().toString();
        policyFollow.setCreatorId(loginUserId);
        policyFollow.setCreateTime(new Date());
        policyFollow.setUpdaterId(loginUserId);
        policyFollow.setUpdateTime(new Date());


        this.save(policyFollow);


        // 返回新单跟进唯一业务ID
        return Collections.singletonMap("policyBizId", policyBizId);
    }

    @Override
    public PolicyFollowDetailVO getPolicyFollowDetailVO(String policyBizId) {
        if (StringUtils.isBlank(policyBizId)) {
            return null;
        }
        // 查询主表
        PolicyFollow policyFollow = getByPolicyBizId(policyBizId);
        if (policyFollow == null) {
            return null;
        }

        // 转换为 DetailVO
        PolicyFollowDetailVO detailVO = PolicyFollowDetailVO.objToVo(policyFollow);

        // 查询介绍人列表
        List<PolicyBroker> brokerList = policyBrokerService.list(
                new QueryWrapper<PolicyBroker>()
                        .eq("policy_biz_id", policyBizId)
                        .eq("is_deleted", 0)
        );
        detailVO.setBrokerList(brokerList);

        // 查询附加险列表
        List<PolicyAdditional> additionalList = policyAdditionalService.lambdaQuery()
                .eq(PolicyAdditional::getPolicyBizId, policyBizId).list();
        List<PolicyAdditionalVO> additionalVOList = additionalList.stream()
                .map(PolicyAdditionalVO::objToVo)
                .collect(Collectors.toList());
        detailVO.setAdditionalList(additionalVOList);

        return detailVO;
    }


    @Override
     public Boolean addToPolicy(List<String> policyNoList) {
         if (CollectionUtils.isEmpty(policyNoList)) {
             throw new BusinessException(ErrorCode.PARAMS_ERROR.getCode(), "保单号列表不能为空");
         }
         // 获取当前登录用户
         AuthUserDto currentLoginUser = SecurityUtil.getCurrentLoginUser();
         String loginUserId = currentLoginUser.getId().toString();

         // 查询所有跟进记录
         List<PolicyFollow> policyFollowList = list(new QueryWrapper<PolicyFollow>().in("policy_no", policyNoList));
         for (PolicyFollow policyFollow : policyFollowList) {
             // 查询保单是否存在
             String policyBizId = policyFollow.getPolicyBizId();
             Policy policy = policyService.getOne(new QueryWrapper<Policy>().eq("policy_biz_id", policyBizId));
             if (policy != null) {
                 // 更新
                 BeanUtils.copyProperties(policyFollow, policy, "id");
                 policy.setUpdaterId(loginUserId);
                 policy.setUpdateTime(new Date());

                 policyService.updateById(policy);
             } else {
                 // 不存在则创建
                 policy = new Policy();
                 BeanUtils.copyProperties(policyFollow, policy, "id");
                 policy.setId(null);
                 policy.setPolicyBizId(policyBizId);
                 policy.setCreatorId(loginUserId);
                 policy.setCreateTime(new Date());
                 policy.setUpdaterId(loginUserId);
                 policy.setUpdateTime(new Date());

                 try {
                     policyService.save(policy);
                 } catch (DuplicateKeyException e) {
                     // 保单号已存在
                     throw new BusinessException("保单号 " + policyFollow.getPolicyNo() + " 已存在，请勿重复添加");
                 }
             }
             // 更新转介人
             updatePolicyBrokerPolicyNo(policyBizId, policyFollow.getPolicyNo());
         }
         return true;
     }

    private void updatePolicyBrokerPolicyNo(String policyBizId, String policyNo) {
        // 更新转介人保单号
        policyBrokerService.update(
                new UpdateWrapper<PolicyBroker>()
                        .set("policy_no", policyNo)
                        .eq("policy_biz_id", policyBizId)
                        .eq("is_deleted", 0)
        );
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean changePolicyFollowStatus(ChangePolicyFollowStatusRequest changePolicyFollowStatusRequest, PolicyFollow policyFollow) {
        if (changePolicyFollowStatusRequest == null || StringUtils.isBlank(changePolicyFollowStatusRequest.getPolicyBizId())) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR.getCode(), "policyBizId不能为空");
        }
        if (policyFollow == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR.getCode(), ErrorCode.NOT_FOUND_ERROR.getMessage());
        }
        // 校验状态是否存在
        PolicyFollowStatusEnum policyFollowStatusEnum = PolicyFollowStatusEnum.getEnumByValue(changePolicyFollowStatusRequest.getStatus());
        if (policyFollowStatusEnum == null) {
            throw new BusinessException(ResultCode.PARAM_CHECK_ERROR.getCode(), "跟进状态不存在");
        }
        // 获取当前跟进状态
        PolicyFollowStatusEnum currentStatusEnum = PolicyFollowStatusEnum.getEnumByValue(policyFollow.getStatus());
        // 校验状态是否可变更 - 终态状态不能变更
        if (PolicyFollowStatusEnum.EFFECTIVE.equals(currentStatusEnum)
                || PolicyFollowStatusEnum.DECLINED.equals(currentStatusEnum)
                || PolicyFollowStatusEnum.CANCELLED.equals(currentStatusEnum)
                || PolicyFollowStatusEnum.CLOSED.equals(currentStatusEnum)
                || PolicyFollowStatusEnum.LAPSED.equals(currentStatusEnum)
        ) {
            throw new BusinessException(ResultCode.PARAM_CHECK_ERROR.getCode(), "生效、拒保、取消投保、关闭、失效状态不能变更");
        }

        String policyBizId = changePolicyFollowStatusRequest.getPolicyBizId();

        // 保单号和转接人都有的情况下，才能修改为生效状态
        if (PolicyFollowStatusEnum.EFFECTIVE.equals(policyFollowStatusEnum)) {
            if (StringUtils.isBlank(policyFollow.getPolicyNo())) {
                throw new BusinessException(ResultCode.PARAM_CHECK_ERROR.getCode(), "保单号不能为空，才能修改为生效状态");
            }
            boolean exists = policyBrokerService.exists(new QueryWrapper<PolicyBroker>().eq("policy_biz_id", policyBizId));
            if (!exists) {
                throw new BusinessException(ResultCode.PARAM_CHECK_ERROR.getCode(), "转介人不能为空，才能修改为生效状态");
            }
        }

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

        policyFollowService.lambdaUpdate()
                .set(PolicyFollow::getEffectiveDate, changePolicyFollowStatusRequest.getEffectiveDate())
                .set(PolicyFollow::getUnderwritingDate, changePolicyFollowStatusRequest.getUnderwritingDate())
                .set(PolicyFollow::getStatus, changePolicyFollowStatusRequest.getStatus())
                .set(PolicyFollow::getNextStatusList, getNextStatus(policyFollowStatusEnum))
                .set(PolicyFollow::getUpdaterId, loginUserId)
                //冷静期结束日期
                .set(PolicyFollow::getCoolingOffEndDate, changePolicyFollowStatusRequest.getCoolingOffEndDate() != null ? changePolicyFollowStatusRequest.getCoolingOffEndDate() : policyFollow.getCoolingOffEndDate())
                //保单截止日期
                .set(PolicyFollow::getPolicyExpirationDate, changePolicyFollowStatusRequest.getPolicyExpirationDate() != null ? changePolicyFollowStatusRequest.getPolicyExpirationDate() : policyFollow.getPolicyExpirationDate())
                .eq(PolicyFollow::getId, policyFollow.getId())
                .update();

        // 如果是生效状态，同步保单、预计发佣、预计来佣
        if (PolicyFollowStatusEnum.EFFECTIVE.equals(policyFollowStatusEnum)) {
            Policy policy = policyService.getOne(new QueryWrapper<Policy>().eq("policy_biz_id", policyBizId));
            if (policy == null) {
                throw new BusinessException(ErrorCode.NOT_FOUND_ERROR.getCode(), "policy不存在");
            }
            // 新单跟进，校验 policy 数据
            policyFollowChangeStatusValidPolicy(policy);

            // 新单跟进，校验 policyFollow 数据
            policyFollowChangeStatusValidPolicyFollow(policyFollow);

            policy.setPolicyNo(policyFollow.getPolicyNo());
            policy.setPolicyHolderAge(calculatePolicyHolderAge(policyFollow.getCustomerBizId()));
            policy.setCoolingOffEndDate(policyFollow.getCoolingOffEndDate());
            policy.setReconciliationCompanyBizId(policyFollow.getReconciliationCompanyBizId());
            policy.setReconciliationCompanyCode(policyFollow.getReconciliationCompanyCode());
            policy.setReconciliationCompany(policyFollow.getReconciliationCompany());
            policy.setInsuranceCompanyBizId(policyFollow.getInsuranceCompanyBizId());
            policy.setInsuranceCompany(policyFollow.getInsuranceCompany());
            policy.setProductName(policyFollow.getProductName());
            // 更新保单状态为生效
            policy.setStatus(PolicyStatusEnum.INFORCE.getItemValue());
            // 手动映射不同名的字段
            policy.setPaymentPremium(policyFollow.getEachIssuePremium());
            policy.setCurrency(policyFollow.getPolicyCurrency());
            policy.setPaymentTerm(policyFollow.getIssueNumber());
            policy.setTotalPaymentPremium(calculateTotalPaymentPremium(policy));
            policy.setUnderwritingDate(changePolicyFollowStatusRequest.getUnderwritingDate());
            policy.setEffectiveDate(changePolicyFollowStatusRequest.getEffectiveDate());
            //冷静期结束日期
            policy.setCoolingOffEndDate(changePolicyFollowStatusRequest.getCoolingOffEndDate() != null ? changePolicyFollowStatusRequest.getCoolingOffEndDate() : policy.getCoolingOffEndDate());

            // 保存保单
            policyService.updateById(policy);

            // 更新转介人保单号
            updatePolicyBrokerPolicyNo(policyBizId, policy.getPolicyNo());

            // 根据保单生成预计入账记录
            log.info("根据保单生成预计入账记录前effectiveDate生效日期：{}",policy.getEffectiveDate());
            generateExpectedCommission(policyFollow, policy);

            // 更新FNA状态为 "签单完成"
            fnaService.update(new UpdateWrapper<Fna>()
                    .set("status", FnaStatusEnum.SIGNED_COMPLETED.getItemValue())
                    .set("policy_no", policy.getPolicyNo())
                    .eq("fna_biz_id", policyFollow.getFnaBizId()));
        }

        // 新增新单状态记录
        PolicyFollowRecord policyFollowRecord = new PolicyFollowRecord();
        policyFollowRecord.setId(null);
        policyFollowRecord.setPolicyBizId(policyBizId);
        policyFollowRecord.setTitle(Objects.requireNonNull(policyFollowStatusEnum.getItemLabel()));
        policyFollowRecord.setMessage(changePolicyFollowStatusRequest.getMessage());
        policyFollowRecord.setCreatorId(loginUserId);
        policyFollowRecord.setCreateTime(new Date());
        policyFollowRecordService.save(policyFollowRecord);

        return true;
    }

    private void policyFollowChangeStatusValidPolicyFollow(PolicyFollow policyFollow) {
        if (ObjectUtils.isEmpty(policyFollow.getReconciliationCompanyBizId())) {
            throw new BusinessException("新单跟进-基础数据，reconciliationCompanyBizId 不能为空");
        }
        if (ObjectUtils.isEmpty(policyFollow.getReconciliationCompanyCode())) {
            throw new BusinessException("新单跟进-基础数据，reconciliationCompanyCode 不能为空");
        }
        if (ObjectUtils.isEmpty(policyFollow.getReconciliationCompany())) {
            throw new BusinessException("新单跟进-基础数据，reconciliationCompany 不能为空");
        }
        if (ObjectUtils.isEmpty(policyFollow.getInsuranceCompanyBizId())) {
            throw new BusinessException("新单跟进-基础数据，insuranceCompanyBizId 不能为空");
        }
        if (ObjectUtils.isEmpty(policyFollow.getInsuranceCompany())) {
            throw new BusinessException("新单跟进-基础数据，insuranceCompany 不能为空");
        }
        if (ObjectUtils.isEmpty(policyFollow.getProductName())) {
            throw new BusinessException("新单跟进-基础数据，productName 不能为空");
        }
        if (ObjectUtils.isEmpty(policyFollow.getProductLaunchBizId())) {
            throw new BusinessException("新单跟进-基础数据，productLaunchBizId 不能为空");
        }
    }

    private void policyFollowChangeStatusValidPolicy(Policy policy) {
        BigDecimal paymentPremium = policy.getPaymentPremium();
        if (paymentPremium == null) {
            throw new BusinessException("期交保费不能为空");
        }
        Object paymentTerm = policy.getPaymentTerm();
        if (paymentTerm == null) {
            throw new BusinessException("供款期数不能为空");
        }
    }

    private BigDecimal calculateTotalPaymentPremium(Policy policy) {
        BigDecimal paymentPremium = policy.getPaymentPremium();
        Object paymentTerm = policy.getPaymentTerm();
        // 计算总保费 = 每期保费 * 供款期数
        return paymentPremium.multiply(Convert.toBigDecimal(paymentTerm)).setScale(4, RoundingMode.HALF_UP);
    }

    private Integer calculatePolicyHolderAge(String customerBizId) {
        Customer customer = customerService.getByCustomerBizId(customerBizId);
        if (customer == null) {
            throw new BusinessException("客户不存在");
        }
        if (customer.getBirthday() == null) {
            throw new BusinessException("客户生日不能为空");
        }
        // 根据生日计算年龄
        return DateUtil.ageOfNow(customer.getBirthday());
    }

    /**
     * 调用对账公司 feignclient，查询对账公司编码
     */
    @Override
    public String queryReconciliationCompanyByFeign(String reconciliationCompanyBizId) {
        ApiInsuranceReconciliationCompanyPageRequest reconciliationCompanyPageRequest = new ApiInsuranceReconciliationCompanyPageRequest();
        reconciliationCompanyPageRequest.setPageNo(1);
        reconciliationCompanyPageRequest.setPageSize(999);
        Result iPageResult = apiInsuranceReconciliationCompanyFeignClient.page(reconciliationCompanyPageRequest);

        // 解析响应获取对账公司编码
        if (iPageResult != null && iPageResult.getCode() == 200) {
            try {
                // Feign 返回的泛型会被反序列化为 LinkedHashMap，需要手动提取
                Object data = iPageResult.getData();
                if (data instanceof Map) {
                    Map<String, Object> dataMap = (Map<String, Object>) data;
                    Object recordsObj = dataMap.get("records");
                    if (recordsObj instanceof List) {
                        List<Map<String, Object>> records = (List<Map<String, Object>>) recordsObj;
                        // 遍历分页结果，找到匹配的对账公司
                        for (Map<String, Object> record : records) {
                            String recordBizId = (String) record.get("reconciliationCompanyBizId");
                            if (reconciliationCompanyBizId.equals(recordBizId)) {
                                // 获取对账公司编码
                                return (String) record.get("code");
                            }
                        }
                    }
                }
            } catch (Exception e) {
                log.error("解析对账公司响应失败: {}", e.getMessage(), e);
            }
        }
        return null;
    }

    @Override
    public String getNextStatus(PolicyFollowStatusEnum policyFollowStatusEnum) {
        // 根据当前状态返回可能的下一步状态
        switch (policyFollowStatusEnum) {
            case PENDING_SIGN:
                return PolicyFollowStatusEnum.SIGNED.getItemValue() + ","
                        + PolicyFollowStatusEnum.CANCELLED.getItemValue();
            case SIGNED:
                return PolicyFollowStatusEnum.WAITING_PAYMENT.getItemValue() + ","
                        + PolicyFollowStatusEnum.CANCELLED.getItemValue();
            case WAITING_PAYMENT:
                return PolicyFollowStatusEnum.PREMIUM_RECONCILING.getItemValue() + ","
                        + PolicyFollowStatusEnum.CANCELLED.getItemValue();
            case PREMIUM_RECONCILING:
                return PolicyFollowStatusEnum.PREMIUM_RECONCILED_UNDERWRITING.getItemValue();
            case PREMIUM_RECONCILED_UNDERWRITING:
                return PolicyFollowStatusEnum.EFFECTIVE.getItemValue() + ","
                        + PolicyFollowStatusEnum.DECLINED.getItemValue() + ","
                        + PolicyFollowStatusEnum.DELAYED_UNDERWRITING.getItemValue();
            case DELAYED_UNDERWRITING:
                return PolicyFollowStatusEnum.PREMIUM_RECONCILED_UNDERWRITING.getItemValue() + ","
                        + PolicyFollowStatusEnum.DECLINED.getItemValue() + ","
                        + PolicyFollowStatusEnum.CANCELLED.getItemValue();
            default:
                return "";
        }
    }

    @Override
    public String getCurrencyValue(String currency) {
        if (StringUtils.isBlank(currency)) {
            return null;
        }
        switch (currency) {
            case "美元":
                currency = "USD";
                break;
            case "人民幣":
            case "人民币":
                currency = "CNY";
                break;
            case "港幣":
            case "港币":
                currency = "HKD";
                break;
            case "澳元":
                currency = "AUD";
                break;
            case "加元":
                currency = "CAD";
                break;
            case "欧元":
                currency = "EUR";
                break;
            case "英鎊":
            case "英镑":
                currency = "GBP";
                break;
            case "新加坡元":
                currency = "SGD";
                break;
            default:
                break;
        }
        return currency;
    }

    @Override
    public PolicyReportData queryPolicyReportData(String policyBizId) {
        // 查询主险信息
        PolicyReportData policyReportData = this.baseMapper.queryPolicyReportData(policyBizId);
        // 处理附加险信息
        List<PolicyAdditional> additionalList= policyAdditionalService.list(new QueryWrapper<PolicyAdditional>().eq("policy_biz_id", policyBizId));
        List<PolicyReportData.AdditionalInsurance> additionalInsurances = new ArrayList<>();
        if (CollUtil.isNotEmpty(additionalList)) {
            for (PolicyAdditional additional : additionalList) {
                PolicyReportData.AdditionalInsurance additionalInsurance = new PolicyReportData.AdditionalInsurance();
                additionalInsurance.setName(additional.getProductLaunchName());
                additionalInsurance.setPaymentTerm(null);
                additionalInsurance.setCurrency(getCurrencyValue(additional.getPolicyCurrency()));
                additionalInsurance.setFirstYearAmount(additional.getEachIssuePremium());
                additionalInsurances.add(additionalInsurance);
            }
        }
        // 处理附加险信息
        policyReportData.setAdditionalInsurances(additionalInsurances);

        return policyReportData;
    }

    /**
     * 根据保单号查询保单跟进信息
     * @param policyNo
     * @return
     */
    @Override
    public PolicyFollow queryOneByPolicyNo(String policyNo) {
        return this.getOne(new LambdaQueryWrapper<PolicyFollow>()
                .eq(PolicyFollow::getPolicyNo,policyNo)
                .last(" limit 1 ")
        );
    }

    @Override
    public PolicyFollow queryOneByPolicyBizId(String policyBizId) {
        return this.getOne(new LambdaQueryWrapper<PolicyFollow>()
                .eq(PolicyFollow::getPolicyBizId,policyBizId)
                .last(" limit 1 ")
        );
    }

    @Override
    public Boolean uploadAttachment(AttachmentUploadRequest attachmentUploadRequest) {
        String policyBizId = attachmentUploadRequest.getPolicyBizId();
        if (policyBizId == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR.getCode(), "policyBizId不能为空");
        }
        String fileName = attachmentUploadRequest.getFileName();
        if (fileName == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR.getCode(), "fileName不能为空");
        }
        String fileUrl = attachmentUploadRequest.getFileUrl();
        if (fileUrl == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR.getCode(), "fileUrl不能为空");
        }
        String ossFileBizId = attachmentUploadRequest.getOssFileBizId();
        if (ossFileBizId == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR.getCode(), "ossFileBizId不能为空");
        }

        PolicyFollowFile policyFollowFile = new PolicyFollowFile();
        policyFollowFile.setPolicyBizId(attachmentUploadRequest.getPolicyBizId());
        policyFollowFile.setOssFileBizId(attachmentUploadRequest.getOssFileBizId());
        policyFollowFile.setFileName(attachmentUploadRequest.getFileName());
        policyFollowFile.setFileUrl(attachmentUploadRequest.getFileUrl());

        return policyFollowFileService.save(policyFollowFile);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean saveInitialPayment(InitialPaymentSaveRequest initialPaymentSaveRequest) {
        // 校验参数
        if (StringUtils.isBlank(initialPaymentSaveRequest.getPolicyBizId())) {
            throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "policyBizId不能为空");
        }

        String policyBizId = initialPaymentSaveRequest.getPolicyBizId();
        PolicyFollow policyFollow = getByPolicyBizId(policyBizId);
        if (policyFollow == null) {
            throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "新单跟进记录不存在");
        }

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

        // 更新相关字段
        boolean result = this.lambdaUpdate()
                .eq(PolicyFollow::getPolicyBizId, policyBizId)
                .set(initialPaymentSaveRequest.getInitialPremium() != null, PolicyFollow::getInitialPremium, initialPaymentSaveRequest.getInitialPremium())
                .set(initialPaymentSaveRequest.getPolicyLevy() != null, PolicyFollow::getPolicyLevy, initialPaymentSaveRequest.getPolicyLevy())
                .set(initialPaymentSaveRequest.getInitialPaymentMethod() != null, PolicyFollow::getInitialPaymentMethod, initialPaymentSaveRequest.getInitialPaymentMethod())
                .set(initialPaymentSaveRequest.getInitialPremiumPaid() != null, PolicyFollow::getInitialPremiumPaid, initialPaymentSaveRequest.getInitialPremiumPaid())
                .set(initialPaymentSaveRequest.getInitialPremiumDue() != null, PolicyFollow::getInitialPremiumDue, initialPaymentSaveRequest.getInitialPremiumDue())
                .set(initialPaymentSaveRequest.getInitialPremiumTotal() != null, PolicyFollow::getInitialPremiumTotal, initialPaymentSaveRequest.getInitialPremiumTotal())
                .set(initialPaymentSaveRequest.getLatestPaymentDate() != null, PolicyFollow::getLatestPaymentDate, initialPaymentSaveRequest.getLatestPaymentDate())
                .set(initialPaymentSaveRequest.getInitialPremiumDiscount() != null, PolicyFollow::getInitialPremiumDiscount, initialPaymentSaveRequest.getInitialPremiumDiscount())
                .set(initialPaymentSaveRequest.getInitialPaymentStatus() != null, PolicyFollow::getInitialPaymentStatus, initialPaymentSaveRequest.getInitialPaymentStatus())
                .set(PolicyFollow::getUpdaterId, loginUserId)
                .set(PolicyFollow::getUpdateTime, new Date())
                .update();

        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean saveMailingInfo(MailingInfoSaveRequest mailingInfoSaveRequest) {
        // 校验参数
        if (StringUtils.isBlank(mailingInfoSaveRequest.getPolicyBizId())) {
            throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "policyBizId不能为空");
        }

        String policyBizId = mailingInfoSaveRequest.getPolicyBizId();
        PolicyFollow policyFollow = getByPolicyBizId(policyBizId);
        if (policyFollow == null) {
            throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "新单跟进记录不存在");
        }

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

        // 更新邮寄信息相关字段

        return this.lambdaUpdate()
                .eq(PolicyFollow::getPolicyBizId, policyBizId)
                .set(mailingInfoSaveRequest.getMailingMethod() != null, PolicyFollow::getMailingMethod, mailingInfoSaveRequest.getMailingMethod())
                .set(mailingInfoSaveRequest.getDeliveryNo() != null, PolicyFollow::getDeliveryNo, mailingInfoSaveRequest.getDeliveryNo())
                .set(mailingInfoSaveRequest.getBrokerSignDate() != null, PolicyFollow::getBrokerSignDate, mailingInfoSaveRequest.getBrokerSignDate())
                .set(mailingInfoSaveRequest.getCustomerSignDate() != null, PolicyFollow::getCustomerSignDate, mailingInfoSaveRequest.getCustomerSignDate())
                .set(mailingInfoSaveRequest.getMailingItem() != null, PolicyFollow::getMailingItem, mailingInfoSaveRequest.getMailingItem())
                .set(PolicyFollow::getUpdaterId, loginUserId)
                .set(PolicyFollow::getUpdateTime, new Date())
                .update();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean batchSaveBrokers(BrokerBatchSaveRequest brokerBatchSaveRequest) {
        // 校验参数
        if (StringUtils.isBlank(brokerBatchSaveRequest.getPolicyBizId())) {
            throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "policyBizId不能为空");
        }

        String policyBizId = brokerBatchSaveRequest.getPolicyBizId();
        PolicyFollow policyFollow = getByPolicyBizId(policyBizId);
        if (policyFollow == null) {
            throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "新单跟进记录不存在");
        }

        if (CollectionUtils.isEmpty(brokerBatchSaveRequest.getBrokerList())) {
            throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "介绍人列表不能为空");
        }

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

        // 删除该 policyBizId 下的所有现有介绍人
        policyBrokerService.lambdaUpdate()
                .eq(PolicyBroker::getPolicyBizId, policyBizId)
                .remove();

        // 批量插入新的介绍人记录
        List<PolicyBroker> brokerList = new ArrayList<>();
        for (BrokerBatchSaveRequest.BrokerInfo brokerInfo : brokerBatchSaveRequest.getBrokerList()) {
            PolicyBroker policyBroker = new PolicyBroker();
            policyBroker.setPolicyBizId(policyBizId);
            policyBroker.setPolicyNo(policyFollow.getPolicyNo());
            policyBroker.setBrokerName(brokerInfo.getBrokerName());
            policyBroker.setBrokerBizId(brokerInfo.getBrokerBizId());
            policyBroker.setGender(brokerInfo.getGender());
            policyBroker.setInternalCode(brokerInfo.getInternalCode());
            policyBroker.setTeam(brokerInfo.getTeam());
            policyBroker.setTeamBizId(brokerInfo.getTeamBizId());
            policyBroker.setBrokerRatio(brokerInfo.getBrokerRatio());
            policyBroker.setRemark(brokerInfo.getRemark());
            policyBroker.setIsDeleted(0);
            policyBroker.setCreatorId(loginUserId);
            policyBroker.setCreateTime(new Date());
            policyBroker.setUpdaterId(loginUserId);
            policyBroker.setUpdateTime(new Date());
            brokerList.add(policyBroker);
        }

        return policyBrokerService.saveBatch(brokerList);
    }

    @Override
    public Page<PolicyNumberResponseVO> queryPolicyNumbers(PolicyNosQueryRequest policyNosQueryRequest) {
        String policyNo = policyNosQueryRequest.getPolicyNo();

        // 创建分页对象
        Page<PolicyFollow> page = new Page<>(policyNosQueryRequest.getPageNo(), policyNosQueryRequest.getPageSize());

        // 构建查询条件
        QueryWrapper<PolicyFollow> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("policy_no", "insurance_company", "insurance_company_biz_id", "insured", "insured_biz_id");
        queryWrapper.like(ObjectUtils.isNotEmpty(policyNo), "policy_no", policyNo);
        queryWrapper.isNotNull("policy_no");

        // 执行分页查询
        Page<PolicyFollow> policyFollowPage = policyFollowService.page(page, queryWrapper);

        // 转换结果
        Page<PolicyNumberResponseVO> resultPage = new Page<>(policyFollowPage.getCurrent(), policyFollowPage.getSize(), policyFollowPage.getTotal());
        List<PolicyNumberResponseVO> voList = policyFollowPage.getRecords().stream()
                .map(this::convertToPolicyNumberResponseVO)
                .collect(Collectors.toList());
        resultPage.setRecords(voList);

        return resultPage;
    }

    @Override
    public List<PolicyFollow> queryList(List<String> policyNoList) {
        List<PolicyFollow> list = baseMapper.selectList(new LambdaQueryWrapper<PolicyFollow>()
                .in(!CollectionUtils.isEmpty(policyNoList), PolicyFollow::getPolicyNo, policyNoList)
        );
        return list;
    }

    @Override
    public List<PolicyFollow> queryListByAppointmentBizId(String appointmentBizId) {
        List<PolicyFollow> list = baseMapper.selectList(new LambdaQueryWrapper<PolicyFollow>()
                .eq(StringUtils.isNotBlank(appointmentBizId), PolicyFollow::getAppointmentBizId, appointmentBizId)
        );
        return list;
    }

    /**
     * 转换为保单号查询响应视图
     *
     * @param policyFollow 新单跟进实体
     * @return 保单号查询响应视图
     */
    private PolicyNumberResponseVO convertToPolicyNumberResponseVO(PolicyFollow policyFollow) {
        if (policyFollow == null) {
            return null;
        }
        PolicyNumberResponseVO vo = new PolicyNumberResponseVO();
        vo.setPolicyNo(policyFollow.getPolicyNo());
        vo.setInsuranceCompany(policyFollow.getInsuranceCompany());
        vo.setInsuranceCompanyBizId(policyFollow.getInsuranceCompanyBizId());
        vo.setInsured(policyFollow.getInsured());
        vo.setInsuredBizId(policyFollow.getInsuredBizId());
        return vo;
    }

    /**
     * 根据保单生成预计入账记录
     *
     * @param policyFollow 保单跟进信息
     */
    private void generateExpectedCommission(PolicyFollow policyFollow, Policy policy) {
        if (policyFollow == null) {
            return;
        }

        // 获取必要的参数
        String policyNo = policyFollow.getPolicyNo();
        String productLaunchBizId = policyFollow.getProductLaunchBizId();
        String insuranceCompanyBizId = policyFollow.getInsuranceCompanyBizId();
        String reconciliationCompany = policy.getReconciliationCompany();
        String reconciliationCompanyCode = policy.getReconciliationCompanyCode();
        String reconciliationCompanyBizId = policy.getReconciliationCompanyBizId();

        // 调用预计入账服务生成记录
        commissionExpectedService.getExpectedCommissionByProductlaunchId(
                policy,
                productLaunchBizId,
                insuranceCompanyBizId,
                reconciliationCompany,
                reconciliationCompanyCode,
                reconciliationCompanyBizId,
                policyFollow.getProfessionalInvestor()
        );
    }

    /**
     * 获取单个保单产品信息
     *
     * @param productLaunchBizId 产品上架业务ID
     * @return 产品信息，如果未找到则返回 null
     */
    private PolicyProductInfo getPolicyProductInfo(String productLaunchBizId) {
        if (StringUtils.isBlank(productLaunchBizId)) {
            log.warn("产品上架业务ID为空，无法获取产品信息");
            return null;
        }

        try {
            // 调用 PolicyService 的批量查询方法，传入单个 ID
            Map<String, PolicyProductInfo> productInfoMap = policyService.getPolicyProductInfoMap(
                    Collections.singletonList(productLaunchBizId)
            );

            if (productInfoMap == null || productInfoMap.isEmpty()) {
                log.warn("未找到产品信息，productLaunchBizId: {}", productLaunchBizId);
                return null;
            }

            PolicyProductInfo productInfo = productInfoMap.get(productLaunchBizId);
            if (productInfo == null) {
                log.warn("产品信息为空，productLaunchBizId: {}", productLaunchBizId);
                return null;
            }
            if (ObjectUtils.isEmpty(productInfo.getReconciliationCompanyBizId())) {
                throw new BusinessException("产品上架信息未配置对账公司");
            }

            log.info("成功获取产品信息: productLaunchBizId={}, reconciliationCompanyBizId={}, reconciliationCompany={}",
                    productLaunchBizId,
                    productInfo.getReconciliationCompanyBizId(),
                    productInfo.getReconciliationCompany()
                    );

            return productInfo;
        } catch (Exception e) {
            log.error("获取产品信息失败，productLaunchBizId: {}, error: {}", productLaunchBizId, e.getMessage(), e);
            return null;
        }
    }

    @Override
    public PolicyDto getProductPlan(String policyBizId) {
        Policy policy = policyService.getOne(new QueryWrapper<Policy>().eq("policy_biz_id", policyBizId));
        List<PolicyAdditional> policyAdditionalList = policyAdditionalService.lambdaQuery()
                .eq(PolicyAdditional::getPolicyBizId, policyBizId)
                .list();
        // 转换为DTO
        return PolicyDto.convertToDto(policy, policyAdditionalList);
    }

    @Override
    public PolicyPolicyholder getPolicyPolicyholder(String policyBizId) {
        return policyPolicyholderService.getOne(new QueryWrapper<PolicyPolicyholder>().eq("policy_biz_id", policyBizId).eq("is_deleted", 0));
    }

    @Override
    public PolicyInsurant getPolicyInsurant(String policyBizId) {
        return policyInsurantService.getOne(new QueryWrapper<PolicyInsurant>().eq("policy_biz_id", policyBizId).eq("is_deleted", 0));
    }

    @Override
    public List<PolicyBeneficiary> getPolicyBeneficiaryList(String policyBizId) {
        return policyBeneficiaryService.list(new QueryWrapper<PolicyBeneficiary>().eq("policy_biz_id", policyBizId).eq("is_deleted", 0));
    }

    @Override
    public PolicySecondHolder getPolicySecondHolder(String policyBizId) {
        return policySecondHolderService.getOne(new QueryWrapper<PolicySecondHolder>().eq("policy_biz_id", policyBizId).eq("is_deleted", 0));
    }

    @Override
    public List<PolicyAppointmentFile> getPolicyAppointmentFileList(String policyBizId) {
        return policyAppointmentFileService.list(new QueryWrapper<PolicyAppointmentFile>().eq("policy_biz_id", policyBizId).eq("is_deleted", 0));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateProductPlan(PolicyUpdateRequest policyUpdateRequest) {
        if (policyUpdateRequest == null || StringUtils.isBlank(policyUpdateRequest.getPolicyBizId())) {
            throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "policyBizId不能为空");
        }
        return policyService.updatePolicy(policyUpdateRequest);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updatePolicyPolicyholder(PolicyPolicyholderUpdateRequest policyPolicyholderUpdateRequest) {
        if (policyPolicyholderUpdateRequest == null || StringUtils.isBlank(policyPolicyholderUpdateRequest.getPolicyPolicyholderBizId())) {
            throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "policyPolicyholderBizId不能为空");
        }
        return policyPolicyholderService.update(policyPolicyholderUpdateRequest);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updatePolicyInsurant(PolicyInsurantUpdateRequest policyInsurantUpdateRequest) {
        if (policyInsurantUpdateRequest == null || StringUtils.isBlank(policyInsurantUpdateRequest.getPolicyInsurantBizId())) {
            throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "policyInsurantBizId不能为空");
        }
        return policyInsurantService.update(policyInsurantUpdateRequest);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updatePolicyBeneficiaryList(PolicyBeneficiaryListUpdateRequest policyBeneficiaryListUpdateRequest) {
        if (policyBeneficiaryListUpdateRequest == null || StringUtils.isBlank(policyBeneficiaryListUpdateRequest.getPolicyBizId())) {
            throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "policyBizId不能为空");
        }
        return policyBeneficiaryService.updatePolicyBeneficiaryList(policyBeneficiaryListUpdateRequest);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updatePolicySecondHolder(PolicySecondHolderUpdateRequest policySecondHolderUpdateRequest) {
        if (policySecondHolderUpdateRequest == null || StringUtils.isBlank(policySecondHolderUpdateRequest.getPolicySecondHolderBizId())) {
            throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "policySecondHolderBizId不能为空");
        }
        return policySecondHolderService.updatePolicySecondHolder(policySecondHolderUpdateRequest);
    }

    @Override
    public Map<String, PolicyFollow> queryPolicyFollowMap(Collection<?> policyNoSet) {
        if (CollectionUtils.isEmpty(policyNoSet)) {
            return Collections.emptyMap();
        }
        List<PolicyFollow> policyFollowList = this.list(new QueryWrapper<PolicyFollow>().in("policy_no", policyNoSet));
        return policyFollowList.stream().collect(Collectors.toMap(PolicyFollow::getPolicyNo, Function.identity(), (oldValue, newValue) -> newValue));
    }

    /**
     * 根据保单号查询新单跟进详情
     * @param policyNo
     * @return
     */
    @Override
    public Result<ApiPolicyFollowDetailResponse> detail(String policyNo){
        if (StringUtils.isBlank(policyNo)) {
            throw new BusinessException("保单号不能为空");
        }
        PolicyFollow policyFollow = this.queryOneByPolicyNo(policyNo);
        if (policyFollow == null) {
            throw new BusinessException("新单跟进信息不存在");
        }
        ApiPolicyFollowDetailResponse response = new ApiPolicyFollowDetailResponse();
        BeanUtils.copyProperties(policyFollow,response);
        return Result.success(response);
    }

    @Override
    public List<String> queryPolicyNoList(String policyHolder, String signer, String brokerName, String insured) {
        // 投保人转换：中文转简体、英文转小写
        String policyHolderSc = ChineseTextConverter.traditionalToSimplified(policyHolder);
        String policyHolderEnLc = EnglishTextUtil.toLowerCase(policyHolder);

        // 受保人转换：中文转简体、英文转小写
        String insuredSc = ChineseTextConverter.traditionalToSimplified(insured);
        String insuredEnLc = EnglishTextUtil.toLowerCase(insured);

        return this.baseMapper.queryPolicyNoList(
                policyHolderSc, policyHolderEnLc,
                signer,
                brokerName,
                insuredSc, insuredEnLc
        );
    }

    /**
     * 更新-新单跟进投保人和受保人的名字冗余字段
     * @return
     */
    @Override
    public Result updateTs() {
        int pageSize = 200;

        // 1. 更新投保人表
        updatePolicyholderNameFields(pageSize);

        // 2. 更新受保人表
        updateInsurantNameFields(pageSize);

        // 3. 更新客户表
        updateCustomerNameFields(pageSize);

        log.info("投保人/受保人名字冗余字段更新完成");
        return Result.success("更新成功");
    }

    /**
     * 批量处理 policy_policyholder 的 nameSc 和 nameEnLc
     */
    private void updatePolicyholderNameFields(int pageSize) {
        int pageNo = 1;
        while (true) {
            Page<PolicyPolicyholder> page = new Page<>(pageNo, pageSize);
            Page<PolicyPolicyholder> resultPage = policyPolicyholderService.page(page);
            List<PolicyPolicyholder> records = resultPage.getRecords();
            if (CollUtil.isEmpty(records)) {
                break;
            }

            List<PolicyPolicyholder> toUpdate = new ArrayList<>();
            for (PolicyPolicyholder entity : records) {
                boolean changed = false;

                // 繁体 → 简体
                if (StringUtils.isNotBlank(entity.getName())) {
                    String nameSc = ChineseTextConverter.traditionalToSimplified(entity.getName());
                    if (!nameSc.equals(entity.getNameSc())) {
                        entity.setNameSc(nameSc);
                        changed = true;
                    }
                }

                // 英文 → 小写
                if (StringUtils.isNotBlank(entity.getNameEn())) {
                    String nameEnLc = EnglishTextUtil.toLowerCase(entity.getNameEn());
                    if (!nameEnLc.equals(entity.getNameEnLc())) {
                        entity.setNameEnLc(nameEnLc);
                        changed = true;
                    }
                }

                if (changed) {
                    entity.setUpdateTime(new Date()); // 可选，记录更新时间
                    toUpdate.add(entity);
                }
            }

            if (!toUpdate.isEmpty()) {
                policyPolicyholderService.updateBatchById(toUpdate);
            }
            pageNo++;
        }
    }

    /**
     * 批量处理 policy_insurant 的 nameSc 和 nameEnLc
     */
    private void updateInsurantNameFields(int pageSize) {
        int pageNo = 1;
        while (true) {
            Page<PolicyInsurant> page = new Page<>(pageNo, pageSize);
            Page<PolicyInsurant> resultPage = policyInsurantService.page(page);
            List<PolicyInsurant> records = resultPage.getRecords();
            if (CollUtil.isEmpty(records)) {
                break;
            }

            List<PolicyInsurant> toUpdate = new ArrayList<>();
            for (PolicyInsurant entity : records) {
                boolean changed = false;

                if (StringUtils.isNotBlank(entity.getName())) {
                    String nameSc = ChineseTextConverter.traditionalToSimplified(entity.getName());
                    if (!nameSc.equals(entity.getNameSc())) {
                        entity.setNameSc(nameSc);
                        changed = true;
                    }
                }

                if (StringUtils.isNotBlank(entity.getNameEn())) {
                    String nameEnLc = EnglishTextUtil.toLowerCase(entity.getNameEn());
                    if (!nameEnLc.equals(entity.getNameEnLc())) {
                        entity.setNameEnLc(nameEnLc);
                        changed = true;
                    }
                }

                if (changed) {
                    entity.setUpdateTime(new Date());
                    toUpdate.add(entity);
                }
            }

            if (!toUpdate.isEmpty()) {
                policyInsurantService.updateBatchById(toUpdate);
            }
            pageNo++;
        }
    }

    /**
     * 批量处理 customer 的 nameSc 和 nameEnLc
     */
    private void updateCustomerNameFields(int pageSize) {
        int pageNo = 1;
        while (true) {
            Page<Customer> page = new Page<>(pageNo, pageSize);
            Page<Customer> resultPage = customerService.page(page);
            List<Customer> records = resultPage.getRecords();
            if (CollUtil.isEmpty(records)) {
                break;
            }

            List<Customer> toUpdate = new ArrayList<>();
            for (Customer entity : records) {
                boolean changed = false;

                if (StringUtils.isNotBlank(entity.getNameCn())) {
                    String nameSc = ChineseTextConverter.traditionalToSimplified(entity.getNameCn());
                    if (!nameSc.equals(entity.getNameSc())) {
                        entity.setNameSc(nameSc);
                        changed = true;
                    }
                }

                if (StringUtils.isNotBlank(entity.getNamePyEn())) {
                    String nameEnLc = EnglishTextUtil.toLowerCase(entity.getNamePyEn());
                    if (!nameEnLc.equals(entity.getNameEnLc())) {
                        entity.setNameEnLc(nameEnLc);
                        changed = true;
                    }
                }

                if (changed) {
                    entity.setUpdateTime(new Date());
                    toUpdate.add(entity);
                }
            }

            if (!toUpdate.isEmpty()) {
                customerService.updateBatchById(toUpdate);
            }
            pageNo++;
        }
    }
}

