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.Commission;
import com.yd.csf.service.model.ExpectedFortune;
import com.yd.csf.service.model.Fortune;
import com.yd.csf.service.service.CommissionService;
import com.yd.csf.service.service.FortuneAccountService;
import com.yd.csf.service.service.FortuneService;
import com.yd.csf.service.dao.FortuneMapper;
import com.yd.csf.service.service.IExpectedFortuneService;
import com.yd.csf.service.vo.CommissionVO;
import com.yd.csf.service.vo.FortuneVO;
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 javax.servlet.ServletOutputStream;
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 IExpectedFortuneService expectedFortuneService;

    @Override
    public Wrapper<Fortune> getQueryWrapper(FortuneQueryRequest fortuneQueryRequest) {
        QueryWrapper<Fortune> queryWrapper = new QueryWrapper<>();
        if (fortuneQueryRequest == null) {
            return queryWrapper;
        }
        String status = fortuneQueryRequest.getStatus();
        String policyNo = fortuneQueryRequest.getPolicyNo();
        queryWrapper.eq(StringUtils.isNotBlank(status), "status", status);
        queryWrapper.eq(StringUtils.isNotBlank(policyNo), "policy_no", policyNo);

        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 = fortuneList.stream().map(FortuneVO::objToVo).collect(Collectors.toList());
        // 关联查询已来佣金额
        List<Commission> commissionList = commissionService.list(new QueryWrapper<Commission>().in("commission_biz_id", fortuneList.stream().map(Fortune::getCommissionBizId).collect(Collectors.toList())));
        Map<String, Commission> commissionMap = commissionList.stream().collect(Collectors.toMap(Commission::getCommissionBizId, commission -> commission));
        fortuneVOList.forEach(fortuneVO -> {
            String commissionBizId = fortuneVO.getCommissionBizId();
//            fortuneVO.setCommissionAmount(commissionAmountMap.getOrDefault(commissionBizId, BigDecimal.ZERO));
            fortuneVO.setCommission(CommissionVO.objToVo(commissionMap.get(commissionBizId)));
        });

        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）
        if (fortuneUpdateRequest.getAmount().compareTo(expectedFortune.getAmount()) < 0) {
            Fortune newFortune = new Fortune();
            BeanUtils.copyProperties(fortune, newFortune);
            newFortune.setAmount(expectedFortune.getAmount().subtract(fortuneUpdateRequest.getAmount()));
            newFortune.setStatus(FortuneStatusEnum.WAIT.getItemValue());
            newFortune.setFortuneBizId(RandomStringGenerator.generateBizId16(CommonEnum.UID_TYPE_FORTUNE.getCode()));
            newFortune.setExpectedFortuneBizId(expectedFortune.getExpectedFortuneBizId());
            newFortune.setIsPart(1);
            // 出账年月为次月
            newFortune.setReconciliationYearMonth(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 String calculateReconciliationYearMonth(Fortune fortune) {
        // 出账年月为次月
        LocalDate reconciliationDate = LocalDate.parse(fortune.getReconciliationYearMonth() + "-01").plusMonths(1);
        return reconciliationDate.format(DateTimeFormatter.ofPattern("yyyy-MM"));
    }

    @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.setTotalOutAmount(BigDecimal.ZERO);
            fortuneStatisticsVO.setTotalInAmount(BigDecimal.ZERO);
            fortuneStatisticsVO.setTotalPolicyCount(0L);
            return fortuneStatisticsVO;
        }
        // 自定义查询
        return this.baseMapper.getFortuneStatistics(fortuneIdList);
    }

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

}




