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

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
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.common.enums.ResultCode;
import com.yd.common.exception.BusinessException;
import com.yd.common.result.Result;
import com.yd.csf.feign.request.expectedfortune.ApiExpectedFortunePageRequest;
import com.yd.csf.feign.response.expectedfortune.ApiExpectedFortunePageResponse;
import com.yd.csf.service.dto.UserGradeDto;
import com.yd.csf.service.enums.FortuneTypeEnum;
import com.yd.csf.service.model.ExpectedFortune;
import com.yd.csf.service.dao.ExpectedFortuneMapper;
import com.yd.csf.service.model.Policy;
import com.yd.csf.service.model.PolicyFollow;
import com.yd.csf.service.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yd.csf.service.vo.ExpectedFortuneStatisticsVO;
import com.yd.csf.service.vo.PayableReportVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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

/**
 * <p>
 * 预计发佣表 服务实现类
 * </p>
 *
 * @author zxm
 * @since 2025-11-17
 */
@Service
@Slf4j
public class ExpectedFortuneServiceImpl extends ServiceImpl<ExpectedFortuneMapper, ExpectedFortune> implements IExpectedFortuneService {

    @Resource
    private PolicyService policyService;

    @Resource
    private PolicyFollowService policyFollowService;

    @Resource
    private IConditionConfigService iConditionConfigService;

    @Autowired
    private IAgentAccumulatedFycService iAgentAccumulatedFycService;

    @Resource
    private ApiExchangeRateFeignClient apiExchangeRateFeignClient;

    @Override
    public IPage<ApiExpectedFortunePageResponse> page(Page<ApiExpectedFortunePageResponse> page,
                                                      ApiExpectedFortunePageRequest request) {
        return baseMapper.page(page, request);
    }

    @Override
    public List<ExpectedFortune> listByPolicyBizId(String policyBizId) {
        return baseMapper.listByPolicyBizId(policyBizId);
    }

    /**
     * 查询列表
     *
     * @param policyNo
     * @return
     */
    @Override
    public List<ExpectedFortune> queryList(String policyNo) {
        return baseMapper.selectList(new LambdaQueryWrapper<ExpectedFortune>().eq(ExpectedFortune::getPolicyNo, policyNo));
    }

    @Override
    public Boolean batchDelByPolicyNo(String policyNo) {
        return this.remove(new LambdaQueryWrapper<ExpectedFortune>().eq(ExpectedFortune::getPolicyNo, policyNo));
    }

    @Override
    public ExpectedFortuneStatisticsVO getStatistics(List<Long> expectedFortuneIds) {
        return baseMapper.getStatistics(expectedFortuneIds);
    }

    @Override
    public IPage<ApiExpectedFortunePageResponse> getVOPage(IPage<ApiExpectedFortunePageResponse> iPage) {
        List<ApiExpectedFortunePageResponse> expectedFortuneList = iPage.getRecords();
        Page<ApiExpectedFortunePageResponse> expectedFortuneVOPage = new Page<>(iPage.getCurrent(), iPage.getSize(), iPage.getTotal());
        if (CollUtil.isEmpty(expectedFortuneList)) {
            return expectedFortuneVOPage;
        }

        // 调整数据顺序、格式
        processData(expectedFortuneList);

        // 1. 转介人职级信息
        List<String> brokerBizIds = expectedFortuneList.stream().map(ApiExpectedFortunePageResponse::getBrokerBizId).collect(Collectors.toList());
        Map<String, UserGradeDto> userGradeMap = iAgentAccumulatedFycService.queryUserGradeMap(brokerBizIds);

        // 2. 关联查询新单跟进信息
        Set<String> policyNoList = expectedFortuneList.stream().map(ApiExpectedFortunePageResponse::getPolicyNo).collect(Collectors.toSet());
        Map<String, PolicyFollow> policyFollowMap = policyFollowService.queryPolicyFollowMap(policyNoList);

        for (ApiExpectedFortunePageResponse vo : expectedFortuneList) {

            UserGradeDto userGradeDto = userGradeMap.get(vo.getBrokerBizId());
            if (userGradeDto != null) {
                vo.setBrokerGradeName(userGradeDto.getGradeName());
            }

            PolicyFollow policyFollow = policyFollowMap.get(vo.getPolicyNo());
            if (policyFollow != null) {
                vo.setProductName(policyFollow.getProductName());
            }
        }

        expectedFortuneVOPage.setRecords(expectedFortuneList);

        return expectedFortuneVOPage;
    }

    /**
     * 调整数据顺序   预计在前，实际在后，按预计发佣月排序
     *
     * @param expectedFortuneList 预计发佣列表
     */
    private void processData(List<ApiExpectedFortunePageResponse> expectedFortuneList) {
        if (CollUtil.isEmpty(expectedFortuneList)) {
            return;
        }

        log.info("顺序调整前: {}", expectedFortuneList.size());

        // 1. 分组
        Map<Integer, List<ApiExpectedFortunePageResponse>> groupMap = expectedFortuneList.stream()
                .collect(Collectors.groupingBy(ApiExpectedFortunePageResponse::getType));

        // 2. 获取预计发佣(type=1)和实际发佣(type=2)列表
        List<ApiExpectedFortunePageResponse> expectedList = groupMap.getOrDefault(1, new ArrayList<>());
        List<ApiExpectedFortunePageResponse> actualList = groupMap.getOrDefault(2, new ArrayList<>());

        // 3. 将 actualList 转换为 Map
        Map<String, List<ApiExpectedFortunePageResponse>> actualMap = actualList.stream()
                .filter(item -> "R".equals(item.getFortuneBizType()))
                .collect(Collectors.groupingBy(ApiExpectedFortunePageResponse::getExpectedFortuneBizId));

        // 4. 调整数据顺序
        List<ApiExpectedFortunePageResponse> sortedList = new ArrayList<>();
        Set<String> matchedActualPayableNos = new HashSet<>();

        for (ApiExpectedFortunePageResponse expected : expectedList) {
            sortedList.add(expected);
            // 查找对应的实际发佣
            List<ApiExpectedFortunePageResponse> matchedList = actualMap.get(expected.getExpectedFortuneBizId());
            if (CollUtil.isNotEmpty(matchedList)) {
                // 设置实际出账记录的字段：持有比例、保费、关联人员、累积已发放保单记账金额、累积已发放港币金额、累积已发放比例%、剩余发放比例%、剩余保单记账金额、剩余发放折合港币金额
                matchedList.forEach(actual -> {
                    actual.setBrokerRatio(expected.getBrokerRatio());
                    actual.setPremium(expected.getPremium());
                    actual.setAmountSourceName(expected.getAmountSourceName());

                    actual.setPaidRuleAmount(expected.getPaidRuleAmount());
                    actual.setPaidAmount(expected.getPaidAmount());
                    actual.setPaidRatio(expected.getPaidRatio());
                    actual.setUnpaidRatio(expected.getUnpaidRatio());
                    actual.setUnpaidRuleAmount(expected.getUnpaidRuleAmount());
                    actual.setUnpaidRuleAmounthHkd(expected.getUnpaidRuleAmounthHkd());
                });
                sortedList.addAll(matchedList);

                matchedActualPayableNos.add(expected.getExpectedFortuneBizId());
            }
        }

        // 5. 添加未匹配的实际发佣记录
        for (ApiExpectedFortunePageResponse actual : actualList) {
            if (!matchedActualPayableNos.contains(actual.getExpectedFortuneBizId())) {
                sortedList.add(actual);
            }
        }

        // 6.设置实际出账记录的字段：待出账金额(估)
        for (ApiExpectedFortunePageResponse item : sortedList) {
            if (item.getType() == 2) {
                item.setCurrentPaymentHkdAmount(item.getHkdAmount());
            }
        }
        // 7. 将排序后的结果写回原列表
        expectedFortuneList.clear();
        expectedFortuneList.addAll(sortedList);

        log.info("顺序调整后: {}", sortedList.size());
    }

    @Override
    public List<ApiExpectedFortunePageResponse> toVOList(List<ExpectedFortune> expectedFortuneList) {
        if (CollUtil.isEmpty(expectedFortuneList)) {
            return Collections.emptyList();
        }

        // 收集所有 brokerBizId
        List<String> brokerBizIds = expectedFortuneList.stream()
                .map(ExpectedFortune::getBrokerBizId)
                .filter(Objects::nonNull)
                .distinct()
                .collect(Collectors.toList());

        Map<String, String> brokerRatioMap = new HashMap<>();
        List<UserGradeDto> userGradeDtoList = new ArrayList<>();
        if (CollUtil.isNotEmpty(brokerBizIds)) {
            List<Map<String, Object>> ratioList = iConditionConfigService.selectBrokerRatioByBizIds(brokerBizIds);
            brokerRatioMap = ratioList.stream()
                    .filter(map -> map.get("conditional_value") != null)
                    .collect(Collectors.toMap(
                            map -> (String) map.get("brokerBizId"),
                            map -> (String) map.get("conditional_value"),
                            (v1, v2) -> v1
                    ));
            userGradeDtoList = iAgentAccumulatedFycService.queryUserGradeList(brokerBizIds);
        }
        Map<String, UserGradeDto> userGradeMap = userGradeDtoList.stream()
                .collect(Collectors.toMap(UserGradeDto::getClientUserBizId, Function.identity()));

        List<String> policyNos = expectedFortuneList.stream()
                .map(ExpectedFortune::getPolicyNo)
                .collect(Collectors.toList());
        List<Policy> policyList = policyService.lambdaQuery()
                .in(Policy::getPolicyNo, policyNos).list();
        List<PolicyFollow> policyFollowList = policyFollowService.lambdaQuery()
                .in(PolicyFollow::getPolicyNo, policyNos).list();

        Map<String, Policy> policyMap = policyList.stream()
                .collect(Collectors.toMap(Policy::getPolicyNo, Function.identity()));
        Map<String, PolicyFollow> policyFollowMap = policyFollowList.stream()
                .collect(Collectors.toMap(PolicyFollow::getPolicyNo, Function.identity()));

        // 组装 VO
        Map<String, String> finalBrokerRatioMap = brokerRatioMap;
        List<ApiExpectedFortunePageResponse> voList = expectedFortuneList.stream().map(ef -> {
            ApiExpectedFortunePageResponse vo = new ApiExpectedFortunePageResponse();
            BeanUtils.copyProperties(ef, vo);

            String ratio = finalBrokerRatioMap.get(ef.getBrokerBizId());
            vo.setCommissionRatio(ratio);

            Policy policy = policyMap.get(ef.getPolicyNo());
            PolicyFollow follow = policyFollowMap.get(ef.getPolicyNo());
            UserGradeDto userGradeDto = userGradeMap.get(ef.getBrokerBizId());
            if (userGradeDto != null) {
                vo.setBrokerGradeName(userGradeDto.getGradeName());
            }
            if (policy != null) {
                vo.setPremium(policy.getPaymentPremium());
            }
            if (follow != null) {
                vo.setProductName(follow.getProductName());
                vo.setProductLaunchBizId(follow.getProductLaunchBizId());
            }
            return vo;
        }).collect(Collectors.toList());

        return voList;
    }

    @Override
    public IPage<PayableReportVO> payableReportPage(Page<PayableReportVO> page, QueryWrapper<ExpectedFortune> queryWrapper) {
        return baseMapper.payableReportPage(page, queryWrapper);
    }

    @Override
    public void updateBatchByBizId(List<String> expectedFortuneBizIdList, String status) {
        baseMapper.updateBatchByBizId(expectedFortuneBizIdList, status);
    }

    @Override
    public ExpectedFortune getByBizId(String expectedFortuneBizId) {
        return this.getOne(new QueryWrapper<ExpectedFortune>().eq("expected_fortune_biz_id", expectedFortuneBizId));
    }

    @Override
    public Integer getPayableNoCurrentSeq() {

        ExpectedFortune latest = this.getOne(
                new QueryWrapper<ExpectedFortune>()
                        .isNotNull("payable_no")
                        .eq("is_part", 0)
                        .orderByDesc("id")
                        .last("LIMIT 1"),
                true
        );
        //获取当前序号作为起点
        int currentSeq = 0;
        if (!Objects.isNull(latest)) {
            String payableNo = latest.getPayableNo();
            currentSeq = Integer.parseInt(payableNo.substring(payableNo.length() - 6));
        }

        return currentSeq;
    }

    @Override
    public String getPayableNo(String fortuneType, String policyNo, long expectedFortuneId) {
        // 1. 安全获取保单号后6位
        String last6Chars = "";
        if (policyNo != null && !policyNo.isEmpty()) {
            int startIdx = Math.max(0, policyNo.length() - 6);
            last6Chars = policyNo.substring(startIdx);
        }

        // 2. 字符串左补0至6位
        // %6s 表示最小宽度为6，不足部分默认用空格填充在左侧
        // replace(' ', '0') 将填充的空格替换为0，实现左补0效果
        String formattedPolicySuffix = String.format("%6s", last6Chars).replace(' ', '0');

        // 3. 项目类型枚举转换为字符串
        String fortuneTypeCode = FortuneTypeEnum.getByItemValue(fortuneType).getItemLabel();

        // 4. 组装最终字符串
        return String.format("%s-%s-%d",
                fortuneTypeCode,
                formattedPolicySuffix,
                expectedFortuneId);
    }

    @Override
    public IPage<ApiExpectedFortunePageResponse> queryListNew(Integer pageNo, Integer pageSize, QueryWrapper<ExpectedFortune> queryWrapper) {
        // 1. 查询列表数据（手动分页）
        List<ApiExpectedFortunePageResponse> records = this.baseMapper.queryListNew(pageNo, pageSize, queryWrapper);

        // 2. 查询总记录数
        Long total = this.baseMapper.queryListNewCount(queryWrapper);
        if (total == null) {
            total = 0L;
        }

        // 3. 手动构建分页对象
        Page<ApiExpectedFortunePageResponse> page = new Page<>(pageNo, pageSize, total);
        page.setRecords(records);

        return page;
    }

    @Override
    public ExpectedFortuneStatisticsVO queryListStatistics(QueryWrapper<ExpectedFortune> queryWrapper) {
        ExpectedFortuneStatisticsVO statistics = this.baseMapper.queryListStatistics(queryWrapper);

        if (statistics == null) {
            return new ExpectedFortuneStatisticsVO();
        }

        return statistics;
    }

    @Override
    public List<ApiExpectedFortunePageResponse> queryListAll(QueryWrapper<ExpectedFortune> queryWrapper) {
        // 1. 查询全量数据
        List<ApiExpectedFortunePageResponse> records = this.baseMapper.queryListAll(queryWrapper);
        if (CollUtil.isEmpty(records)) {
            return Collections.emptyList();
        }

        // 2. 调整数据顺序、格式（与 /list 一致）
        processData(records);

        // 3. 补充转介人职级信息
        List<String> brokerBizIds = records.stream().map(ApiExpectedFortunePageResponse::getBrokerBizId).collect(Collectors.toList());
        Map<String, UserGradeDto> userGradeMap = iAgentAccumulatedFycService.queryUserGradeMap(brokerBizIds);

        // 4. 补充产品计划信息
        Set<String> policyNoList = records.stream().map(ApiExpectedFortunePageResponse::getPolicyNo).collect(Collectors.toSet());
        Map<String, PolicyFollow> policyFollowMap = policyFollowService.queryPolicyFollowMap(policyNoList);

        // 5. 补充关联人员信息

        for (ApiExpectedFortunePageResponse vo : records) {
            UserGradeDto userGradeDto = userGradeMap.get(vo.getBrokerBizId());
            if (userGradeDto != null) {
                vo.setBrokerGradeName(userGradeDto.getGradeName());
            }
            PolicyFollow policyFollow = policyFollowMap.get(vo.getPolicyNo());
            if (policyFollow != null) {
                vo.setProductName(policyFollow.getProductName());
            }
        }

        return records;
    }

    /**
     * 查询币对的默认汇率
     *
     * @param sourceCurrency   源币种
     * @param targetCurrency   目标币种
     * @return 汇率
     */
    @Override
    public BigDecimal queryExchangeRateByFeign(String sourceCurrency, String targetCurrency) {
        if (sourceCurrency.equalsIgnoreCase(targetCurrency)) {
            return BigDecimal.ONE;
        }
        // 调用Feign客户端查询汇率
        Result<BigDecimal> result = apiExchangeRateFeignClient.getExchangeRate(sourceCurrency, targetCurrency, "");
        if (result != null && result.getData() != null) {
            return result.getData();
        } else {
            throw new BusinessException(ResultCode.PARAMS_ERROR.getCode(), "查询币对的默认汇率失败, 币种：" + sourceCurrency + " -> " + targetCurrency);
        }
    }
}
