package com.trade.admin.job;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.trade.common.core.page.GridPage;
import com.trade.common.utils.DateUtils;
import com.trade.service.DictConstants;
import com.trade.service.finance.disbursement.dto.ExportTaxRefundSelfDto;
import com.trade.service.finance.disbursement.service.BillingDisbursementService;
import com.trade.service.thirdparty.xiaotu.dto.*;
import com.trade.service.thirdparty.xiaotu.service.XiaotuRequestService;
import com.trade.service.trade.exportrebate.domain.TaxRebateExportDetails;
import com.trade.service.trade.exportrebate.domain.TaxRebatePurchaseDetails;
import com.trade.service.trade.exportrebate.service.TaxRebateExportDetailsBaseService;
import com.trade.service.trade.exportrebate.service.TaxRebatePurchaseDetailsBaseService;
import com.trade.service.trade.salesorder.service.ICustomsDeclarationGoodsService;
import com.trade.service.trade.salesorder.vo.CustomsDeclarationGoodsBelongsVO;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

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

/**
 * 出口退税记录拉取定时任务
 */
@Component
public class ExportTaxRebateSchedule {

    private static final Logger logger = LoggerFactory.getLogger(ExportTaxRebateSchedule.class);
    @Resource
    private TaxRebateExportDetailsBaseService taxRebateExportDetailsBaseService;
    @Resource
    private TaxRebatePurchaseDetailsBaseService taxRebatePurchaseDetailsBaseService;
    @Resource
    private ICustomsDeclarationGoodsService customsDeclarationGoodsService;
    @Resource
    private XiaotuRequestService xiaotuRequestService;
    @Resource
    private BillingDisbursementService billingDisbursementService;

    /**
     * 1、外贸：出口明细的业务主键是“关联号”；进货明细的业务主键是“关联号+序号”； 2、生产：出口明细的业务主键是“所属期+序号”；
     * 3、企业21位报关单已经申报过退税了，但是后来发现申报错误了，或者退运了，就需要冲减原本的退税数据，这种情况下存在多条（具体方式为：新增一条金额为负数的记录） 4、冲减完成还可以继续申报
     */
    /**
     * 每月25号的3点执行拉取退税记录任务
     */
    @Scheduled(cron = "0 0 3 25 * ?")
    public void pullTaxRebateRecordsJob() {
        int pageNum = 1;
        int pageSize = 100;
        while (true) {
            GridPage<CustomsDeclarationGoodsBelongsVO> gridPage = customsDeclarationGoodsService
                    .getAllNeedPullTaxRebateRecords(pageNum, pageSize);
            List<CustomsDeclarationGoodsBelongsVO> rows = gridPage.getRows();
            handleTaxRebateRecords(rows);
            if (CollUtil.isEmpty(rows) || rows.size() < pageSize) {
                break;
            }
            pageNum++;
        }
    }

    private void handleTaxRebateRecords(List<CustomsDeclarationGoodsBelongsVO> rows) {
        if (CollUtil.isEmpty(rows)) {
            return;
        }
        // 查询21位报关单商品信息
        Map<String, CustomsDeclarationGoodsBelongsVO> map = rows.stream()
                .collect(Collectors.toMap(CustomsDeclarationGoodsBelongsVO::getCkbgdh, (v) -> v, (v1, v2) -> v2));
        // 外贸型和生产型，分别处理
        Map<Boolean, List<CustomsDeclarationGoodsBelongsVO>> exportMap = rows.stream()
                .collect(Collectors.groupingBy(CustomsDeclarationGoodsBelongsVO::getHasPurchaseContract));
        List<CustomsDeclarationGoodsBelongsVO> tradeList = exportMap.get(true);
        // 贸易型企业数据
        if (CollUtil.isNotEmpty(tradeList)) {
            Map<String, List<CustomsDeclarationGoodsBelongsVO>> userGroup = tradeList.stream()
                    .collect(Collectors.groupingBy(e -> e.getXtEid() + "_" + e.getXtUserId()));
            userGroup.forEach((k, v) -> {
                // 根据21位报关单拉取明细数据
                BusinessCommonRequest businessCommonRequest = getBusinessCommonRequest(k);
                List<String> ckbgdhList = v.stream().map(CustomsDeclarationGoodsBelongsVO::getCkbgdh).distinct()
                        .collect(Collectors.toList());
                ExportDetailsRequest request = getExportDetailsRequest(ckbgdhList);
                int page = 1;
                int pageSize = request.getPageSize();
                while (true) {
                    // 分页处理，防止小图返回多页数据
                    CommonQueryResponse<TradeExportAndPurchaseDetailsResponse> responses = xiaotuRequestService
                            .queryTradeExportAndPurchaseDetails(request, businessCommonRequest);
                    if (responses == null || CollUtil.isEmpty(responses.getRows())) {
                        break;
                    }
                    processTradeData(responses.getRows(), map);
                    if (responses.getPageSize() < pageSize || responses.getRows().size() < pageSize) {
                        break;
                    }
                    page++;
                    request.setPage(page);
                }
            });
        }
        // 生产型企业数据
        List<CustomsDeclarationGoodsBelongsVO> produceList = exportMap.get(false);
        if (CollUtil.isNotEmpty(produceList)) {
            Map<String, List<CustomsDeclarationGoodsBelongsVO>> userGroup = produceList.stream()
                    .collect(Collectors.groupingBy(e -> e.getXtEid() + "_" + e.getXtUserId()));
            userGroup.forEach((k, v) -> {
                BusinessCommonRequest businessCommonRequest = getBusinessCommonRequest(k);
                List<String> ckbgdhList = v.stream().map(CustomsDeclarationGoodsBelongsVO::getCkbgdh).distinct()
                        .collect(Collectors.toList());
                ExportDetailsRequest request = getExportDetailsRequest(ckbgdhList);
                int page = 1;
                int pageSize = request.getPageSize();
                while (true) {
                    CommonQueryResponse<ProduceExportDetailsResponse> responses = xiaotuRequestService
                            .queryProduceExportDetails(request, businessCommonRequest);
                    if (responses == null || CollUtil.isEmpty(responses.getRows())) {
                        break;
                    }
                    processProduceData(responses.getRows(), map);
                    if (responses.getPageSize() < pageSize || responses.getRows().size() < pageSize) {
                        break;
                    }
                    page++;
                    request.setPage(page);
                }
            });
        }
    }

    private static @NotNull BusinessCommonRequest getBusinessCommonRequest(String k) {
        BusinessCommonRequest businessCommonRequest = new BusinessCommonRequest();
        businessCommonRequest.setXtEid(k.split("_")[0]);
        businessCommonRequest.setXtUid(k.split("_")[1]);
        return businessCommonRequest;
    }

    private static @NotNull ExportDetailsRequest getExportDetailsRequest(List<String> ckbgdhList) {
        ExportDetailsRequest request = new ExportDetailsRequest();
        request.setCkbgdhs(ckbgdhList);
        request.setPage(1);
        request.setPageSize(ckbgdhList.size());
        return request;
    }

    /**
     * 处理贸易型企业数据
     * 
     * @param responses
     * @param map
     */
    private void processTradeData(List<TradeExportAndPurchaseDetailsResponse> responses,
            Map<String, CustomsDeclarationGoodsBelongsVO> map) {
        if (CollUtil.isEmpty(responses)) {
            return;
        }
        // 已完成退税的申报商品id
        List<Long> finishedGoodsIds = new ArrayList<>();
        // 新拉取到的出口明细对象集合
        List<TaxRebateExportDetails> exportDetails = new ArrayList<>();
        // 外贸型，出口明细中“关联号”是唯一业主主键，用于后续判断新拉取到的记录是更新（赋值id字段）还是新增。
        Map<String, TaxRebateExportDetails> taxRebateExportDetailMap = new HashMap<>();
        // 外贸型，出口明细中“关联号”是唯一业主主键，记录本次查询结果中，对应“关联号”返回的进货明细
        Map<String, List<PurchaseDetailsResponse>> purchaseDetailsResponseMap = new HashMap<>();
        for (TradeExportAndPurchaseDetailsResponse response : responses) {
            // 获取商品信息
            CustomsDeclarationGoodsBelongsVO vo = map.get(response.getCkbgdh());
            // 构建出口明细对象
            TaxRebateExportDetails detail = new TaxRebateExportDetails(response, vo);
            exportDetails.add(detail);
            taxRebateExportDetailMap.put(response.getGlh(), detail);
            purchaseDetailsResponseMap.put(response.getGlh(), response.getTsjhmx());
            // 记录完成退税的商品信息，用于后续更新状态
            if (vo != null && DictConstants.REBATE_PROCESS_STATUS_DONE.equals(detail.getStatus())) {
                finishedGoodsIds.add(vo.getId());
            }
        }
        // 根据关联号查询，表内已存在的历史记录，用于判断更新或者新增
        List<String> correlationNos = exportDetails.stream().map(TaxRebateExportDetails::getCorrelationNo).distinct()
                .collect(Collectors.toList());
        Map<String, TaxRebateExportDetails> existMap = taxRebateExportDetailsBaseService
                .getByCorrelationNos(correlationNos).stream()
                .collect(Collectors.toMap(TaxRebateExportDetails::getCorrelationNo, (v) -> v, (v1, v2) -> v2));
        List<TaxRebateExportDetails> saveExportList = new ArrayList<>();
        List<TaxRebateExportDetails> updateExportList = new ArrayList<>();
        for (TaxRebateExportDetails exportDetail : exportDetails) {
            // 已拉取到的记录，则更新，新记录则插入
            TaxRebateExportDetails detail = existMap.get(exportDetail.getCorrelationNo());
            if (detail == null) {
                saveExportList.add(exportDetail);
            } else {
                exportDetail.setId(detail.getId());
                updateExportList.add(exportDetail);
            }
        }
        if (CollUtil.isNotEmpty(saveExportList)) {
            taxRebateExportDetailsBaseService.saveBatch(saveExportList);
        }
        if (CollUtil.isNotEmpty(updateExportList)) {
            taxRebateExportDetailsBaseService.updateBatchById(updateExportList);
        }
        List<TaxRebatePurchaseDetails> taxRebatePurchaseDetailList = new ArrayList<>();
        for (Map.Entry<String, List<PurchaseDetailsResponse>> entry : purchaseDetailsResponseMap.entrySet()) {
            TaxRebateExportDetails taxRebateExportDetails = taxRebateExportDetailMap.get(entry.getKey());
            if (taxRebateExportDetails == null) {
                logger.error("出口退税:进货信息处理，未找到对应的出口记录（关联号：{}）", entry.getKey());
                continue;
            }
            List<PurchaseDetailsResponse> purchaseResponseDetails = entry.getValue();
            if (CollUtil.isEmpty(purchaseResponseDetails)) {
                logger.error("出口退税:进货信息处理，未找到对应的进货记录（关联号：{}）", entry.getKey());
                continue;
            }
            taxRebatePurchaseDetailList.addAll(purchaseResponseDetails.stream()
                    .map(o -> new TaxRebatePurchaseDetails(o, taxRebateExportDetails)).collect(Collectors.toList()));
        }
        // 根据“关联号”+“序号” 查询已经存在的进货记录
        Map<String, TaxRebatePurchaseDetails> purchaseDetailsExistMap = taxRebatePurchaseDetailsBaseService
                .getByCorrelationNos(correlationNos).stream().collect(Collectors
                        .toMap(o -> o.getCorrelationNo() + "_" + o.getDeclarationSerialNo(), (v) -> v, (v1, v2) -> v2));
        List<TaxRebatePurchaseDetails> savePurchaseList = new ArrayList<>();
        List<TaxRebatePurchaseDetails> updatePurchaseList = new ArrayList<>();
        for (TaxRebatePurchaseDetails taxRebatePurchaseDetails : taxRebatePurchaseDetailList) {
            // 存在进货记录则更新，否则新增
            TaxRebatePurchaseDetails detail = purchaseDetailsExistMap.get(taxRebatePurchaseDetails.getCorrelationNo()
                    + "_" + taxRebatePurchaseDetails.getDeclarationSerialNo());
            if (detail == null) {
                savePurchaseList.add(taxRebatePurchaseDetails);
            } else {
                taxRebatePurchaseDetails.setId(detail.getId());
                updatePurchaseList.add(taxRebatePurchaseDetails);
            }
        }
        if (CollUtil.isNotEmpty(savePurchaseList)) {
            taxRebatePurchaseDetailsBaseService.saveBatch(savePurchaseList);
        }
        if (CollUtil.isNotEmpty(updatePurchaseList)) {
            taxRebatePurchaseDetailsBaseService.updateBatchById(updatePurchaseList);
        }
        // 更新已完成退税的商品记录
        if (CollUtil.isNotEmpty(finishedGoodsIds)) {
            customsDeclarationGoodsService.updateTsjltbbsDoneByIds(finishedGoodsIds);
        }
    }

    /**
     * 处理生产型企业数据
     * 
     * @param responses
     * @param map
     */
    private void processProduceData(List<ProduceExportDetailsResponse> responses,
            Map<String, CustomsDeclarationGoodsBelongsVO> map) {
        if (CollUtil.isEmpty(responses)) {
            return;
        }
        // 已完成退税的申报商品id
        List<Long> finishedGoodsIds = new ArrayList<>();
        // 新拉取到的出口明细对象集合
        List<TaxRebateExportDetails> exportDetails = new ArrayList<>();
        for (ProduceExportDetailsResponse response : responses) {
            // 获取商品信息
            CustomsDeclarationGoodsBelongsVO vo = map.get(response.getCkbgdh());
            // 构建出口明细对象
            TaxRebateExportDetails detail = new TaxRebateExportDetails(response, vo);
            exportDetails.add(detail);
            // 记录完成退税的商品信息，用于后续更新状态
            if (vo != null && DictConstants.REBATE_PROCESS_STATUS_DONE.equals(detail.getStatus())) {
                finishedGoodsIds.add(vo.getId());
            }
        }
        // 生产型，出口明细中“所属期+序号”唯一业主主键，用于后续判断新拉取到的记录是更新（赋值id字段）还是新增。
        // 根据序号号查询，表内已存在的历史记录，用于判断更新或者新增
        List<String> declarationSerialNos = exportDetails.stream().map(TaxRebateExportDetails::getDeclarationSerialNo)
                .distinct().collect(Collectors.toList());
        Map<String, TaxRebateExportDetails> existMap = taxRebateExportDetailsBaseService
                .getByDeclarationSerialNos(declarationSerialNos).stream().collect(Collectors.toMap(
                        o -> o.getDeclarationMonthYear() + "_" + o.getDeclarationSerialNo(), (v) -> v, (v1, v2) -> v2));
        List<TaxRebateExportDetails> saveExportList = new ArrayList<>();
        List<TaxRebateExportDetails> updateExportList = new ArrayList<>();
        for (TaxRebateExportDetails exportDetail : exportDetails) {
            // 已拉取到的记录，则更新，新记录则插入
            TaxRebateExportDetails detail = existMap
                    .get(exportDetail.getDeclarationMonthYear() + "_" + exportDetail.getDeclarationSerialNo());
            if (detail == null) {
                saveExportList.add(exportDetail);
            } else {
                exportDetail.setId(detail.getId());
                updateExportList.add(exportDetail);
            }
        }
        if (CollUtil.isNotEmpty(saveExportList)) {
            taxRebateExportDetailsBaseService.saveBatch(saveExportList);
        }
        if (CollUtil.isNotEmpty(updateExportList)) {
            taxRebateExportDetailsBaseService.updateBatchById(updateExportList);
        }
        // 更新已完成退税的商品记录
        if (CollUtil.isNotEmpty(finishedGoodsIds)) {
            customsDeclarationGoodsService.updateTsjltbbsDoneByIds(finishedGoodsIds);
        }
    }

    /**
     * 每月26号的3点,根据18位报关单号汇总生成C端用户的退税收款信息
     */
    @Scheduled(cron = "0 0 3 26 * ?")
    public void generateTaxRebatePaymentInfoForSelfExportUserJob() {
        // 拉取自营出口客户，已退税且未入账的出口信息记录
        int page = 1;
        int pageSize = 200;
        while (true) {
            GridPage<TaxRebateExportDetails> detailsGridPage = taxRebateExportDetailsBaseService
                    .getPayableTaxRebateExportDetailsForSelfExportUser(page, pageSize);
            if (detailsGridPage == null || CollUtil.isEmpty(detailsGridPage.getRows())) {
                break;
            }
            List<ExportTaxRefundSelfDto> exportTaxRefundDtos = new ArrayList<>();
            List<TaxRebateExportDetails> rows = detailsGridPage.getRows();
            Map<String, List<TaxRebateExportDetails>> map = rows.stream()
                    .collect(Collectors.groupingBy(o -> o.getCustomsDeclarationNo() + "_" + o.getSalesContractId() + "_"
                            + DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, o.getGmtModified())));
            for (Map.Entry<String, List<TaxRebateExportDetails>> entry : map.entrySet()) {
                String key = entry.getKey();
                List<TaxRebateExportDetails> value = entry.getValue();
                if (CollUtil.isEmpty(value)) {
                    continue;
                }
                ExportTaxRefundSelfDto dto = new ExportTaxRefundSelfDto();
                dto.setCustomsDeclarationNo(key.split("_")[0]);
                String srt = key.split("_")[1];
                dto.setSaleContractId(StrUtil.isEmpty(srt) ? null : Long.parseLong(srt));
                dto.setRefundAmount(value.stream().map(TaxRebateExportDetails::getTaxRefundAmount)
                        .reduce(BigDecimal.ZERO, BigDecimal::add));
                dto.setRzrq(DateUtils.atStartOfDay(value.get(0).getGmtModified()));
                exportTaxRefundDtos.add(dto);
                List<Long> detailIds = value.stream().map(TaxRebateExportDetails::getId).distinct()
                        .collect(Collectors.toList());
                if (CollUtil.isNotEmpty(detailIds)) {
                    // 更新退税状态
                    taxRebateExportDetailsBaseService.batchUpdatePaymentStatusAndPaymentDate(detailIds,
                            DictConstants.REBATE_PAYMENT_STATUS_PAYED, dto.getRzrq());
                }
            }
            if (CollUtil.isNotEmpty(exportTaxRefundDtos)) {
                // 生成退税入账确认记录
                billingDisbursementService.saveSelfTaxRefund(exportTaxRefundDtos);
            }
            page++;
            if (rows.size() < pageSize) {
                break;
            }
        }
    }
}
