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

import com.alibaba.fastjson.JSON;
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.base.feign.request.exchangerate.ApiExchangeRateConvertRequest;
import com.yd.base.feign.response.exchangerate.ApiExchangeRateConvertResponse;
import com.yd.common.enums.CommonEnum;
import com.yd.common.exception.BusinessException;
import com.yd.common.result.Result;
import com.yd.common.utils.CodeGenerator;
import com.yd.common.utils.RandomStringGenerator;
import com.yd.csf.api.dto.ApiSalarySplitSummaryPageDTO;
import com.yd.csf.api.service.ApiSalarySplitService;
import com.yd.csf.api.utils.ExchangeUtils;
import com.yd.csf.feign.dto.excel.ApiSalarySplitSummaryExcelDto;
import com.yd.csf.feign.dto.salarysplit.ApiSalarySplitBatchSaveDto;
import com.yd.csf.feign.dto.salarysplit.ApiSalarySplitPageDto;
import com.yd.csf.feign.dto.salarysplit.ApiSalarySplitStatisticsDto;
import com.yd.csf.feign.dto.salarysplit.ApiSalarySplitSummaryPageDto;
import com.yd.csf.feign.request.salarysplit.*;
import com.yd.csf.api.dto.ApiSalarySplitPageListDTO;
import com.yd.csf.feign.response.salarysplit.ApiCalculateToAmountResponse;
import com.yd.csf.feign.response.salarysplit.ApiQueryRemainingResponse;
import com.yd.csf.feign.response.salarysplit.ApiSalarySplitExportSummaryListResponse;
import com.yd.csf.feign.response.salarysplit.ApiSalarySplitQueryRateResponse;
import com.yd.csf.service.model.FortuneAccount;
import com.yd.csf.service.model.SalarySplit;
import com.yd.csf.service.service.FortuneAccountService;
import com.yd.csf.service.service.ISalarySplitService;
import com.yd.oss.feign.client.ApiExcelFeignClient;
import com.yd.oss.feign.dto.ExportParam;
import com.yd.oss.feign.dto.ExportResult;
import com.yd.oss.feign.request.ApiExportRequest;
import com.yd.user.feign.client.sysdict.ApiSysDictFeignClient;
import com.yd.user.feign.request.sysdict.GetDictTypeListRequest;
import com.yd.user.feign.response.sysdict.GetDictItemListByDictTypeResponse;
import com.yd.user.feign.response.sysdict.GetDictTypeListResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class ApiSalarySplitServiceImpl implements ApiSalarySplitService {

    @Autowired
    private FortuneAccountService fortuneAccountService;

    @Autowired
    private ISalarySplitService iSalarySplitService;

    @Autowired
    private ApiExchangeRateFeignClient apiExchangeRateFeignClient;

    @Autowired
    private ApiExcelFeignClient apiExcelFeignClient;

    @Autowired
    private ApiSysDictFeignClient apiSysDictFeignClient;

    /**
     * 分页查询-薪资拆分应发信息汇总列表
     * @param request
     * @return
     */
    @Override
    public Result<ApiSalarySplitSummaryPageDTO> summaryPage(ApiSalarySplitSummaryPageRequest request) {
        ApiSalarySplitSummaryPageDTO response = new ApiSalarySplitSummaryPageDTO();
        // 查询分页信息
        Page<ApiSalarySplitSummaryPageDto> page = new Page<>(request.getPageNo(), request.getPageSize());
        IPage<ApiSalarySplitSummaryPageDto> iPage = iSalarySplitService.summaryPage(page, request);
        if (CollectionUtils.isNotEmpty(iPage.getRecords())) {
            Map<String, String> map = getBillOrgDict();
            iPage.getRecords().stream().map(dto -> {
                dto.setBillOrg(map != null ? map.get(dto.getBillOrg()) : "");
                return dto;
            }).collect(Collectors.toList());
        }
        response.setPage(iPage);
        //查询薪资拆分业务ID列表
        List<String> salarySplitBizIdList = iSalarySplitService.queryList(request);
        response.setSalarySplitBizIdList(salarySplitBizIdList);
        return Result.success(response);
    }

    /**
     * 获取出账机构字典数据
     */
    private Map<String, String> getBillOrgDict() {
        Map<String, String> dictMap = new HashMap<>();
        try {
            GetDictTypeListRequest dictRequest = new GetDictTypeListRequest();
            dictRequest.setTypeList(Collections.singletonList("csf_bill_org"));
            List<GetDictTypeListResponse> dictTypeResponses = apiSysDictFeignClient.getByDictTypeList(dictRequest).getData();

            if (dictTypeResponses != null && !dictTypeResponses.isEmpty()) {
                for (GetDictTypeListResponse dictTypeResponse : dictTypeResponses) {
                    if ("csf_bill_org".equals(dictTypeResponse.getDictType())
                            && dictTypeResponse.getDictItemList() != null) {
                        for (GetDictItemListByDictTypeResponse dictItem : dictTypeResponse.getDictItemList()) {
                            dictMap.put(dictItem.getItemValue(), dictItem.getItemLabel());
                        }
                        break;
                    }
                }
            }
        } catch (Exception e) {
            log.error("获取出账机构字典数据失败", e);
        }
        return dictMap;
    }

    /**
     * 分页查询-薪资拆分应发信息列表
     * @param request
     * @return
     */
    @Override
    public Result<ApiSalarySplitPageListDTO> page(ApiSalarySplitPageRequest request) {
        ApiSalarySplitPageListDTO response = new ApiSalarySplitPageListDTO();
        // 查询分页信息
        Page<ApiSalarySplitPageDto> page = new Page<>(request.getPageNo(), request.getPageSize());
        IPage<ApiSalarySplitPageDto> iPage = iSalarySplitService.page(page, request);
        response.setPage(iPage);

        // 查询统计信息
        ApiSalarySplitStatisticsDto statisticsDto = new ApiSalarySplitStatisticsDto();
        FortuneAccount fortuneAccount = fortuneAccountService.queryOne(request.getFortuneAccountBizId());
        // 发放币种
        statisticsDto.setBeSplitCurrency(fortuneAccount != null ? fortuneAccount.getPayoutCurrency() : "");

        BigDecimal beSplitAmount = BigDecimal.ZERO;
        if (fortuneAccount != null) {
            // 查询所有拆分记录，计算已拆分总金额
            List<SalarySplit> salarySplits = iSalarySplitService.lambdaQuery()
                    .eq(SalarySplit::getFortuneAccountBizId, request.getFortuneAccountBizId())
                    .list();
            BigDecimal splitTotal = salarySplits.stream()
                    .map(SalarySplit::getFromAmount)
                    .filter(Objects::nonNull)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);

            BigDecimal fortuneAmount = fortuneAccount.getPayoutAmount() != null ? fortuneAccount.getPayoutAmount() : BigDecimal.ZERO;
            beSplitAmount = fortuneAmount.subtract(splitTotal);
            if (beSplitAmount.compareTo(BigDecimal.ZERO) < 0) {
                beSplitAmount = BigDecimal.ZERO; // 防止负数
            }
        }
        statisticsDto.setBeSplitAmount(beSplitAmount);
        response.setStatisticsDto(statisticsDto);

        return Result.success(response);
    }

    /**
     * 批量保存
     * @param request
     * @return
     */
    @Override
    public Result batchSave(ApiSalarySplitBatchSaveRequest request) {
        //查询出账记录是否存在
        FortuneAccount fortuneAccount = fortuneAccountService.queryOne(request.getFortuneAccountBizId());
        if (fortuneAccount == null) {
            throw new BusinessException("出账记录不存在");
        }
        //统计保存入参的薪资拆分应发记录原币种金额金额之和
        if (CollectionUtils.isNotEmpty(request.getApiSalarySplitBatchSaveDtoList())) {
            //入参的薪资拆分应发记录原币种金额金额之和
            BigDecimal total = request.getApiSalarySplitBatchSaveDtoList().stream()
                    .map(ApiSalarySplitBatchSaveDto::getFromAmount)
                    .filter(Objects::nonNull)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            //原币种总金额
            BigDecimal fortuneAmount = fortuneAccount.getHkdAmount() != null ? fortuneAccount.getHkdAmount() : BigDecimal.ZERO;
            //入参的薪资拆分应发记录原币种金额金额之和不能大于原币种总金额
            if (fortuneAmount.compareTo(total) < 0) {
                throw new BusinessException("拆分的原币种金额之和不能大于原币种总金额");
            }
        }

        //薪资拆分应发记录-先删除后新增
        iSalarySplitService.deleteByFortuneAccountBizId(request.getFortuneAccountBizId());

        //批量新增
        if (CollectionUtils.isEmpty(request.getApiSalarySplitBatchSaveDtoList())) {
            return Result.success();
        }
        List<SalarySplit> salarySplitList = new ArrayList<>();
        for (ApiSalarySplitBatchSaveDto dto : request.getApiSalarySplitBatchSaveDtoList()) {
            SalarySplit salarySplit = new SalarySplit();
            BeanUtils.copyProperties(dto,salarySplit);
            //薪资拆分应发表唯一业务ID
            salarySplit.setSalarySplitBizId(RandomStringGenerator.generateBizId16(CommonEnum.UID_TYPE_SALARY_SPLIT.getCode()));
            //发放编号
            salarySplit.setSalarySplitNo(CodeGenerator.generate10Code("SP"));
            //出账记录业务id
            salarySplit.setFortuneAccountBizId(request.getFortuneAccountBizId());
            salarySplitList.add(salarySplit);
        }
        iSalarySplitService.saveOrUpdateBatch(salarySplitList);
        return Result.success();
    }

    /**
     * 查询-原币种剩余总金额和原币种
     * @param request
     * @return
     */
    @Override
    public Result<ApiQueryRemainingResponse> queryRemaining(ApiQueryRemainingRequest request) {
        // 1. 校验出账记录是否存在
        FortuneAccount fortuneAccount = fortuneAccountService.queryOne(request.getFortuneAccountBizId());
        if (fortuneAccount == null) {
            throw new BusinessException("出账记录不存在");
        }

        // 2. 计算本次拟拆分金额总和（使用请求中的 fromAmountList）
        BigDecimal splitTotal = BigDecimal.ZERO;
        if (CollectionUtils.isNotEmpty(request.getFromAmountList())) {
            splitTotal = request.getFromAmountList().stream()
                    .filter(Objects::nonNull)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
        }

        // 3. 计算剩余可拆金额（账户总额 - 本次拟拆分总额）
        BigDecimal fortuneAmount = fortuneAccount.getPayoutAmount() != null ? fortuneAccount.getPayoutAmount() : BigDecimal.ZERO;
        BigDecimal beSplitAmount = fortuneAmount.subtract(splitTotal);
        if (beSplitAmount.compareTo(BigDecimal.ZERO) < 0) {
            beSplitAmount = BigDecimal.ZERO; // 防止负数
        }

        // 4. 封装响应
        ApiQueryRemainingResponse response = new ApiQueryRemainingResponse();
        response.setCurrency(fortuneAccount.getPayoutCurrency());
        response.setFromAmount(beSplitAmount);
        return Result.success(response);
    }

    /**
     * 查询-原币种和原币种金额——>目标币种即时汇率和目标币种金额
     * @param request
     * @return
     */
    @Override
    public Result<ApiSalarySplitQueryRateResponse> queryRate(ApiSalarySplitQueryRateRequest request) {
        //查询出账记录是否存在
        FortuneAccount fortuneAccount = fortuneAccountService.queryOne(request.getFortuneAccountBizId());
        if (fortuneAccount == null) {
            throw new BusinessException("出账记录不存在");
        }
        ApiExchangeRateConvertRequest convertRequest = new ApiExchangeRateConvertRequest();
        //原币种金额
        convertRequest.setAmount(request.getFromAmount());
        //原币种
        convertRequest.setFromCurrency(fortuneAccount.getPayoutCurrency());
        //目标币种
        convertRequest.setToCurrency(request.getToCurrency());
        //调用远程转换接口
        Result<ApiExchangeRateConvertResponse> result = apiExchangeRateFeignClient.convert(convertRequest);
        if (result != null && result.getData() != null) {
            ApiSalarySplitQueryRateResponse response = new ApiSalarySplitQueryRateResponse();
            BeanUtils.copyProperties(result.getData(),response);
            return Result.success(response);
        }
        return Result.success();
    }

    /**
     * 计算-目标金额
     * @param request
     * @return
     */
    @Override
    public Result<ApiCalculateToAmountResponse> calculateToAmount(ApiCalculateToAmountRequest request) {
        BigDecimal toAmount = ExchangeUtils.calculateTargetAmount(request.getFromAmount(),request.getExchangeRate());
        ApiCalculateToAmountResponse response = new ApiCalculateToAmountResponse();
        response.setToAmount(toAmount);
        return Result.success(response);
    }

    /**
     * 导出-薪资拆分应发信息汇总列表
     * @param request
     * @return
     */
    @Override
    public Result<ApiSalarySplitExportSummaryListResponse> export(ApiSalarySplitExportSummaryListRequest request) {
        // 查询数据
        List<ApiSalarySplitSummaryPageDto> dataList = iSalarySplitService.summaryList(request);
        log.info("导出-薪资拆分应发信息汇总列表:dataList,{}", JSON.toJSONString(dataList));
        Map<String, String> map = getBillOrgDict();
        List<ApiSalarySplitSummaryExcelDto> excelDtoList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(dataList)) {
            excelDtoList = dataList.stream().map(dto -> {
                ApiSalarySplitSummaryExcelDto excelDto = new ApiSalarySplitSummaryExcelDto();
                BeanUtils.copyProperties(dto,excelDto);
                excelDto.setBillOrg(map != null ? map.get(dto.getBillOrg()) : "");
                return excelDto;
            }).collect(Collectors.toList());
        }
        log.info("导出-薪资拆分应发信息汇总列表:excelDtoList,{}", JSON.toJSONString(excelDtoList));
        // 构建导出参数
        ExportParam exportParam = new ExportParam();
        // 指定需要导出的字段（字段名必须与 DTO 中的属性名一致）
        exportParam.setFieldNames(Arrays.asList(
                "salarySplitNo","businessNo","brokerName","internalNumber","team","fromAmount",
                "currency","exchangeRate","toAmount","toCurrency",
                "fortuneAccountMonth","billOrg","amount"
        ));
        exportParam.setFileName("薪资拆分应发信息汇总");
        exportParam.setUploadToOss(true);
        exportParam.setOssPath("exports/salary_split/");

        // 构建请求对象
        ApiExportRequest exportRequest = new ApiExportRequest();
        exportRequest.setDataList(excelDtoList);
        exportRequest.setEntityClass(ApiSalarySplitSummaryExcelDto.class);
        exportRequest.setExportParam(exportParam);

        log.info("导出-薪资拆分应发信息汇总列表:exportRequest,{}", JSON.toJSONString(exportRequest));
        // 远程调用导出接口
        Result<ExportResult> result = apiExcelFeignClient.export(exportRequest);
        if (result.getCode() != 200 || result.getData() == null) {
            throw new BusinessException("导出失败：" + result.getMsg());
        }

        ExportResult exportResult = result.getData();
        if (!exportResult.getSuccess()) {
            throw new BusinessException("导出失败：" + exportResult.getErrorMsg());
        }

        log.info("导出-薪资拆分应发信息汇总列表:exportResult,{}", JSON.toJSONString(exportResult));
        // 封装响应
        ApiSalarySplitExportSummaryListResponse response = new ApiSalarySplitExportSummaryListResponse();
        response.setUrl(exportResult.getOssUrl());
//        response.setFileSize(exportResult.getFileSize());
//        response.setTotalCount(dataList.size());
        return Result.success(response);
    }

}
