package com.ruoyi.info.collection.service.support;

import com.ruoyi.info.collection.domain.CcdiCreditNegativeInfo;
import com.ruoyi.info.collection.domain.CcdiDebtsInfo;
import com.ruoyi.lsfx.domain.response.CreditParsePayload;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.sql.Date;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * 征信解析结果装配器
 */
@Component
public class CreditInfoPayloadAssembler {

    private static final BigDecimal MISSING_SENTINEL = new BigDecimal("-9999");

    private static final List<DebtMapping> DEBT_MAPPINGS = List.of(
            new DebtMapping("uncle_bank_house", "银行", "住房贷款", "银行", "未结清银行住房贷款"),
            new DebtMapping("uncle_bank_car", "银行", "汽车贷款", "银行", "未结清银行汽车贷款"),
            new DebtMapping("uncle_bank_manage", "银行", "经营贷款", "银行", "未结清银行经营贷款"),
            new DebtMapping("uncle_bank_consume", "银行", "消费贷款", "银行", "未结清银行消费贷款"),
            new DebtMapping("uncle_bank_other", "银行", "其他贷款", "银行", "未结清银行其他贷款"),
            new DebtMapping("uncle_not_bank", "非银", "非银行贷款", "非银", "未结清非银行贷款"),
            new DebtMapping("uncle_credit_card", "银行", "信用卡", "银行", "未结清信用卡")
    );

    public List<CcdiDebtsInfo> buildDebts(String personId, String personName, LocalDate queryDate, CreditParsePayload payload) {
        Map<String, Object> source = payload == null ? null : payload.getLxDebt();
        if (source == null || source.isEmpty()) {
            return List.of();
        }
        List<CcdiDebtsInfo> rows = new ArrayList<>();
        for (DebtMapping mapping : DEBT_MAPPINGS) {
            CcdiDebtsInfo row = buildDebtRow(personId, personName, queryDate, source, mapping);
            if (row != null) {
                rows.add(row);
            }
        }
        return rows;
    }

    public CcdiCreditNegativeInfo buildNegative(String personId, String personName, LocalDate queryDate, CreditParsePayload payload) {
        Map<String, Object> source = payload == null ? null : payload.getLxPublictype();
        CcdiCreditNegativeInfo info = new CcdiCreditNegativeInfo();
        info.setPersonId(personId);
        info.setPersonName(personName);
        info.setQueryDate(queryDate == null ? null : Date.valueOf(queryDate));
        info.setCivilCnt(toInteger(source == null ? null : source.get("civil_cnt")));
        info.setEnforceCnt(toInteger(source == null ? null : source.get("enforce_cnt")));
        info.setAdmCnt(toInteger(source == null ? null : source.get("adm_cnt")));
        info.setCivilLmt(toBigDecimal(source == null ? null : source.get("civil_lmt")));
        info.setEnforceLmt(toBigDecimal(source == null ? null : source.get("enforce_lmt")));
        info.setAdmLmt(toBigDecimal(source == null ? null : source.get("adm_lmt")));
        return info;
    }

    private CcdiDebtsInfo buildDebtRow(String personId, String personName, LocalDate queryDate,
                                       Map<String, Object> source, DebtMapping mapping) {
        Object stateValue = source.get(mapping.prefix() + "_state");
        if (isMissingSentinel(stateValue)) {
            return null;
        }
        BigDecimal principalBalance = toBigDecimal(source.get(mapping.prefix() + "_bal"));
        BigDecimal debtTotalAmount = toBigDecimal(source.get(mapping.prefix() + "_lmt"));
        String debtStatus = toStringValue(stateValue);
        if (isEmptyMetrics(principalBalance, debtTotalAmount, debtStatus)) {
            return null;
        }

        CcdiDebtsInfo row = new CcdiDebtsInfo();
        row.setPersonId(personId);
        row.setPersonName(personName);
        row.setQueryDate(queryDate == null ? null : Date.valueOf(queryDate));
        row.setDebtMainType(mapping.debtMainType());
        row.setDebtSubType(mapping.debtSubType());
        row.setCreditorType(mapping.creditorType());
        row.setDebtName(mapping.debtName());
        row.setPrincipalBalance(principalBalance);
        row.setDebtTotalAmount(debtTotalAmount);
        row.setDebtStatus(debtStatus);
        return row;
    }

    private boolean isEmptyMetrics(BigDecimal principalBalance, BigDecimal debtTotalAmount, String debtStatus) {
        boolean principalEmpty = principalBalance == null || BigDecimal.ZERO.compareTo(principalBalance) == 0;
        boolean totalEmpty = debtTotalAmount == null || BigDecimal.ZERO.compareTo(debtTotalAmount) == 0;
        return principalEmpty && totalEmpty && isBlank(debtStatus);
    }

    private Integer toInteger(Object value) {
        BigDecimal decimal = toBigDecimal(value);
        return decimal == null ? 0 : decimal.intValue();
    }

    private BigDecimal toBigDecimal(Object value) {
        if (value == null) {
            return null;
        }
        if (isMissingSentinel(value)) {
            return null;
        }
        if (value instanceof BigDecimal decimal) {
            return decimal;
        }
        String text = Objects.toString(value, "").trim();
        if (text.isEmpty()) {
            return null;
        }
        return new BigDecimal(text);
    }

    private String toStringValue(Object value) {
        if (value == null) {
            return null;
        }
        if (isMissingSentinel(value)) {
            return null;
        }
        String text = Objects.toString(value, "").trim();
        return text.isEmpty() ? null : text;
    }

    private boolean isMissingSentinel(Object value) {
        if (value == null) {
            return false;
        }
        String text = Objects.toString(value, "").trim();
        if (text.isEmpty()) {
            return false;
        }
        try {
            return new BigDecimal(text).compareTo(MISSING_SENTINEL) == 0;
        } catch (NumberFormatException e) {
            return false;
        }
    }

    private boolean isBlank(String value) {
        return value == null || value.trim().isEmpty();
    }

    private record DebtMapping(String prefix, String debtMainType, String debtSubType, String creditorType, String debtName) {
    }
}
