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;


    @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();

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

        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();
        List<Commission> commissionList = this.list(new QueryWrapper<Commission>().in("commission_biz_id", commissionBizIdList));
        // 校验来佣记录状态
        for (Commission commission : commissionList) {
            if (StringUtils.equals(commission.getStatus(), CommissionStatusEnum.WAIT.getItemValue())) {
                throw new BusinessException(ResultCode.FAIL.getCode(), "来佣记录为未比对，不能生成出帐");
            }
        }

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

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

        // 校验，如果有"可发放或已发并关账"的发佣记录，不能重复生成
        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(), "该来佣记录已有出帐，不能重复生成");
            }
        }

        // 1.查询所有保单号对应的保单跟进记录
        List<PolicyFollow> policyFollowListList = policyFollowService.list(new QueryWrapper<PolicyFollow>().in("policy_no", policyNoSet));

        // 2.根据保单号查询所有转介人
        List<PolicyBroker> brokerList = policyBrokerService.list(new QueryWrapper<PolicyBroker>().in("policy_no", policyNoSet));
        if (CollUtil.isEmpty(brokerList)) {
            throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "该保单不存在转介人，请先配置转介人");
        }
        // 构建保单号到转介人的映射
        Map<String, List<PolicyBroker>> brokerMap = brokerList.stream().collect(Collectors.groupingBy(PolicyBroker::getPolicyNo));

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

        // 4. 构建发佣记录
        List<Fortune> newFortuneList = new ArrayList<>();
        for (PolicyFollow policyFollow : policyFollowListList) {
            String policyNo = policyFollow.getPolicyNo();

            List<PolicyBroker> policyBrokers = brokerMap.get(policyNo);
            if (CollectionUtils.isNotEmpty(policyBrokers)) {
                for (PolicyBroker policyBroker : policyBrokers) {
                    for (Commission commission : commissionList) {
                        Fortune fortune = new Fortune();
                        fortune.setFortuneBizId(RandomStringGenerator.generateBizId16(CommonEnum.UID_TYPE_FORTUNE.getCode()));
                        fortune.setPolicyNo(policyNo);
                        fortune.setBroker(policyBroker.getBrokerName());
                        fortune.setStatus(FortuneStatusEnum.WAIT.getItemValue());

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

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

    @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);
        // 计算待入账金额
        commissionStatistics.setPendingPaidAmount(commissionStatistics.getTotalAmount().subtract(commissionStatistics.getTotalPaidAmount()));
        // 计算已入账比例
        BigDecimal divided = commissionStatistics.getTotalPaidAmount().divide(commissionStatistics.getTotalAmount(), 4, RoundingMode.HALF_UP);
        // 格式化 %
        commissionStatistics.setPaidAmountRatio(String.format("%.2f%%", divided.doubleValue() * 100));

        return commissionStatistics;
    }
}




