package com.jwipc.sys.logic.impl;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.jwipc.exception.DaoException;
import com.jwipc.security.LoginUtil;
import com.jwipc.supplier.clent.dto.SupplierContactsDTO;
import com.jwipc.supplier.client.SupplierClient;
import com.jwipc.sys.client.ExchangeRateClient;
import com.jwipc.sys.client.SequenceClient;
import com.jwipc.sys.client.TaxClient;
import com.jwipc.sys.client.dto.TaxDTO;
import com.jwipc.sys.constant.FinancialShareClient;
import com.jwipc.sys.dto.CreateFinancialShareContractDTO;
import com.jwipc.sys.dto.CreateFinancialShareContractDetailDTO;
import com.jwipc.sys.dto.FinancialShareApiResultDTO;
import com.jwipc.sys.entity.FinancialShareContract;
import com.jwipc.sys.logic.FinancialShareLogic;
import com.jwipc.sys.service.IFinancialShareContractService;
import com.jwipc.sys.util.FinancialShareUtil;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 *  财务共享-接口实现类
 * </p>
 *
 * @author Chen Tianshi
 * @since 2025/12/10 14:08
 */
@Service
@RequiredArgsConstructor
public class FinancialShareLogicImpl implements FinancialShareLogic {
    private final FinancialShareClient financialShareClient;
    private final FinancialShareUtil financialShareUtil;
    private final IFinancialShareContractService financialShareService;
    private final SequenceClient sequenceClient;
    private final SupplierClient supplierClient;
    private final ExchangeRateClient exchangeRateClient;
    private final TaxClient taxClient;

    private static final int AMOUNT_SCALE = 2;
    private static final RoundingMode AMOUNT_ROUNDING = RoundingMode.HALF_UP;

    @Override
    public void createCostContract(CreateFinancialShareContractDTO dto) {
        List<CreateFinancialShareContractDetailDTO> detailList = dto.getDetail();
        if (CollectionUtils.isNotEmpty(detailList)) {
            String contractCode = sequenceClient.createfinanceSequenceNo("financial_share_contract");

            JSONObject dataItem = new JSONObject();
            String invoiceType = "A";
            if (StringUtils.equals(dto.getInvoiceType(), "1")) {
                invoiceType = "B"; // 增值税普通发票
            } else if (StringUtils.equals(dto.getInvoiceType(), "2")) {
                invoiceType = "A"; // 增值税专用发票
            }
            DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            LocalDateTime now = LocalDateTime.now();
            LocalDateTime twoYearsLater = now.plusYears(2);
            dataItem.put("contractCode", contractCode);     // 共享候选键，唯一
            dataItem.put("applyUser", dto.getCreateUserAccount());
            dataItem.put("contractType", dto.getContractType());
            dataItem.put("costCompanyCode", dto.getCompanyCode());
            dataItem.put("isCurrency", true);
            dataItem.put("invoiceType", invoiceType);
            dataItem.put("signDate", dateTimeFormatter.format(now));
            dataItem.put("endDate", dateTimeFormatter.format(twoYearsLater));
            dataItem.put("contractExecutionDate", dateTimeFormatter.format(now));
            dataItem.put("companyCode", dto.getCompanyCode());
            dataItem.put("applierUser", dto.getCreateUserAccount());
            // 关联立项
            setProjectDetail(detailList, dataItem);
            // 签约方
            setContractPartyDetail(dto, dataItem);
            dataItem.put("contractTotalAmount", dto.getContractTotalAmount().setScale(AMOUNT_SCALE, AMOUNT_ROUNDING));
            dataItem.put("contractTotalAmountCurrency", dto.getContractTotalAmount().setScale(AMOUNT_SCALE, AMOUNT_ROUNDING));
            // 付款信息
            setPaymentDetail(dto, dataItem);

            JSONObject reqBody = new JSONObject();
            JSONArray dataArray = new JSONArray();
            dataArray.add(dataItem);
            reqBody.put("data", dataArray);

            String accessToken = financialShareUtil.getShareAccessToken();
            FinancialShareApiResultDTO tenderApiResult = financialShareClient.createContractApplicationBill(accessToken, reqBody);
            JSONObject data = financialShareUtil.handleApiResult(tenderApiResult, "创建费用合同申请单");
            JSONArray resultArray = data.getJSONArray("result");

            saveFinancialShareContract(dto, contractCode, resultArray);
        }
    }

    /**
     * 设置签约方
     * @param dto 创建财务共享合同审批申请单 DTO
     * @param dataItem 请求参数
     */
    private void setContractPartyDetail(CreateFinancialShareContractDTO dto, JSONObject dataItem) {
        JSONArray contractPartyDetail = new JSONArray();
        // 甲方
        JSONObject party1 = new JSONObject();
        // 当前用户
        String currentUserName = LoginUtil.getName();
        party1.put("signContract", "0");
        party1.put("partyType", "bos_org");
        party1.put("contractParty", dto.getCompanyCode());
        party1.put("partPerson", currentUserName);
        party1.put("contactPerson", currentUserName);
        contractPartyDetail.add(party1);
        // 乙方
        JSONObject party2 = new JSONObject();
        // 供应商主数据中的联系人类型：是“业务接口人”对应的姓名
        SupplierContactsDTO supplier = supplierClient.getDefaultContact(dto.getSupplierCode(), "12");
        String supplierContactPerson = "";
        if (supplier != null) {
            supplierContactPerson = supplier.getContactsName();
        }
        party2.put("signContract", "1");
        party2.put("partyType", "bd_supplier");
        party2.put("contractParty", dto.getSupplierCode());
        party2.put("partPerson", dto.getSupplierName());
        party2.put("contactPerson", supplierContactPerson);
        contractPartyDetail.add(party2);
        dataItem.put("contractPartyDetail", contractPartyDetail);
    }

    /**
     * 设置关联立项
     * @param detailList 明细数据
     * @param dataItem 请求参数
     */
    private void setProjectDetail(List<CreateFinancialShareContractDetailDTO> detailList, JSONObject dataItem) {
        JSONArray projectDetail = new JSONArray();
        for (CreateFinancialShareContractDetailDTO detail : detailList) {
            String toCurrency = detail.getBillCurrencyCode();
            if (StringUtils.isEmpty(toCurrency)) {
                throw new DaoException("原采购单币种为空");
            }
            JSONObject project = new JSONObject();
            project.put("billNo", detail.getPurchaseBillCode());
            project.put("applierUser", detail.getBillCreateUserCode());
            project.put("description", detail.getBillMaterialSpec());
            project.put("applierDate", detail.getBillCreateTime());
            project.put("itemFullName", detail.getExpenseTypeLongName());
            project.put("canAmount", detail.getBillItemPrice().setScale(AMOUNT_SCALE, AMOUNT_ROUNDING));
            project.put("billCanAmount", detail.getBillItemPrice().setScale(AMOUNT_SCALE, AMOUNT_ROUNDING));
            project.put("projectWriteFffAmount", calculateAmountByExchangeRate(detail.getDetailAmount(), detail.getCurrencyCode(), toCurrency));
            projectDetail.add(project);
        }
        dataItem.put("projectDetail", projectDetail);
    }

    /**
     * 设置付款计划
     * @param dto 创建财务共享合同审批申请单 DTO
     * @param dataItem  请求参数
     */
    private void setPaymentDetail(CreateFinancialShareContractDTO dto, JSONObject dataItem) {
        List<CreateFinancialShareContractDetailDTO> detailList = dto.getDetail();
        JSONArray paymentDetail = new JSONArray();
        // 按成本中心、报销类别、税率进行分组汇总
        List<CreateFinancialShareContractDetailDTO> summaryList =
                new ArrayList<>(
                        detailList.stream()
                                .collect(Collectors.toMap(
                                        d -> norm(d.getCostCenterCode()) + "|" + norm(d.getExpenseTypeCode()) + "|" + norm(d.getTaxCode()),
                                        d -> {
                                            CreateFinancialShareContractDetailDTO copy = new CreateFinancialShareContractDetailDTO();
                                            copy.setCostCenterCode(norm(d.getCostCenterCode()));
                                            copy.setExpenseTypeCode(norm(d.getExpenseTypeCode()));
                                            copy.setTaxCode(norm(d.getTaxCode()));
                                            copy.setCurrencyCode(d.getCurrencyCode());
                                            copy.setDetailAmount(Optional.ofNullable(d.getDetailAmount()).orElse(BigDecimal.ZERO));
                                            return copy;
                                        },
                                        (a, b) -> {
                                            a.setDetailAmount(a.getDetailAmount().add(
                                                    Optional.ofNullable(b.getDetailAmount()).orElse(BigDecimal.ZERO)
                                            ));
                                            return a;
                                        }
                                ))
                                .values()
                );
        for (CreateFinancialShareContractDetailDTO detail : summaryList) {
            String taxCode = detail.getTaxCode();
            BigDecimal taxRate = BigDecimal.ZERO;               // 税率
            BigDecimal taxAmount;                               // 税额
            BigDecimal expenseAmount = detail.getDetailAmount();// 含税金额
            BigDecimal noTaxAmount;                             // 不含税金额
            if (StringUtils.isNotEmpty(taxCode)) {
                TaxDTO byCode = taxClient.getByCode(taxCode);
                if (ObjectUtil.isNotNull(byCode)) {
                    taxRate = byCode.getTaxValue();
                }
            }
            noTaxAmount = expenseAmount.divide(BigDecimal.ONE.add(taxRate), AMOUNT_SCALE, AMOUNT_ROUNDING);
            taxAmount = expenseAmount.subtract(noTaxAmount);

            JSONObject payment = new JSONObject();
            payment.put("currencyCode", detail.getCurrencyCode());
            payment.put("expenseAmount", expenseAmount.setScale(AMOUNT_SCALE, AMOUNT_ROUNDING));
            payment.put("taxRate", taxRate);
            payment.put("taxAmount", taxAmount.setScale(AMOUNT_SCALE, AMOUNT_ROUNDING));
            payment.put("noTaxAmount", noTaxAmount);
            payment.put("costCenterCode", detail.getCostCenterCode());
            payment.put("costUndertakeCompanyCode", dto.getCompanyCode());
            payment.put("expenseItemNumber", detail.getExpenseTypeCode());
            paymentDetail.add(payment);
        }
        dataItem.put("paymentDetail", paymentDetail);
    }

    /**
     * 创建财务共享合同
     * @param dto 创建财务共享合同审批申请单 DTO
     * @param contractCode 表编码
     * @param resultArray 共享返回结果
     */
    private void saveFinancialShareContract(CreateFinancialShareContractDTO dto, String contractCode, JSONArray resultArray) {
        List<Long> businessIdList = dto.getDetail().stream()
                .map(CreateFinancialShareContractDetailDTO::getBusinessId)
                .filter(Objects::nonNull)
                .distinct()
                .toList();
        List<FinancialShareContract> financialShareContractList = new ArrayList<>();
        for (Object object : resultArray) {
            JSONObject jsonObject = (JSONObject) object;
            // 财务共享合同审批申请单-存SRM
            for (Long businessId : businessIdList) {
                FinancialShareContract createEntity = new FinancialShareContract();
                createEntity.setCode(contractCode);
                createEntity.setBusinessType(dto.getBusinessType());
                createEntity.setBusinessId(businessId);
                createEntity.setContractId(jsonObject.getString("id"));
                createEntity.setContractCode(jsonObject.getString("number"));
                createEntity.setSupplierId(dto.getSupplierId());
                createEntity.setSupplierCode(dto.getSupplierCode());
                createEntity.setDeleteFlag("0");
                createEntity.setCreateTime(LocalDateTime.now());
                createEntity.setCreateUserId(LoginUtil.getUserId());
                createEntity.setUpdateTime(LocalDateTime.now());
                createEntity.setUpdateUserId(LoginUtil.getUserId());
                financialShareContractList.add(createEntity);
            }
            financialShareService.saveOrUpdateBatch(financialShareContractList);
        }
    }
    /**
     * 根据汇率计算金额
     * @param amount 金额
     * @param fromCurrency 源币种
     * @param toCurrency 目标币种
     * @return 计算后的金额
     */
    private BigDecimal calculateAmountByExchangeRate(BigDecimal amount, String fromCurrency, String toCurrency) {
        if (amount == null) {
            return BigDecimal.ZERO;
        }

        BigDecimal rate = resolveExchangeRate(fromCurrency, toCurrency);

        return amount
                .multiply(rate)
                .setScale(AMOUNT_SCALE, AMOUNT_ROUNDING);
    }

    /**
     * 获取汇率
     * @param fromCurrency 源币种
     * @param toCurrency 目标币种
     * @return 汇率
     */
    private BigDecimal resolveExchangeRate(String fromCurrency, String toCurrency) {
        // 同币种：汇率 = 1
        if (fromCurrency.equalsIgnoreCase(toCurrency)) {
            return BigDecimal.ONE;
        }

        // 正向汇率
        BigDecimal forwardRate = exchangeRateClient.getExchangeRate(fromCurrency, toCurrency);
        if (isValidRate(forwardRate)) {
            return forwardRate;
        }

        // 反向汇率，推导正向汇率
        BigDecimal reverseRate = exchangeRateClient.getExchangeRate(toCurrency, fromCurrency);
        if (isValidRate(reverseRate)) {
            return BigDecimal.ONE.divide(reverseRate, AMOUNT_SCALE, AMOUNT_ROUNDING);
        }

        throw new DaoException(String.format(
                "未维护汇率：%s -> %s",
                fromCurrency, toCurrency
        ));
    }

    /**
     * 汇率是否有效
     * @param rate 汇率
     */
    private boolean isValidRate(BigDecimal rate) {
        if (rate == null) {
            return false;
        }
        // 你已确认：ONE = 未取到
        return rate.compareTo(BigDecimal.ONE) != 0
                && rate.compareTo(BigDecimal.ZERO) > 0;
    }

    private static String norm(String s) {
        if (s == null) return "";
        return s.trim();
    }
}
