package com.yd.csf.api.controller;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
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.common.enums.ResultCode;
import com.yd.common.result.Result;
import com.yd.csf.api.dto.QueryCommissionExpectedByPageNewResponse;
import com.yd.csf.api.dto.QueryCommissionExpectedByPageResponse;
import com.yd.csf.api.dto.ReceivableReportResponse;
import com.yd.csf.api.service.ApiCommissionExpectedService;
import com.yd.csf.service.common.ErrorCode;
import com.yd.csf.service.dto.*;
import com.yd.csf.service.model.CommissionExpected;
import com.yd.csf.service.model.Policy;
import com.yd.csf.service.model.PolicyFollow;
import com.yd.csf.service.service.CommissionExpectedService;
import com.yd.csf.service.service.PolicyFollowService;
import com.yd.csf.service.service.PolicyService;
import com.yd.csf.service.vo.*;
import com.yd.insurance.base.feign.client.insurancereconciliationcompany.ApiInsuranceReconciliationCompanyFeignClient;
import com.yd.insurance.base.feign.request.insurancereconciliationcompany.ApiInsuranceReconciliationCompanyPageRequest;
import com.yd.insurance.base.feign.response.insurancereconciliationcompany.ApiInsuranceReconciliationCompanyPageResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
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.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * CommissionExpected接口
 *
 * @author jianan
 * @since 2025-08-31
 */
@Slf4j
@RestController
@RequestMapping("/CommissionExpected")
@Tag(name = "预计入账接口")
public class ApiCommissionExpectedController {

    @Resource
    private CommissionExpectedService commissionExpectedService;
    @Resource
    private PolicyService policyService;
    @Resource
    private PolicyFollowService policyFollowService;
    @Resource
    private ApiInsuranceReconciliationCompanyFeignClient companyFeignClient;
    @Autowired
    private ApiCommissionExpectedService apiCommissionExpectedService;

    /**
     * 批量新增预计入账
     *
     * @param commissionExpectedAddRequest
     * @param request
     * @return
     */
    @PostMapping("/add")
    @Operation(summary = "新增预计入账")
    public Result<Boolean> addCommissionExpected(@RequestBody CommissionExpectedAddRequest commissionExpectedAddRequest, HttpServletRequest request) {
        if (commissionExpectedAddRequest == null) {
            return Result.fail(ResultCode.PARAMS_ERROR.getCode(), ResultCode.PARAMS_ERROR.getMessage());
        }
        return Result.success(commissionExpectedService.addCommissionExpected(commissionExpectedAddRequest));
    }

    /**
     * 删除预计入账
     *
     * @param commissionExpectedBizId 预计入账业务id
     * @param request
     * @return
     */
    @DeleteMapping("/delete")
    @Operation(summary = "删除预计入账")
    public Result<Boolean> deleteCommissionExpected(@RequestParam("commissionExpectedBizId") String commissionExpectedBizId, HttpServletRequest request) {
        if (StringUtils.isBlank(commissionExpectedBizId)) {
            return Result.fail(ResultCode.PARAMS_ERROR.getCode(), "预计入账业务id不能为空");
        }
        return Result.success(commissionExpectedService.deleteCommissionExpected(commissionExpectedBizId));
    }

    /**
     * 更新预计入账
     *
     * @param commissionExpectedUpdateRequest
     * @return
     */
    @PostMapping("/update")
    @Operation(summary = "更新预计入账")
    public Result<Boolean> updateCommissionExpected(@RequestBody CommissionExpectedUpdateRequest commissionExpectedUpdateRequest) {
        if (commissionExpectedUpdateRequest == null || StringUtils.isBlank(commissionExpectedUpdateRequest.getCommissionExpectedBizId())) {
            return Result.fail(ResultCode.PARAMS_ERROR.getCode(), "commissionExpectedBizId不能为空");
        }
        return Result.success(commissionExpectedService.updateCommissionExpected(commissionExpectedUpdateRequest));
    }

    /**
     * 预计入账-修改状态
     *
     * @param commissionExpectedChangeStatusRequest
     * @return
     */
    @PostMapping("/change_status")
    @Operation(summary = "预计入账-修改状态")
    public Result<Boolean> changeStatus(@RequestBody CommissionExpectedChangeStatusRequest commissionExpectedChangeStatusRequest) {
        if (commissionExpectedChangeStatusRequest == null || StringUtils.isBlank(commissionExpectedChangeStatusRequest.getCommissionExpectedBizId())) {
            return Result.fail(ResultCode.PARAMS_ERROR.getCode(), "commissionExpectedBizId不能为空");
        }
        return Result.success(commissionExpectedService.changeStatus(commissionExpectedChangeStatusRequest));
    }

    /**
     * 根据 CommissionExpectedBizId 获取CommissionExpected（封装类）
     *
     * @param commissionExpectedBizId 预计入账业务id
     * @return
     */
    @GetMapping("/get/vo")
    @Operation(summary = "预计入账详情")
    public Result<CommissionExpectedVO> getCommissionExpectedVOByBizId(String commissionExpectedBizId, HttpServletRequest request) {
        if (StringUtils.isBlank(commissionExpectedBizId)) {
            return Result.fail(ResultCode.PARAMS_ERROR.getCode(), "commissionExpectedBizId不能为空");
        }
        // 查询数据库
        CommissionExpected CommissionExpected = commissionExpectedService.getByBizId(commissionExpectedBizId);
        if (CommissionExpected == null) {
            return Result.fail(ResultCode.NULL_ERROR.getCode(), ResultCode.NULL_ERROR.getMessage());
        }

        // 获取封装类
        return Result.success(commissionExpectedService.getCommissionExpectedVO(CommissionExpected));
    }

    /**
     * 分页获取CommissionExpected列表（仅管理员可用）
     *
     * @param CommissionExpectedQueryRequest
     * @return
     */
    @PostMapping("/list/page")
    @Operation(summary = "分页获取预计入账列表", description = "可根据 reconciliation_company、commission_name、commission_period、amount 排序，默认按照佣金期数升序排序")
    public Result<Page<CommissionExpectedVO>> listCommissionExpectedByPage(@RequestBody CommissionExpectedQueryRequest CommissionExpectedQueryRequest) {
        // 校验参数
        if (CommissionExpectedQueryRequest == null || CommissionExpectedQueryRequest.getPolicyNo() == null) {
            return Result.fail(ResultCode.PARAMS_ERROR.getCode(), "保单号不能为空");
        }
        long current = CommissionExpectedQueryRequest.getPageNo();
        long size = CommissionExpectedQueryRequest.getPageSize();

        // 查询数据库
        Page<CommissionExpected> CommissionExpectedPage = commissionExpectedService.page(new Page<>(current, size),
                commissionExpectedService.getQueryWrapper(CommissionExpectedQueryRequest));
        return Result.success(commissionExpectedService.getCommissionExpectedVOPage(CommissionExpectedPage));
    }

    /**
     * 计算统计数据 总金额、总入账金额、待入账金额、已入账比例（已入账金额/总金额）、总保单数
     */
    @PostMapping("/statistics")
    @Operation(summary = "计算统计数据 总金额、总入账金额、待入账金额、已入账比例（已入账金额/总金额）、总保单数")
    public Result<CommissionExpectedStatisticsVO> getCommissionStatistics(@RequestBody CommissionExpectedStatisticsRequest commissionExpectedStatisticsRequest) {
        if (commissionExpectedStatisticsRequest == null) {
            return Result.fail(ErrorCode.PARAMS_ERROR.getCode(), ErrorCode.PARAMS_ERROR.getMessage());
        }
        return Result.success(commissionExpectedService.getExpectedStatistics(commissionExpectedStatisticsRequest.getCommissionExpectedIds()));
    }

    /**
     * 应收款管理列表查询（旧）
     *
     * @param commissionExpectedQueryRequest
     * @return
     */
    @PostMapping("/queryCommissionExpectedByPage")
    @Operation(summary = "应收款管理列表查询（旧）")
    public Result<QueryCommissionExpectedByPageResponse> queryCommissionExpectedByPage(@RequestBody CommissionExpectedQueryRequest commissionExpectedQueryRequest) {
        long current = commissionExpectedQueryRequest.getPageNo();
        long size = commissionExpectedQueryRequest.getPageSize();

        // 查询列表数据
        QueryWrapper<CommissionExpected> queryWrapper = commissionExpectedService.getQueryWrapper(commissionExpectedQueryRequest);
        Page<CommissionExpected> commissionExpectedPage = commissionExpectedService.page(new Page<>(current, size),
                queryWrapper);

        // 查询统计数据
        List<CommissionExpected> commissionExpectedList = commissionExpectedService.list(queryWrapper);
        // 计算统计数据
        List<Long> expectedIds = commissionExpectedList.stream().map(CommissionExpected::getId).collect(Collectors.toList());
        CommissionExpectedStatisticsVO expectedStatisticsVO = commissionExpectedService.getExpectedStatistics(expectedIds);
        // 组装返回值
        QueryCommissionExpectedByPageResponse response = new QueryCommissionExpectedByPageResponse();
        response.setExpectedStatisticsVO(expectedStatisticsVO);
        response.setPage(commissionExpectedService.getCommissionExpectedVOPage(commissionExpectedPage));
        return Result.success(response);
    }

    /**
     * 应收款管理列表查询（新）
     *
     * @param commissionExpectedQueryRequest
     * @return
     */
    @PostMapping("/queryCommissionExpectedByPage/new")
    @Operation(summary = "应收款管理列表查询（新）")
    public Result<QueryCommissionExpectedByPageNewResponse> queryCommissionExpectedByPageNew(
            @RequestBody CommissionExpectedQueryRequest commissionExpectedQueryRequest) {

        // 统计信息仍基于所有符合条件的主记录
        QueryWrapper<CommissionExpected> queryWrapper = commissionExpectedService
                .getQueryWrapper(commissionExpectedQueryRequest);
        List<CommissionExpected> allExpectedList = commissionExpectedService.list(queryWrapper);
        List<Long> expectedIds = allExpectedList.stream()
                .map(CommissionExpected::getId)
                .collect(Collectors.toList());
        CommissionExpectedStatisticsVO statisticsNewVO = commissionExpectedService
                .getExpectedStatisticsNew(expectedIds);

        // 获取混合分页结果
        Page<CommissionExpectedNewVO> mixedPage = commissionExpectedService
                .getCommissionExpectedVONewPage(commissionExpectedQueryRequest,allExpectedList);

        // 组装返回
        QueryCommissionExpectedByPageNewResponse response = new QueryCommissionExpectedByPageNewResponse();
        response.setExpectedStatisticsVO(statisticsNewVO);
        response.setPage(mixedPage);
        return Result.success(response);
    }

    /**
     * 应收款导出（旧）
     *
     * @param commissionExpectedQueryRequest
     * @return
     */
    @PostMapping("/export/old")
    @Operation(summary = "应收款导出")
    public void exportCommissionExpected(@RequestBody CommissionExpectedQueryRequest commissionExpectedQueryRequest, HttpServletResponse response) throws UnsupportedEncodingException {
        if (commissionExpectedQueryRequest == null) {
            throw new RuntimeException("查询参数不能为空");
        }

        // 设置响应头
        String fileName = URLEncoder.encode("应收款管理数据", "UTF-8").replaceAll("\\+", "%20");
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");

        // 查询数据
        QueryWrapper<CommissionExpected> queryWrapper = commissionExpectedService.getQueryWrapper(commissionExpectedQueryRequest);
        List<CommissionExpected> commissionExpectedList = commissionExpectedService.list(queryWrapper);

        // 转换为导出DTO
        List<CommissionExpectedExportDTO> exportDataList = commissionExpectedList.stream()
                .map(CommissionExpectedExportDTO::convertToExportDTO)
                .collect(Collectors.toList());

        // 使用EasyExcel导出
        try (ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream(), CommissionExpectedExportDTO.class).build()) {
            WriteSheet writeSheet = EasyExcel.writerSheet("应收款数据").build();
            excelWriter.write(exportDataList, writeSheet);
        } catch (Exception e) {
            throw new RuntimeException("导出应收款数据失败", e);
        }

    }

    /**
     * 应收款导出（新）
     *
     * @param commissionExpectedQueryRequest
     * @return
     */
    @PostMapping("/export")
    @Operation(summary = "应收款导出")
    public void exportCommissionExpectedNew(@RequestBody CommissionExpectedQueryRequest commissionExpectedQueryRequest, HttpServletResponse response) throws UnsupportedEncodingException {
        apiCommissionExpectedService.exportCommissionExpectedNew(commissionExpectedQueryRequest,response);
    }

    /**
     * 获取保单应收款
     */
    @PostMapping("/getExpectedCommissionByProductlaunchId")
    @Operation(summary = "获取保单应收款")
    public Result<Boolean> getExpectedCommissionByProductlaunchId(@RequestBody GetExpectedCommissionByProductlaunchIdRequest request) {
        if (request == null) {
            return Result.fail(ErrorCode.PARAMS_ERROR.getCode(), ErrorCode.PARAMS_ERROR.getMessage());
        }
        Policy policy = policyService.lambdaQuery().eq(Policy::getPolicyNo, request.getPolicyNo()).one();
        if (policy == null) {
            return Result.fail(ErrorCode.PARAMS_ERROR.getCode(), "保单不存在");
        }
        PolicyFollow policyFollow = policyFollowService.lambdaQuery().eq(PolicyFollow::getPolicyNo, request.getPolicyNo()).one();
        if (policyFollow == null) {
            return Result.fail(ErrorCode.PARAMS_ERROR.getCode(), "新单跟进不存在");
        }

        commissionExpectedService.getExpectedCommissionByProductlaunchId(
                policy,
                request.getProductLaunchBizId(),
                request.getInsuranceCompanyBizId(),
                request.getReconciliationCompany(),
                request.getReconciliationCompanyCode(),
                request.getReconciliationCompanyBizId(),
                policyFollow.getProfessionalInvestor());


        return Result.success(true);
    }

    /**
     * 应收款报表
     *
     * @param commissionExpectedQueryRequest
     * @return
     */
    @PostMapping("/receivable_report")
    @Operation(summary = "应收款报表")
    public Result<ReceivableReportResponse> receivableReport(@RequestBody CommissionExpectedQueryRequest commissionExpectedQueryRequest) {
        //保單持有人（中/英、繁简/大小写）、签单人、转介人名称（主）、受保人（中/英、繁简/大小写）、查询保单号列表
        List<String> queryPolicyNoList = new ArrayList<>();
        Boolean queryFlag = false;
        if (StringUtils.isNotBlank(commissionExpectedQueryRequest.getPolicyHolder())
            || StringUtils.isNotBlank(commissionExpectedQueryRequest.getSigner())
            || StringUtils.isNotBlank(commissionExpectedQueryRequest.getBrokerName())
            || StringUtils.isNotBlank(commissionExpectedQueryRequest.getInsured())
        ){
            queryPolicyNoList = policyFollowService.queryPolicyNoList(
                    commissionExpectedQueryRequest.getPolicyHolder(),
                    commissionExpectedQueryRequest.getSigner(),
                    commissionExpectedQueryRequest.getBrokerName(),
                    commissionExpectedQueryRequest.getInsured());
            queryFlag = true;
        }
        log.info("应收款报表=>receivableReport=>queryPolicyNoList:{}",JSON.toJSONString(queryPolicyNoList));
        // 构建查询条件
        commissionExpectedQueryRequest.setPolicyNoList(queryPolicyNoList);
        commissionExpectedQueryRequest.setQueryFlag(queryFlag);
        QueryWrapper<CommissionExpected> queryWrapper = commissionExpectedService.getQueryWrapper(commissionExpectedQueryRequest);

        // 先查询所有符合条件的记录ID（用于统计）
        List<CommissionExpected> allCommissionExpectedList = commissionExpectedService.list(queryWrapper);
        List<Long> allExpectedIdList = allCommissionExpectedList.stream().map(CommissionExpected::getId).collect(Collectors.toList());

        // 查询统计数据（基于所有符合条件的记录）
        CommissionExpectedStatisticsVO statisticsVO = commissionExpectedService.getExpectedStatisticsNew(allExpectedIdList);

        // 应收款报表分页查询 - 按保单号和期数维度统计
        Page<ReceivableReportVO> reportPage = new Page<>(commissionExpectedQueryRequest.getPageNo(), commissionExpectedQueryRequest.getPageSize());
        IPage<ReceivableReportVO> receivableReportPage = new Page<>(commissionExpectedQueryRequest.getPageNo(), commissionExpectedQueryRequest.getPageSize());
        if (!CollectionUtils.isEmpty(allExpectedIdList)) {
            receivableReportPage = commissionExpectedService.receivableReportPage(reportPage, allExpectedIdList);
        }
//        enrichReceivableReportWithCompanyName(receivableReportPage);
        receivableReportPage = convertReceivableReport(receivableReportPage);
        // 组装返回结果
        ReceivableReportResponse response = new ReceivableReportResponse();
        response.setStatisticsVO(statisticsVO);
        response.setPage(receivableReportPage);
        return Result.success(response);
    }


    public IPage<ReceivableReportVO> convertReceivableReport(IPage<ReceivableReportVO> receivableReportPage) {
        if (!org.springframework.util.CollectionUtils.isEmpty(receivableReportPage.getRecords())) {
            List<String> policyNoList = receivableReportPage.getRecords().stream().map(ReceivableReportVO::getPolicyNo).collect(Collectors.toList());
            List<PolicyFollow> policyFollowList = new ArrayList<>();
            if (!org.springframework.util.CollectionUtils.isEmpty(policyNoList)) {
                policyFollowList = policyFollowService.lambdaQuery()
                        .in(PolicyFollow::getPolicyNo, policyNoList)
                        .list();
            }
            Map<String, PolicyFollow> policyFollowMap = policyFollowList.stream()
                    .collect(Collectors.toMap(PolicyFollow::getPolicyNo, Function.identity()));
            List<ReceivableReportVO> voList = receivableReportPage.getRecords().stream().map(vo -> {
                PolicyFollow policyFollow= policyFollowMap.get(vo.getPolicyNo());
                if (policyFollow != null) {
                    vo.setProductName(policyFollow.getProductName());
                    vo.setProductLaunchBizId(policyFollow.getProductLaunchBizId());
                }
                //已入账比例（%）>= 预计入账比例（%） 待入账比例和待入账金额归零
                //已入账比例（%）
                BigDecimal paidRatio = ObjectUtils.defaultIfNull(vo.getPaidRatio(), BigDecimal.ZERO);
                //预计入账比例（%）
                BigDecimal commissionRatio = ObjectUtils.defaultIfNull(vo.getCommissionRatio(), BigDecimal.ZERO);
                if (paidRatio.compareTo(commissionRatio) >= 0) {
                    //待入账金额（港币）
                    vo.setUnpaidAmount(BigDecimal.ZERO);
                    //待入账比例（%）
                    vo.setUnpaidRatio(BigDecimal.ZERO);
                }
                return vo;
            }).collect(Collectors.toList());
            receivableReportPage.setRecords(voList);
        }
        return receivableReportPage;
    }

    private void enrichReceivableReportWithCompanyName(IPage<ReceivableReportVO> page) {
        if (page == null || CollectionUtils.isEmpty(page.getRecords())) {
            return;
        }

        // 收集所有非空的对账公司 bizId（去重）
        List<String> bizIdList = page.getRecords().stream()
                .map(ReceivableReportVO::getReconciliationCompanyBizId)
                .filter(StringUtils::isNotBlank)
                .distinct()
                .collect(Collectors.toList());
        if (bizIdList.isEmpty()) {
            return;
        }

        // 调用 Feign 批量查询对账公司信息
        ApiInsuranceReconciliationCompanyPageRequest request = new ApiInsuranceReconciliationCompanyPageRequest();
        request.setReconciliationCompanyBizIdList(bizIdList);
        request.setPageNo(1);
        request.setPageSize(bizIdList.size());

        Result result = companyFeignClient.page(request);
        List<ApiInsuranceReconciliationCompanyPageResponse> companyList = extractCompanyListFromResult(result);
        if (companyList.isEmpty()) {
            return;
        }

        // 构建 bizId -> name 映射
        Map<String, String> nameMap = companyList.stream()
                .filter(c -> StringUtils.isNotBlank(c.getReconciliationCompanyBizId()))
                .collect(Collectors.toMap(
                        ApiInsuranceReconciliationCompanyPageResponse::getReconciliationCompanyBizId,
                        ApiInsuranceReconciliationCompanyPageResponse::getName,
                        (v1, v2) -> v1 // 重复时保留第一个
                ));
        // 回填名称
        page.getRecords().forEach(vo -> {
            if (StringUtils.isNotBlank(vo.getReconciliationCompanyBizId())) {
                String name = nameMap.get(vo.getReconciliationCompanyBizId());
                if (StringUtils.isNotBlank(name)) {
                    vo.setReconciliationCompany(name);
                }
            }
        });
    }

    private List<ApiInsuranceReconciliationCompanyPageResponse> extractCompanyListFromResult(Result result) {
        if (result == null || result.getCode() != 200 || result.getData() == null) {
            return Collections.emptyList();
        }
        Object data = result.getData();
        try {
            // 将 data 转为 JSON 字符串再解析为 Map，以便提取 records
            Map<String, Object> dataMap = JSON.parseObject(JSON.toJSONString(data), new TypeReference<Map<String, Object>>() {});
            Object recordsObj = dataMap.get("records");
            if (recordsObj instanceof List) {
                List<?> recordsList = (List<?>) recordsObj;
                List<ApiInsuranceReconciliationCompanyPageResponse> companyList = new ArrayList<>();
                for (Object item : recordsList) {
                    // 将每个元素转换为目标类型
                    ApiInsuranceReconciliationCompanyPageResponse company = JSON.parseObject(
                            JSON.toJSONString(item),
                            ApiInsuranceReconciliationCompanyPageResponse.class
                    );
                    companyList.add(company);
                }
                return companyList;
            }
        } catch (Exception e) {
            log.error("解析公司列表失败", e);
        }
        return Collections.emptyList();
    }

    @GetMapping("/test_expected_commission")
    @Operation(summary = "测试佣金匹配")
    public Result<Boolean> testExpectedCommission(@RequestParam("policyNo") String policyNo,
                                                  @RequestParam("effectiveDate") String effectiveDate,
                                                  @RequestParam("coolingOffEndDate") String coolingOffEndDate) {
        if (StringUtils.isBlank(policyNo)) {
            return Result.fail(ResultCode.NULL_ERROR.getCode(), "policyNo不能为空");
        }
        try {
            commissionExpectedService.testExpectedCommission(policyNo, effectiveDate, coolingOffEndDate);
        } catch (IOException e) {
            return Result.fail(ResultCode.FAIL.getCode(), "读取文件失败");
        }

        return Result.success(true);
    }
}
