from dataclasses import dataclass
from typing import List, Dict, Any, Optional


@dataclass
class DecisionOutput:
    decision: str
    reasons: List[str]
    flags: List[str]
    confidence: str
    score: int
    risk_class: str
    approved_amount: Optional[float]
    approved_term_days: Optional[int]
    features_used: Dict[str, Any]


def _interpolar_limite_por_score(score: int) -> float:
    """
    Calcula o valor máximo de crédito recomendado com base no score (0-100)
    e nas faixas definidas, usando interpolação linear dentro de cada faixa.
    """
    if score < 10:
        return 0.0
    elif score <= 25:
        # 10-25 → 0 a 10.000
        return 10000.0 * (score - 10) / 15.0
    elif score <= 50:
        # 26-50 → 10.000 a 25.000
        return 10000.0 + 15000.0 * (score - 26) / 25.0
    else:  # 51-100
        # 51-100 → 25.000 a 50.000
        return 25000.0 + 25000.0 * (score - 51) / 50.0


def make_credit_decision(
    *,
    score: int,
    risk_class: str,
    confidence: str,
    reasons: List[str],
    features_used: Dict[str, Any],
) -> DecisionOutput:

    flags: List[str] = []
    approved_amount: Optional[float] = None
    approved_term_days: Optional[int] = None

    # Extrair informações auxiliares
    bank_features = features_used.get("bank_features", {})
    consistency_report = features_used.get("company_consistency_report", {})
    consistency_status = consistency_report.get("status")
    has_valid_extrato = bank_features.get("has_valid_extrato", False)
    fluxo_val = bank_features.get("fluxo_liquido")
    try:
        fluxo = float(fluxo_val) if fluxo_val is not None else 0.0
    except (TypeError, ValueError):
        fluxo = 0.0

    valor_solicitado = features_used.get("valor_credito")
    prazo_solicitado = features_used.get("prazo_dias")
    recommended_max_value = features_used.get("recommended_max_value")
    recommended_term_days = features_used.get("recommended_term_days")

    # =================================================================
    # REGRAS DE NEGAÇÃO (em ordem de prioridade)
    # =================================================================

    # 1) Inconsistência grave de identidade
    if consistency_status == "INCONSISTENT":
        return DecisionOutput(
            decision="RECUSADO",
            reasons=reasons + ["(Neg) Inconsistência grave de identidade legal: documentos de empresas diferentes."],
            flags=["INCONSISTENCIA_LEGAL"],
            confidence=confidence,
            score=score,
            risk_class=risk_class,
            approved_amount=0.0,
            approved_term_days=None,
            features_used=features_used,
        )

    # 2) Fluxo negativo em extrato válido
    if has_valid_extrato and fluxo < 0:
        return DecisionOutput(
            decision="RECUSADO",
            reasons=reasons + ["(Neg) Fluxo de caixa negativo no extrato bancário inviabiliza concessão de crédito."],
            flags=["FLUXO_NEGATIVO"],
            confidence=confidence,
            score=score,
            risk_class=risk_class,
            approved_amount=0.0,
            approved_term_days=None,
            features_used=features_used,
        )

    # 3) Extrato válido com recommended_max_value == 0 (capacidade zero)
    if has_valid_extrato and recommended_max_value is not None and recommended_max_value == 0:
        return DecisionOutput(
            decision="RECUSADO",
            reasons=reasons + ["(Neg) O extrato bancário não indica capacidade de pagamento (limite zero)."],
            flags=["CAPACIDADE_ZERO"],
            confidence=confidence,
            score=score,
            risk_class=risk_class,
            approved_amount=0.0,
            approved_term_days=None,
            features_used=features_used,
        )

    # 4) Score mínimo não atingido
    if score < 10:
        return DecisionOutput(
            decision="RECUSADO",
            reasons=reasons + ["(Neg) O score de crédito é inferior ao mínimo exigido (10 pontos)."],
            flags=["SCORE_MINIMO_NAO_ATINGIDO"],
            confidence=confidence,
            score=score,
            risk_class=risk_class,
            approved_amount=0.0,
            approved_term_days=None,
            features_used=features_used,
        )

    # =================================================================
    # CÁLCULO DO LIMITE MÁXIMO COM BASE NO SCORE (INTERPOLADO)
    # =================================================================
    limite_interpolado = _interpolar_limite_por_score(score)

    # O máximo permitido é o menor entre o limite interpolado e o recommended_max_value (se existir e for >0)
    max_permitido = limite_interpolado
    if recommended_max_value is not None and recommended_max_value > 0:
        max_permitido = min(max_permitido, recommended_max_value)

    # Define o valor aprovado (menor entre solicitado e máximo permitido)
    if valor_solicitado and valor_solicitado <= max_permitido:
        approved_amount = valor_solicitado
    else:
        approved_amount = max_permitido
        if valor_solicitado and valor_solicitado > max_permitido:
            reasons.append(
                f"(Neg) O valor solicitado ({int(valor_solicitado)}) excede o limite máximo calculado ({int(max_permitido)})."
            )

    approved_term_days = prazo_solicitado  # pode ser ajustado depois

    # =================================================================
    # DECISÃO BASEADA NA CLASSE DE RISCO (A–E)
    # =================================================================
    if risk_class == "A":
        decision = "APROVADO"
        flags.extend(["CONDICOES_IDEAIS"])

        reasons.append("(Pos) A identidade legal da empresa foi validada com sucesso.")
        reasons.append("(Pos) Os documentos apresentados são consistentes entre si.")
        if fluxo > 0:
            reasons.append("(Pos) O extrato bancário demonstra fluxo de caixa positivo suficiente.")
        reasons.append("(Pos) O valor aprovado está dentro dos limites da política de crédito.")

    elif risk_class == "B":
        decision = "APROVADO_COM_RESTRICOES"
        flags.append("AJUSTE_DE_VALOR")

        reasons.append("(Pos) A empresa apresenta identidade validada.")
        reasons.append("(Neg) O valor solicitado excede a capacidade financeira estimada ou o limite da faixa.")
        reasons.append(f"(Info) Valor aprovado: {int(approved_amount)}.")

    elif risk_class == "C":
        decision = "SOLICITAR_AJUSTE_PRAZO"
        flags.append("AJUSTE_DE_PRAZO")

        reasons.append("(Pos) A empresa possui identidade legal válida.")
        reasons.append("(Neg) O prazo solicitado não é compatível com o fluxo financeiro ou política.")
        if recommended_term_days:
            approved_term_days = recommended_term_days
            reasons.append(f"(Info) Prazo recomendado: {recommended_term_days} dias.")
        else:
            reasons.append("(Info) Recomenda-se prazo de 15, 30 ou 45 dias.")
        if consistency_status == "PARTIAL":
            flags.append("CONSISTENCIA_LEGAL_PARCIAL")
            reasons.append("(Info) Pequenas divergências legais foram identificadas.")

    elif risk_class == "D":
        decision = "ANALISE_MANUAL"
        flags.append("INTERVENCAO_HUMANA")

        reasons.append("(Info) O sistema identificou condições que exigem validação humana.")
        if consistency_status == "PARTIAL":
            flags.append("CONSISTENCIA_LEGAL_PARCIAL")
            reasons.append("(Info) Pequenas divergências legais foram identificadas.")
        if has_valid_extrato and fluxo <= 0:
            flags.append("DADOS_BANCARIOS_INSUFICIENTES")
            reasons.append("(Neg) Os dados bancários indicam fluxo não positivo.")
        reasons.append("(Info) Um analista poderá solicitar documentos ou correções adicionais.")

    elif risk_class == "E":
        decision = "RECUSADO"
        flags.append("RISCO_INACEITAVEL")

        reasons.append("(Neg) Não foi possível validar de forma confiável a identidade legal da empresa.")
        if has_valid_extrato and fluxo <= 0:
            reasons.append("(Neg) O extrato bancário não demonstra capacidade financeira.")
        reasons.append("(Info) O pedido pode ser reavaliado após correção das pendências.")

    else:
        decision = "ANALISE_MANUAL"
        flags.append("CLASSE_DESCONHECIDA")
        reasons.append("(Info) A classificação de risco não pôde ser interpretada automaticamente.")

    # Adiciona flag da faixa de score (apenas informativa)
    if score <= 25:
        flags.append("FAIXA_10_25")
    elif score <= 50:
        flags.append("FAIXA_26_50")
    else:
        flags.append("FAIXA_51_100")

    return DecisionOutput(
        decision=decision,
        reasons=reasons,
        flags=flags,
        confidence=confidence,
        score=score,
        risk_class=risk_class,
        approved_amount=approved_amount,
        approved_term_days=approved_term_days,
        features_used=features_used,
    )