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

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yd.base.feign.client.exchangerate.ApiExchangeRateFeignClient;
import com.yd.base.feign.request.exchangerate.ApiExchangeRateConvertRequest;
import com.yd.base.feign.response.exchangerate.ApiExchangeRateConvertResponse;
import com.yd.common.enums.CommonEnum;
import com.yd.common.exception.BusinessException;
import com.yd.common.result.Result;
import com.yd.common.utils.RandomStringGenerator;
import com.yd.csf.api.service.ApiPremiumReconciliationService;
import com.yd.csf.api.service.ApiPremiumRemittanceService;
import com.yd.csf.feign.dto.premiumreconciliation.ApiPremiumReconciliationDto;
import com.yd.csf.feign.dto.premiumremittance.ApiPremiumRemittanceDto;
import com.yd.csf.feign.enums.ReconciliationStatusEnum;
import com.yd.csf.feign.request.premiumreconciliation.ApiCalculateRemainingUnpaidAmountRequest;
import com.yd.csf.feign.request.premiumreconciliation.ApiPremiumReconciliationAddRequest;
import com.yd.csf.feign.request.premiumreconciliation.ApiPremiumReconciliationPageRequest;
import com.yd.csf.feign.request.premiumreconciliation.ApiPremiumReconciliationResultEditRequest;
import com.yd.csf.feign.response.premiumreconciliation.ApiCalculateRemainingUnpaidAmountResponse;
import com.yd.csf.feign.response.premiumreconciliation.ApiPremiumReconciliationDetailResponse;
import com.yd.csf.feign.response.premiumreconciliation.ApiPremiumReconciliationPageResponse;
import com.yd.csf.feign.response.team.ApiTeamPageResponse;
import com.yd.csf.service.dto.PremiumReconciliationDto;
import com.yd.csf.service.model.Policy;
import com.yd.csf.service.model.PolicyFollow;
import com.yd.csf.service.model.PremiumReconciliation;
import com.yd.csf.service.service.IPremiumReconciliationService;
import com.yd.csf.service.service.PolicyFollowService;
import com.yd.csf.service.service.PolicyService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.Objects;

@Slf4j
@Service
public class ApiPremiumReconciliationServiceImpl implements ApiPremiumReconciliationService {

    @Autowired
    private PolicyService policyService;

    @Autowired
    private IPremiumReconciliationService iPremiumReconciliationService;

    @Autowired
    private ApiPremiumRemittanceService apiPremiumRemittanceService;

    @Autowired
    private ApiExchangeRateFeignClient apiExchangeRateFeignClient;

    @Autowired
    private PolicyFollowService policyFollowService;

    /**
     * 分页列表查询-保费对账记录信息
     * @param request
     * @return
     */
    @Override
    public Result<IPage<ApiPremiumReconciliationPageResponse>> page(ApiPremiumReconciliationPageRequest request) {
        Page<ApiPremiumReconciliationPageResponse> page = new Page<>(request.getPageNo(), request.getPageSize());
        IPage<ApiPremiumReconciliationPageResponse> iPage = iPremiumReconciliationService.page(page, request);
        return Result.success(iPage);
    }

    /**
     * 添加-保费对账记录信息
     * @param request
     * @return
     */
    @Override
    public Result add(ApiPremiumReconciliationAddRequest request) {
        //根据当前Policy保单信息里面的生效日期、付款频率、缴费宽限期，校验当天是否在缴费期内，不在缴费期内不能保费对账 TODO 校验待定
        //保费对账信息
        ApiPremiumReconciliationDto apiPremiumReconciliationDto = request.getApiPremiumReconciliationDto();
        //校验-保单所有期数的保费对账是否对账完成（全部对账完成就不能新增录入对账信息了）
        Result<Boolean> result = checkReconciliationComplete(apiPremiumReconciliationDto.getPolicyNo());
        if (!result.getData()) {
            throw new BusinessException(result.getMsg());
        }
        //校验保单信息是否存在
        Policy policy = policyService.queryOne(apiPremiumReconciliationDto.getPolicyNo());
        if (Objects.isNull(policy)) {
            throw new BusinessException("保单信息不存在");
        }
        //计算当前期数
        String currentIssueNumber = calculateCurrentIssueNumber(policy.getPolicyNo(),Integer.parseInt(policy.getPaymentTerm().toString()));
        PremiumReconciliation premiumReconciliation = new PremiumReconciliation();
        //申请人
        premiumReconciliation.setApplicant(apiPremiumReconciliationDto.getApplicant());
        //当前期数
        premiumReconciliation.setCurrentIssueNumber(currentIssueNumber);
        //保单受保人（被保人）
        premiumReconciliation.setInsured(policy.getInsured());
        //保险公司名称
        premiumReconciliation.setInsurer(policy.getInsurer());
        //保单号
        premiumReconciliation.setPolicyNo(policy.getPolicyNo());
        //保费对账记录表唯一业务ID
        premiumReconciliation.setPremiumReconciliationBizId(RandomStringGenerator.generateBizId16(CommonEnum.UID_TYPE_PREMIUM_RECONCILIATION.getCode()));
        //对账状态 - 保司对账中
        premiumReconciliation.setReconciliationStatus(ReconciliationStatusEnum.BS_DZZ.getItemValue());
        iPremiumReconciliationService.saveOrUpdate(premiumReconciliation);

        //添加-保费对账汇款记录列表
        apiPremiumRemittanceService.addPremiumRemittanceList(request.getApiPremiumRemittanceDtoList(),
                premiumReconciliation.getPremiumReconciliationBizId());

        return Result.success();
    }

    /**
     * 计算当前期数
     * @param policyNo
     * @return
     */
    public String calculateCurrentIssueNumber(String policyNo,Integer paymentTerm) {
        //保单号查询对账记录无数据，说明第一期。有数据：1、最新的记录的待付金额大于0，当前期数为最新的记录期数。2、最新的记录的待付金额小于等于0，当前期数 = 最新的记录期数 + 1 <= 保单的供款年期
        //保单号查询对账记录无数据，说明第一期
        //根据保单号查询最新对账记录
        PremiumReconciliation premiumReconciliation = iPremiumReconciliationService.queryLatestOneByPolicyNo(policyNo);
        if (Objects.isNull(premiumReconciliation)) {
            return "1";
        }
        //有数据，最新的记录的待付金额大于0，当前期数为最新的记录期数
        if (premiumReconciliation.getRemainingUnpaidAmount().compareTo(BigDecimal.ZERO) > 0) {
            return premiumReconciliation.getCurrentIssueNumber();
        }
        //最新的记录的待付金额小于等于0，当前期数 = 最新的记录期数 + 1 <= 保单的供款年期
        if (premiumReconciliation.getRemainingUnpaidAmount().compareTo(BigDecimal.ZERO) <= 0) {
            //最新的记录期数 + 1
            Integer thisQs = Integer.parseInt(premiumReconciliation.getCurrentIssueNumber()) + 1;
            if (thisQs > paymentTerm) {
                //最新的记录期数 + 1 > 保单的供款年期，提示
                throw new BusinessException("当前保单保费所有期数已经全部对账完成，不能对账了");
            }
            return thisQs.toString();
        }
        return "1";
    }

    /**
     * 编辑-单个保费对账记录信息
     * @param request
     * @return
     */
    @Override
    public Result edit(ApiPremiumReconciliationDto request) {
        if (StringUtils.isBlank(request.getPremiumReconciliationBizId())) {
            throw new BusinessException("保费对账记录表唯一业务ID不能为空");
        }
        //校验保费对账记录信息是否存在
        Result<PremiumReconciliation> result = checkPremiumReconciliationIsExist(request.getPremiumReconciliationBizId());
        PremiumReconciliation premiumReconciliation = result.getData();
        BeanUtils.copyProperties(request,premiumReconciliation);
        iPremiumReconciliationService.saveOrUpdate(premiumReconciliation);
        return Result.success();
    }

    /**
     * 详情-保费对账记录信息
     * @param premiumReconciliationBizId 保费对账记录表唯一业务ID
     * @return
     */
    @Override
    public Result<ApiPremiumReconciliationDetailResponse> detail(String premiumReconciliationBizId) {
        ApiPremiumReconciliationDetailResponse response = new ApiPremiumReconciliationDetailResponse();
        //校验保费对账记录信息是否存在
        Result<PremiumReconciliation> result = checkPremiumReconciliationIsExist(premiumReconciliationBizId);
        PremiumReconciliation premiumReconciliation = result.getData();
        ApiPremiumReconciliationDto apiPremiumReconciliationDto = new ApiPremiumReconciliationDto();
        BeanUtils.copyProperties(premiumReconciliation,apiPremiumReconciliationDto);
        response.setApiPremiumReconciliationDto(apiPremiumReconciliationDto);
        //保费对账-汇款记录列表
        List<ApiPremiumRemittanceDto> apiPremiumRemittanceDtoList = apiPremiumRemittanceService.apiPremiumRemittanceDtoList(premiumReconciliationBizId);
        response.setApiPremiumRemittanceDtoList(apiPremiumRemittanceDtoList);
        return Result.success(response);
    }

    /**
     * 计算待付金额-保费对账记录信息
     * @param request
     * @return
     */
    @Override
    public Result<ApiCalculateRemainingUnpaidAmountResponse> calculateRemainingUnpaidAmount(ApiCalculateRemainingUnpaidAmountRequest request) {
        //校验保费对账记录信息是否存在
        Result<PremiumReconciliation> result = checkPremiumReconciliationIsExist(request.getPremiumReconciliationBizId());
        PremiumReconciliation premiumReconciliation = result.getData();

        //查询保单信息
        Policy policy = policyService.queryOne(premiumReconciliation.getPolicyNo());
        if (Objects.isNull(policy)) {
            throw new BusinessException("保单信息不存在");
        }

        //获取保单币种
        String policyCurrency = policy.getCurrency();
        if (StringUtils.isBlank(policyCurrency)) {
            throw new BusinessException("保单币种不能为空");
        }

        //验证保单币种是否支持 - 通过Feign客户端调用
        Result<Boolean> currencySupportedResult = apiExchangeRateFeignClient.isCurrencySupportedResult(policyCurrency);
        if (currencySupportedResult.getCode() != 200 || Boolean.FALSE.equals(currencySupportedResult.getData())) {
            throw new BusinessException("保单币种不支持: " + policyCurrency);
        }

        //将当次保司认定金额转换为保单币种的金额
        String recognizedCurrency = request.getRecognizedCurrency();
        if (StringUtils.isBlank(recognizedCurrency)) {
            throw new BusinessException("当次保司认定币种不能为空");
        }

        //验证认定币种是否支持 - 通过Feign客户端调用
        Result<Boolean> recognizedCurrencySupportedResult = apiExchangeRateFeignClient.isCurrencySupportedResult(recognizedCurrency);
        if (recognizedCurrencySupportedResult.getCode() != 200 || Boolean.FALSE.equals(recognizedCurrencySupportedResult.getData())) {
            throw new BusinessException("认定币种不支持: " + recognizedCurrency);
        }

        //转换当次保司认定金额到保单币种的金额 - 通过Feign客户端调用
        BigDecimal currentRecognizedAmount = request.getRecognizedAmount();
        BigDecimal currentRecognizedAmountInPolicyCurrency;

        if (recognizedCurrency.equalsIgnoreCase(policyCurrency)) {
            // 币种相同，直接使用原金额
            currentRecognizedAmountInPolicyCurrency = currentRecognizedAmount;
        } else {
            // 币种不相同，调用汇率服务进行转换
            ApiExchangeRateConvertRequest convertRequest = new ApiExchangeRateConvertRequest();
            //被转换金额
            convertRequest.setAmount(currentRecognizedAmount);
            //被转换币种
            convertRequest.setFromCurrency(recognizedCurrency);
            //转换币种
            convertRequest.setToCurrency(policyCurrency);
            // 可以根据需要设置交易日期或汇率日期，这里null查询最新汇率日期的汇率转换
            convertRequest.setTransactionDate(null);
//            convertRequest.setTransactionDate(request.getTransactionDate());

            Result<ApiExchangeRateConvertResponse> convertResult = apiExchangeRateFeignClient.convert(convertRequest);
            if (convertResult.getCode() != 200) {
                throw new BusinessException("币种转换失败: " + convertResult.getMsg());
            }

            currentRecognizedAmountInPolicyCurrency = convertResult.getData().getConvertedAmount();
        }

        //根据当前期数和保单号，查询非当前保费对账记录的保司认定金额之和
        List<PremiumReconciliation> premiumReconciliationList = iPremiumReconciliationService.queryList(PremiumReconciliationDto.builder()
                .premiumReconciliationBizId(request.getPremiumReconciliationBizId())
                .currentIssueNumber(premiumReconciliation.getCurrentIssueNumber())
                .isExcludeMy(true)
                .build());

        //计算非当前保费对账记录的保司认定金额之和（转换为保单币种）
        BigDecimal otherRecognizedAmountSumInPolicyCurrency = BigDecimal.ZERO;
        if (!CollectionUtils.isEmpty(premiumReconciliationList)) {
            for (PremiumReconciliation pr : premiumReconciliationList) {
                if (pr.getRecognizedAmount() != null && StringUtils.isNotBlank(pr.getRecognizedCurrency())) {
                    //将每条记录的认定金额转换为保单币种
                    BigDecimal convertedAmount;

                    if (pr.getRecognizedCurrency().equalsIgnoreCase(policyCurrency)) {
                        // 币种相同，直接使用
                        convertedAmount = pr.getRecognizedAmount();
                    } else {
                        // 调用汇率服务进行转换
                        ApiExchangeRateConvertRequest prConvertRequest = new ApiExchangeRateConvertRequest();
                        prConvertRequest.setAmount(pr.getRecognizedAmount());
                        prConvertRequest.setFromCurrency(pr.getRecognizedCurrency());
                        prConvertRequest.setToCurrency(policyCurrency);

                        Result<ApiExchangeRateConvertResponse> prConvertResult = apiExchangeRateFeignClient.convert(prConvertRequest);
                        if (prConvertResult.getCode() != 200) {
                            log.warn("保费对账记录币种转换失败，记录ID: {}, 原因: {}",
                                    pr.getPremiumReconciliationBizId(), prConvertResult.getMsg());
                            continue; // 跳过转换失败的记录
                        }

                        convertedAmount = prConvertResult.getData().getConvertedAmount();
                    }

                    otherRecognizedAmountSumInPolicyCurrency = otherRecognizedAmountSumInPolicyCurrency.add(convertedAmount);
                }
            }
        }

        //计算总认定金额（保单币种）
        BigDecimal totalRecognizedAmountInPolicyCurrency =
                otherRecognizedAmountSumInPolicyCurrency.add(currentRecognizedAmountInPolicyCurrency);

        //获取期交保费（如果为空则设为0）
        BigDecimal paymentPremium = policy.getPaymentPremium() != null ?
                policy.getPaymentPremium() : BigDecimal.ZERO;

        //获取保单征费（转换为BigDecimal）
        BigDecimal policyLevy = BigDecimal.ZERO;
        if (StringUtils.isNotBlank(policy.getPolicyLevy())) {
            try {
                // 注意：保单征费的币种应该与保单币种一致，但这里可以再次确认
                String policyLevyStr = policy.getPolicyLevy().trim();
                // 如果保单征费包含币种信息，需要解析，这里假设是纯数字字符串
                policyLevy = new BigDecimal(policyLevyStr);
            } catch (NumberFormatException e) {
                log.error("保单征费格式错误，policyLevy: {}", policy.getPolicyLevy());
                throw new BusinessException("保单征费格式错误，无法计算");
            }
        }

        //计算总额和剩余待付金额（均为保单币种）
        BigDecimal totalPremium = paymentPremium.add(policyLevy);
        BigDecimal remainingUnpaidAmount = totalPremium.subtract(totalRecognizedAmountInPolicyCurrency);

        //如果剩余待付金额为负数，说明已超额支付，可以设为0或负数，根据业务需求
        // 如果要求不能为负数，则取最大值
        // remainingUnpaidAmount = remainingUnpaidAmount.max(BigDecimal.ZERO);

        // 设置精度，保留2位小数，银行家舍入法
        remainingUnpaidAmount = remainingUnpaidAmount.setScale(2, RoundingMode.HALF_EVEN);

        //构建响应对象
        ApiCalculateRemainingUnpaidAmountResponse response = new ApiCalculateRemainingUnpaidAmountResponse();
        response.setRemainingUnpaidAmount(remainingUnpaidAmount);
        response.setRemainingUnpaidCurrency(policyCurrency);

        return Result.success(response);
    }

    /**
     * 设置认定结果-保费对账记录信息
     * @param request
     * @return
     */
    @Override
    public Result editResult(ApiPremiumReconciliationResultEditRequest request) {
        //校验保费对账记录信息是否存在
        Result<PremiumReconciliation> result = checkPremiumReconciliationIsExist(request.getPremiumReconciliationBizId());
        PremiumReconciliation premiumReconciliation = result.getData();
        BeanUtils.copyProperties(request,premiumReconciliation);
        //对账状态->保司对账成功
        premiumReconciliation.setReconciliationStatus(ReconciliationStatusEnum.BS_DZ_CG.getItemValue());
        //更新保费对账记录信息
        iPremiumReconciliationService.saveOrUpdate(premiumReconciliation);

        //校验当期剩余待付金额小于等于0并且当前期数是第一期首期，才会去更新保单生效日期和保单状态
        if (premiumReconciliation.getCurrentIssueNumber().equals("1")) {
            //当前期数是第一期首期
            if (request.getRemainingUnpaidAmount().compareTo(BigDecimal.ZERO) <= 0) {
                //校验生效日期、核保日期必填
                if (Objects.isNull(request.getEffectiveDate())) {
                    throw new BusinessException("生效日期不能为空");
                }
                if (Objects.isNull(request.getUnderwritingDate())) {
                    throw new BusinessException("核保日期不能为空");
                }
                //更新新单和保单状态为生效中，更新生效日期和核保日期
                //更新新单跟进：新单状态——>生效、生效日期、核保日期
                PolicyFollow policyFollow = policyFollowService.queryOneByPolicyNo(premiumReconciliation.getPolicyNo());
                if (!Objects.isNull(policyFollow)) {
                    //生效日期
                    policyFollow.setEffectiveDate(request.getEffectiveDate());
                    //核保日期
                    policyFollow.setUnderwritingDate(request.getUnderwritingDate());
                    //新单跟进状态——>生效
                    policyFollow.setStatus("TAKE_EFFECT");
                    policyFollowService.saveOrUpdate(policyFollow);
                }
                //更新保单信息：保单状态——>生效、生效日期、核保日期
                Policy policy = policyService.queryOne(premiumReconciliation.getPolicyNo());
                if (!Objects.isNull(policy)) {
                    //生效日期
                    policy.setEffectiveDate(request.getEffectiveDate());
                    //核保日期
                    policy.setUnderwritingDate(request.getUnderwritingDate());
                    //保单状态——>生效
                    policy.setStatus("TAKE_EFFECT");
                    policyService.saveOrUpdate(policy);
                }
            }else {
                //大于0，只更新新单跟进：新单状态——>保费对账成功，核保中
                PolicyFollow policyFollow = policyFollowService.queryOneByPolicyNo(premiumReconciliation.getPolicyNo());
                if (!Objects.isNull(policyFollow)) {
                    //新单跟进状态——>保费对账成功，核保中
                    policyFollow.setStatus("UNDERWRITING_PROGRESS");
                    policyFollowService.saveOrUpdate(policyFollow);
                }
            }
        }
        return Result.success();
    }

    /**
     * 校验-保单所有期数的保费对账是否对账完成（全部对账完成就不能新增录入对账信息了）
     * @param policyNo
     * @return
     */
    @Override
    public Result<Boolean> checkReconciliationComplete(String policyNo) {
        //查询保单信息
        Policy policy = policyService.queryOne(policyNo);
        if (Objects.isNull(policy)) {
            throw new BusinessException("保单信息不存在");
        }
        //获取保单供款年期
        String paymentTerm = String.valueOf(policy.getPaymentTerm());
        //根据保单号查询最新对账记录
        PremiumReconciliation premiumReconciliation = iPremiumReconciliationService.queryLatestOneByPolicyNo(policyNo);
        if (Objects.isNull(premiumReconciliation)) {
            //无数据，说明还没有对账记录，可以对账。
            return Result.success(true);
        }
        //有数据
        //校验最新对账记录的待付金额是否小于等于0并且当前期数等于保单的供款年期，如果是说明对账所有期数已经全部完成不能对账了。
        if (premiumReconciliation.getRemainingUnpaidAmount().compareTo(BigDecimal.ZERO) <= 0
                && premiumReconciliation.getCurrentIssueNumber().equals(paymentTerm)) {
            return Result.success(false,"当前保单保费所有期数已经全部对账完成，不能对账了");
        }
        return Result.success(true);
    }

    /**
     * 校验保费对账记录信息是否存在
     * @param premiumReconciliationBizId
     * @return
     */
    @Override
    public Result<PremiumReconciliation> checkPremiumReconciliationIsExist(String premiumReconciliationBizId) {
        PremiumReconciliation premiumReconciliation = iPremiumReconciliationService.queryOne(premiumReconciliationBizId);
        if (Objects.isNull(premiumReconciliation)) {
            //数据不存在
            throw new BusinessException("保费对账记录信息不存在");
        }
        return Result.success(premiumReconciliation);
    }

}
