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

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

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.NumberFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author Zhang Jianan
 * @description 针对表【commission(保单来佣表)】的数据库操作Service实现
 * @createDate 2025-09-19 16:08:05
 */
@Service
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;


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

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

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

        if (commissionDateStart != null && commissionDateEnd != null) {
            queryWrapper.between("commission_date", commissionDateStart, commissionDateEnd);
        }
        // 查询预计入账日期及之前的记录
        if (expectedDate != null) {
            queryWrapper.lt("expected_date", expectedDate);
        }

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

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

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

        commissionVOPage.setRecords(commissionVOList);
        return commissionVOPage;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateCommission(CommissionUpdateRequest commissionUpdateRequest) {
        String commissionBizId = commissionUpdateRequest.getCommissionBizId();
        Commission commission = this.getOne(new QueryWrapper<Commission>().eq("commission_biz_id", commissionBizId));
        if (commission == null) {
            throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "未找到该来佣记录");
        }
        BeanUtils.copyProperties(commissionUpdateRequest, commission, "id", "commissionBizId");
        // 查询预计来佣
        CommissionExpected commissionExpected = queryByCommission(commission);
        if (commissionExpected != null) {
            // 对比预计来佣
            compareWithExpected(commission, commissionExpected);
            commissionExpectedService.updateById(commissionExpected);
        } else {
            // 预计来佣不存在，来佣状态设置为 比对失败
            commission.setStatus(CommissionStatusEnum.COMPARE_FAIL.getItemValue());
            commission.setRemark("未找到当前来佣对应的预计来佣，比对失败");
        }

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

        return this.updateById(commission);
    }

    private CommissionExpected queryByCommission(Commission commission) {
        QueryWrapper<CommissionExpected> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("policy_no", commission.getPolicyNo());
        queryWrapper.eq("commission_name", commission.getCommissionName());
        queryWrapper.eq("commission_period", commission.getCommissionPeriod());
        queryWrapper.eq("currency", commission.getCurrency());
        return commissionExpectedService.getOne(queryWrapper);
    }

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

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

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

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

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

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

        // 5. 筛出来佣对应的预计发佣记录
        List<ExpectedFortune> filteredExpectedFortuneList = expectedFortuneList.stream()
                .filter(expectedFortune -> commissionList.stream()
                        .anyMatch(commission -> StringUtils.equals(commission.getPolicyNo(), expectedFortune.getPolicyNo())
                                && commission.getCommissionPeriod().equals(expectedFortune.getFortunePeriod())))
                .collect(Collectors.toList());

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

        // 7. 构建实际的初始发佣记录
        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);

            fortune.setCreateTime(new Date());
            fortune.setUpdateTime(new Date());

            newFortuneList.add(fortune);
        }
        // 8. 保存发佣记录
        if (CollUtil.isNotEmpty(newFortuneList)) {
            boolean saveSuccess = fortuneService.saveBatch(newFortuneList);
            if (!saveSuccess) {
                throw new BusinessException(ResultCode.FAIL.getCode(), "保存发佣记录失败");
            }
        }
        return true;
    }

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

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

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

        Commission commission = new Commission();
        BeanUtils.copyProperties(commissionAddRequest, commission);
        // 生成新单编号
        String commissionBizId = RandomStringGenerator.generateBizId16(CommonEnum.UID_TYPE_COMMISSION.getCode());
        commission.setCommissionBizId(commissionBizId);
        // 查询预计来佣
        CommissionExpected commissionExpected = queryByCommission(commission);
        if (commissionExpected != null) {
            // 对比预计来佣
            compareWithExpected(commission, commissionExpected);
            commissionExpectedService.updateById(commissionExpected);
        } else {
            // 预计来佣不存在，来佣状态设置为 比对失败
            commission.setStatus(CommissionStatusEnum.COMPARE_FAIL.getItemValue());
            commission.setRemark("未找到当前来佣对应的预计来佣，比对失败");
        }

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

        return this.save(commission);
    }

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

    @Override
    public void compareWithExpected(Commission commission, CommissionExpected expected) {
        if (expected != null) {
            if (expected.getAmount().compareTo(commission.getAmount()) == 0) {
                // 一致，来佣状态设置为 比对成功
                commission.setStatus(CommissionStatusEnum.COMPARE_SUCCESS.getItemValue());
                // 预计来佣的状态设置为 已来佣
                expected.setStatus(CommissionExpectedStatusEnum.COMPARED.getItemValue());
            } else {
                // 不一致，来佣状态设置为 比对失败
                commission.setStatus(CommissionStatusEnum.COMPARE_FAIL.getItemValue());
                expected.setStatus(CommissionExpectedStatusEnum.PARTIAL.getItemValue());
            }
        }
    }

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

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

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

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

        return commissionStatistics;
    }
}




