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

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
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.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.utils.RandomStringGenerator;
import com.yd.csf.service.dto.*;
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.FortuneMapper;
import com.yd.csf.service.vo.FortuneVO;
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.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author Zhang Jianan
 * @description 针对表【fortune(保单发佣表)】的数据库操作Service实现
 * @createDate 2025-09-22 13:22:08
 */
@Service
public class FortuneServiceImpl extends ServiceImpl<FortuneMapper, Fortune>
        implements FortuneService {

    @Resource
    private FortuneAccountService fortuneAccountService;
    @Resource
    private CommissionService commissionService;
    @Resource
    private CommissionExpectedService commissionExpectedService;
    @Resource
    private IExpectedFortuneService expectedFortuneService;
    @Resource
    private PolicyService policyService;


    @Override
    public Wrapper<Fortune> getQueryWrapper(FortuneQueryRequest fortuneQueryRequest) {
        QueryWrapper<Fortune> queryWrapper = new QueryWrapper<>();
        if (fortuneQueryRequest == null) {
            return queryWrapper;
        }
        String reconciliationYearMonth = fortuneQueryRequest.getReconciliationYearMonth();
        List<String> statusList = fortuneQueryRequest.getStatusList();
        String policyNo = fortuneQueryRequest.getPolicyNo();
        List<String> insuranceCompanyBizIdList = fortuneQueryRequest.getInsuranceCompanyBizIdList();
        List<String> productLaunchBizIdList = fortuneQueryRequest.getProductLaunchBizIdList();
        LocalDate payoutDateStart = fortuneQueryRequest.getPayoutDateStart();
        LocalDate payoutDateEnd = fortuneQueryRequest.getPayoutDateEnd();

        queryWrapper.eq(StringUtils.isNotBlank(reconciliationYearMonth), "reconciliation_year_month", reconciliationYearMonth);
        queryWrapper.in(CollUtil.isNotEmpty(statusList), "status", statusList);
        queryWrapper.eq(StringUtils.isNotBlank(policyNo), "policy_no", policyNo);
        queryWrapper.in(CollUtil.isNotEmpty(insuranceCompanyBizIdList), "insurance_company_biz_id", insuranceCompanyBizIdList);
        queryWrapper.in(CollUtil.isNotEmpty(productLaunchBizIdList), "product_launch_biz_id", productLaunchBizIdList);

        queryWrapper.gt(ObjectUtils.isNotEmpty(payoutDateStart), "payout_date", payoutDateStart);
        queryWrapper.lt(ObjectUtils.isNotEmpty(payoutDateEnd), "payout_date", payoutDateEnd);

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

    @Override
    public Page<FortuneVO> getFortuneVOPage(Page<Fortune> fortunePage) {
        List<Fortune> fortuneList = fortunePage.getRecords();
        Page<FortuneVO> fortuneVOPage = new Page<>(fortunePage.getCurrent(), fortunePage.getSize(), fortunePage.getTotal());
        if (CollUtil.isEmpty(fortuneList)) {
            return fortuneVOPage;
        }

        List<FortuneVO> fortuneVOList = new ArrayList<>();
        Set<String> expectedFortuneBizIdSet = new HashSet<>();
        Set<String> commissionBizIdSet = new HashSet<>();
        Set<String> policyNoSet = new HashSet<>();
        for (Fortune fortune : fortuneList) {
            FortuneVO fortuneVO = FortuneVO.objToVo(fortune);
            fortuneVOList.add(fortuneVO);
            expectedFortuneBizIdSet.add(fortune.getExpectedFortuneBizId());
            commissionBizIdSet.add(fortune.getCommissionBizId());
            policyNoSet.add(fortune.getPolicyNo());
        }
        // 1.关联查询来佣信息
        List<Commission> commissionList = commissionService.list(new QueryWrapper<Commission>().in("commission_biz_id", commissionBizIdSet));
        // 1.1 关联查询来佣预期信息
        List<CommissionExpected> commissionExpectedList = commissionExpectedService.lambdaQuery()
                .in(CommissionExpected::getCommissionExpectedBizId, expectedFortuneBizIdSet)
                .select(CommissionExpected::getCommissionExpectedBizId, CommissionExpected::getPaidAmount, CommissionExpected::getPaidRatio)
                .list();
        Map<String, CommissionExpected> commissionExpectedMap = commissionExpectedList.stream().collect(Collectors.toMap(CommissionExpected::getCommissionExpectedBizId, a -> a, (oldValue, newValue) -> newValue));

        // 2.关联查询保单信息
        QueryWrapper<Policy> queryWrapper = new QueryWrapper<Policy>();
        queryWrapper.select("policy_no", "payment_premium", "product_name", "insurance_company", "reconciliation_company");
        queryWrapper.in("policy_no", policyNoSet);
        List<Policy> policyList = policyService.list(queryWrapper);
        Map<String, Policy> policyMap = policyList.stream().collect(Collectors.toMap(Policy::getPolicyNo, a -> a, (oldValue, newValue) -> newValue));

        // 3.关联查询预计出账信息
        List<ExpectedFortune> expectedFortuneList = expectedFortuneService.list(new QueryWrapper<ExpectedFortune>().in("expected_fortune_biz_id", expectedFortuneBizIdSet));
        Map<String, ExpectedFortune> expectedFortuneMap = expectedFortuneList.stream().collect(Collectors.toMap(ExpectedFortune::getExpectedFortuneBizId, a -> a, (oldValue, newValue) -> newValue));

        fortuneVOList.forEach(fortuneVO -> {
            String commissionBizId = fortuneVO.getCommissionBizId();
            // 设置来佣金额和比例
            CommissionExpected commissionExpected = commissionExpectedMap.get(commissionBizId);
            if (commissionExpected != null) {
                fortuneVO.setCommissionPaidAmount(commissionExpected.getPaidAmount());
                fortuneVO.setCommissionPaidRatio(commissionExpected.getPaidRatio());
            }
            // 设置保单信息
            Policy policy = policyMap.get(fortuneVO.getPolicyNo());
            if (policy != null) {
                fortuneVO.setPremium(policy.getPaymentPremium());
                fortuneVO.setInsuranceCompany(policy.getInsuranceCompany());
            }
            // 设置预计出账信息
            ExpectedFortune expectedFortune = expectedFortuneMap.get(fortuneVO.getExpectedFortuneBizId());
            if (expectedFortune != null) {
                FortuneVO.calculateByExpectedFortune(fortuneVO, expectedFortune);
            }
        });

        fortuneVOPage.setRecords(fortuneVOList);
        return fortuneVOPage;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateFortune(FortuneUpdateRequest fortuneUpdateRequest) {
        if (fortuneUpdateRequest.getStatus() == null) {
            throw new BusinessException(ResultCode.PARAM_CHECK_ERROR.getCode(), "出账状态不能为空");
        }
        if (!StringUtils.equalsAny(fortuneUpdateRequest.getStatus(), FortuneStatusEnum.RESERVED.getItemValue(), FortuneStatusEnum.INVALID.getItemValue(), FortuneStatusEnum.CHECKED.getItemValue(), FortuneStatusEnum.CHECKED.getItemValue())) {
            throw new BusinessException(ResultCode.PARAM_CHECK_ERROR.getCode(), "出账状态只能为保留、已失效、可出帐，检核完成");
        }

        String fortuneBizId = fortuneUpdateRequest.getFortuneBizId();
        // 查询出账数据
        Fortune fortune = this.getOne(new QueryWrapper<Fortune>().eq("fortune_biz_id", fortuneBizId));
        if (fortune == null) {
            throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "发佣数据不存在");
        }
        // 查询预计出账数据
        ExpectedFortune expectedFortune = expectedFortuneService.getOne(new QueryWrapper<ExpectedFortune>().eq("expected_fortune_biz_id", fortune.getExpectedFortuneBizId()));
        if (expectedFortune == null) {
            throw new BusinessException(ResultCode.NULL_ERROR.getCode(), "预计出账数据不存在");
        }

        // 如果是部分出账，新增一条待出账的实际出账记录（fortune）
        BigDecimal currentPaymentAmount = fortuneUpdateRequest.getCurrentPaymentAmount();
        if (currentPaymentAmount != null && currentPaymentAmount.compareTo(BigDecimal.ZERO) > 0 && currentPaymentAmount.compareTo(expectedFortune.getAmount()) < 0) {
            Fortune newFortune = new Fortune();
            BeanUtils.copyProperties(fortune, newFortune, "id", "fortuneBizId");
            newFortune.setAmount(expectedFortune.getAmount());
            newFortune.setCurrentPaymentAmount(expectedFortune.getAmount().subtract(currentPaymentAmount));
            newFortune.setStatus(FortuneStatusEnum.WAIT.getItemValue());
            newFortune.setFortuneBizId(RandomStringGenerator.generateBizId16(CommonEnum.UID_TYPE_FORTUNE.getCode()));
            newFortune.setExpectedFortuneBizId(expectedFortune.getExpectedFortuneBizId());
            newFortune.setIsPart(1);
            // 设置预计出账日期为次月
            newFortune.setPayoutDate(calculateReconciliationYearMonth(fortune));
            this.save(newFortune);
        }

        BeanUtils.copyProperties(fortuneUpdateRequest, fortune, "id", "fortuneBizId", "expectedFortuneBizId", "commissionBizId");

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

        // 更新预计出账状态
        expectedFortune.setStatus(fortuneUpdateRequest.getStatus());
        expectedFortuneService.updateById(expectedFortune);

        // 更新实际出账数据
        fortune.setUpdaterId(loginUserId);
        fortune.setUpdateTime(new Date());

        return this.updateById(fortune);
    }

    private LocalDate calculateReconciliationYearMonth(Fortune fortune) {
        // 设置预计出账日期为次月
        return LocalDate.now().plusMonths(1);
    }

    @Override
    public void downloadFortune(FortuneDownloadRequest fortuneDownloadRequest, HttpServletResponse response) throws IOException {
        List<String> fortuneBizIdList = fortuneDownloadRequest.getFortuneBizIdList();
        if (CollUtil.isNotEmpty(fortuneBizIdList)) {
            List<Fortune> fortuneList = this.list(new QueryWrapper<Fortune>().in("fortune_biz_id", fortuneBizIdList));
            if (CollUtil.isNotEmpty(fortuneList)) {
                // 转换为导出DTO
                List<FortuneExportDTO> exportDTOList = fortuneList.stream().map(fortune -> {
                    FortuneExportDTO exportDTO = new FortuneExportDTO();
                    BeanUtils.copyProperties(fortune, exportDTO);
                    return exportDTO;
                }).collect(Collectors.toList());

                // 设置响应头
                response.setContentType("application/vnd.ms-excel;charset=UTF-8");
                response.setCharacterEncoding("utf-8");
                String encode = URLEncoder.encode("保单发佣.xlsx", "UTF-8");
                response.setHeader("Content-Disposition", "attachment;filename=" + "fortune_"+System.currentTimeMillis() + ".xlsx");

                // 导出
                try {
                    EasyExcel.write(response.getOutputStream(), FortuneExportDTO.class).sheet("发佣").doWrite(exportDTOList);
                } catch (IOException e) {
                    log.error("导出保单发佣数据失败", e);
                    throw new BusinessException(ResultCode.FAIL.getCode(), "导出失败");
                }
            }
        }
    }

    @Override
    public void downloadAccount(FortuneDownloadRequest fortuneDownloadRequest, HttpServletResponse response) throws UnsupportedEncodingException {
        List<String> fortuneBizIdList = fortuneDownloadRequest.getFortuneBizIdList();
        if (CollUtil.isNotEmpty(fortuneBizIdList)) {
            List<Fortune> fortuneList = this.list(new QueryWrapper<Fortune>().in("fortune_biz_id", fortuneBizIdList));
            // 校验发佣记录状态
            StringBuilder validateMsg = new StringBuilder();
            for (Fortune fortune : fortuneList) {
                if (!StringUtils.equals(fortune.getStatus(), FortuneStatusEnum.CHECKED.getItemValue())) {
                    validateMsg.append(fortune.getPolicyNo()).append("-").append(fortune.getBroker()).append("未检核，不能生成出账记录; ");
                }
            }
            if (StringUtils.isNotBlank(validateMsg.toString())) {
                throw new BusinessException(ResultCode.FAIL.getCode(), validateMsg.toString());
            }

            if (CollUtil.isNotEmpty(fortuneList)) {
                // 按人和币种分组
                Map<String, List<Fortune>> fortuneMap = fortuneList.stream().collect(Collectors.groupingBy(fortune -> fortune.getBroker() + "_" + fortune.getCurrency()));

                // 创建按人分组的导出DTO列表
                List<FortuneAccountExportDTO> accountExportDTOList = new ArrayList<>();

                // 收集所有不同的fortune项目名称
                Set<String> allFortuneNames = fortuneList.stream()
                        .map(Fortune::getFortuneName)
                        .filter(StringUtils::isNotBlank)
                        .collect(Collectors.toSet());

                // 处理每个分组的数据
                for (Map.Entry<String, List<Fortune>> entry : fortuneMap.entrySet()) {
                    String broker = entry.getKey().split("_")[0];
                    String currency = entry.getKey().split("_")[1];
                    List<Fortune> brokerFortunes = entry.getValue();

                    FortuneAccountExportDTO accountDTO = new FortuneAccountExportDTO();
                    accountDTO.setBroker(broker);
                    accountDTO.setFortuneList(brokerFortunes);

                    // 设置团队、币种（取第一个记录）
                    if (CollUtil.isNotEmpty(brokerFortunes)) {
                        accountDTO.setTeam(brokerFortunes.get(0).getTeam());
                        accountDTO.setCurrency(currency);
                    }

                    // 计算出账总额
                    BigDecimal totalAmount = brokerFortunes.stream()
                            .map(Fortune::getAmount)
                            .reduce(BigDecimal.ZERO, BigDecimal::add);
                    accountDTO.setAmount(totalAmount);

                    // 按fortune项目分组并累加金额
                    Map<String, BigDecimal> fortuneAmountMap = brokerFortunes.stream()
                            .collect(Collectors.groupingBy(
                                    Fortune::getFortuneName,
                                    Collectors.reducing(BigDecimal.ZERO, Fortune::getAmount, BigDecimal::add)
                            ));

                    // 设置各个fortune项目的金额
                    fortuneAmountMap.forEach(accountDTO::addFortuneAmount);

                    accountExportDTOList.add(accountDTO);
                }

//                // 设置响应头
//                response.setContentType("application/vnd.ms-excel;charset=UTF-8");
//                response.setCharacterEncoding("utf-8");
//                String fileName = "fortune_account_" + System.currentTimeMillis() + ".xlsx";
//                response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
//
//                // 创建动态表头
//                List<List<String>> head = new ArrayList<>();
//                head.add(Collections.singletonList("转介人"));
//                head.add(Collections.singletonList("所属团队"));
//                head.add(Collections.singletonList("出账币种"));
//                head.add(Collections.singletonList("出账总额"));
//
//                // 添加所有fortune项目作为表头
//                for (String fortuneName : allFortuneNames) {
//                    head.add(Collections.singletonList(fortuneName + "金额"));
//                }
//
//                // 构建数据行
//                List<List<Object>> dataList = new ArrayList<>();
//                for (FortuneAccountExportDTO dto : accountExportDTOList) {
//                    List<Object> row = new ArrayList<>();
//                    row.add(dto.getBroker());
//                    row.add(dto.getTeam());
//                    row.add(dto.getCurrency());
//                    row.add(dto.getAmount());
//                    for (String fortuneName : allFortuneNames) {
//                        row.add(dto.getFortuneAmount(fortuneName));
//                    }
//                    dataList.add(row);
//                }

                // 写入数据库
                fortuneAccountService.saveFortuneAccount(accountExportDTOList);

//                // 使用try-with-resources确保流正确关闭
//                try (ServletOutputStream outputStream = response.getOutputStream()) {
//                    // 写入 Excel
//                    EasyExcel.write(outputStream)
//                            .head(head)
//                            .sheet("出账清单")
//                            .doWrite(dataList);
//
//                    outputStream.flush();
//                } catch (Exception e) {
//                    log.error("导出失败", e);
//                    throw new BusinessException(ResultCode.FAIL.getCode(), "导出失败");
//                }
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateFortuneStatus(FortuneStatusUpdateRequest fortuneStatusUpdateRequest) {

        List<String> fortuneBizIdList = fortuneStatusUpdateRequest.getFortuneBizIdList();
        List<Fortune> fortuneList = this.list(new QueryWrapper<Fortune>().in("fortune_biz_id", fortuneBizIdList));

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

        Date now = new Date();
        List<Fortune> updateList = new ArrayList<>();
        for (Fortune fortune : fortuneList) {
            Fortune updateFortune = new Fortune();
            updateFortune.setId(fortune.getId());
            updateFortune.setUpdaterId(loginUserId);
            updateFortune.setUpdateTime(now);
            updateFortune.setStatus(fortuneStatusUpdateRequest.getStatus());
            updateList.add(updateFortune);
        }

        return this.updateBatchById(updateList);
    }

    @Override
    public Fortune getByFortuneBizId(String fortuneBizId) {
        return this.getOne(new QueryWrapper<Fortune>().eq("fortune_biz_id", fortuneBizId));
    }

    @Override
    public Boolean addFortune(FortuneAddRequest fortuneAddRequest) {
        Fortune fortune = new Fortune();
        BeanUtil.copyProperties(fortuneAddRequest, fortune);
        // 生成发佣业务ID
        fortune.setFortuneBizId(RandomStringGenerator.generateBizId16(CommonEnum.UID_TYPE_FORTUNE.getCode()));
        fortune.setStatus(FortuneStatusEnum.WAIT.getItemValue());

        return this.save(fortune);
    }

    /**
     * 查询单个对象
     * @param fortuneBizId
     * @return
     */
    @Override
    public Fortune queryOne(String fortuneBizId) {
        return this.getOne(new LambdaQueryWrapper<Fortune>().eq(Fortune::getFortuneBizId,fortuneBizId));
    }

    @Override
    public FortuneStatisticsVO getFortuneStatistics(List<Long> fortuneIdList) {
        if (CollectionUtils.isEmpty(fortuneIdList)) {
            FortuneStatisticsVO fortuneStatisticsVO = new FortuneStatisticsVO();
            fortuneStatisticsVO.setTotalInAmount(BigDecimal.ZERO);
            fortuneStatisticsVO.setTotalPolicyCount(0L);
            fortuneStatisticsVO.setTotalPremium(BigDecimal.ZERO);
            fortuneStatisticsVO.setPendingOutAmount(BigDecimal.ZERO);
            fortuneStatisticsVO.setAvailableOutAmount(BigDecimal.ZERO);
            fortuneStatisticsVO.setDifferenceAmount(BigDecimal.ZERO);
            return fortuneStatisticsVO;
        }
        // 自定义查询
        FortuneStatisticsVO fortuneStatistics = this.baseMapper.getFortuneStatistics(fortuneIdList);
        // 计算差额
        fortuneStatistics.setDifferenceAmount(fortuneStatistics.getPendingOutAmount().subtract(fortuneStatistics.getAvailableOutAmount()));
        return fortuneStatistics;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean addFortuneBatch(List<FortuneAddRequest> fortuneAddRequestList) {
        if (CollectionUtils.isEmpty(fortuneAddRequestList)) {
            return false;
        }

        List<Fortune> fortuneList = new ArrayList<>();
        for (FortuneAddRequest fortuneAddRequest : fortuneAddRequestList) {
            Fortune fortune = new Fortune();
            BeanUtil.copyProperties(fortuneAddRequest, fortune);
            // 生成发佣业务ID
            fortune.setFortuneBizId(RandomStringGenerator.generateBizId16(CommonEnum.UID_TYPE_FORTUNE.getCode()));
            fortune.setStatus(FortuneStatusEnum.WAIT.getItemValue());
            fortuneList.add(fortune);
        }
        return this.saveBatch(fortuneList);
    }

}




