import logging
from decimal import Decimal
from typing import Dict, Any, List
from api.v1.modules.a76.invoices.models import InvoiceHeader
from core.exceptions import ErrorCollector

logger = logging.getLogger(__name__)

def review_sisexpo_limits(
    invoice: InvoiceHeader,
    settings: Dict[str, Any],
    total_qty: Decimal,
    total_net_weight: Decimal,
    total_value: Decimal,
    errors: ErrorCollector
) -> None:
    """
    Validates invoice totals against the SisExpo min/max limit parameters.
    Uses robust resolution for deep nested JSON structure.
    """
    invoice_type = (invoice.invoice_type or "").strip().upper()
    op_type = "exp"
    
    # 1. Start from ssisexpo root
    params = settings.get("ssisexpo", {})
    cat_name = "ssisexpo"

    # 2. Deep resolution if not in root (Frontend structure)
    # Search for any limit field to decide if we should deep dive
    has_root_limits = any(params.get(k) is not None for k in ["cantlimite", "CantLimite", "pesolimite", "PesoLimite", "valorlimite", "ValorLimite"])
    
    if not has_root_limits:
        invoice_map = settings.get("invoices", {}).get("types", {}).get(op_type, {}).get(invoice_type, {})
        # Buscar en ssimpFormData (shared schema) dentro de qsisgen o ssisgen
        params = invoice_map.get("qsisgen", {}).get("ssimpFormData", {}) or invoice_map.get("ssisgen", {}).get("ssimpFormData", {}) or params
        cat_name = f"invoices.types.{op_type}.{invoice_type}.ssimpFormData"

    # Obtener límites Máximos
    limit_qty = Decimal(str(params.get("cantlimite") or params.get("CantLimite") or 0))
    limit_weight = Decimal(str(params.get("pesolimite") or params.get("PesoLimite") or 0))
    limit_value = Decimal(str(params.get("valorlimite") or params.get("ValorLimite") or 0))

    # Obtener límites Mínimos
    min_limit_qty = Decimal(str(params.get("cantlimitemin") or params.get("CantLimiteMin") or 0))
    min_limit_weight = Decimal(str(params.get("pesolimitemin") or params.get("PesoLimiteMin") or 0))
    min_limit_value = Decimal(str(params.get("valorlimitemin") or params.get("ValorLimiteMin") or 0))

    logger.info(f"DEBUG_EXPO_LIMITS: Invoice={invoice.invoice_number} | DetectedType={invoice_type} | ResolvedCat={cat_name}")
    logger.info(f"DEBUG_EXPO_LIMITS: RAW_PARAMS_FOR_VAL={params}") # Cuidado, esto puede ser largo pero nos dirá la verdad
    logger.info(f"DEBUG_EXPO_LIMITS: Qty: Current={total_qty} Max={limit_qty} Min={min_limit_qty}")
    logger.info(f"LIMIT_CHECK_EXPO: Weight: Current={total_net_weight} Max={limit_weight} Min={min_limit_weight}")
    logger.info(f"LIMIT_CHECK_EXPO: Value: Current={total_value} Max={limit_value} Min={min_limit_value}")

    solution = ["Ajuste los valores de la factura o consulte a su Administrador para parametrizar la factura."]
    code = "PAR.EXPO"

    # --- Max Validations ---
    if limit_qty > 0 and total_qty > limit_qty:
        errors.add_error(field="financials.total_quantity", message=f"La cantidad total ({total_qty}) excede el máximo permitido ({limit_qty}).", solution=solution, code=code)

    if limit_weight > 0 and total_net_weight > limit_weight:
        errors.add_error(field="financials.net_weight", message=f"El peso neto total ({total_net_weight}) excede el máximo permitido ({limit_weight}).", solution=solution, code=code)

    if limit_value > 0 and total_value > limit_value:
        errors.add_error(field="financials.value_me", message=f"El valor total en USD ({total_value}) excede el máximo permitido ({limit_value}).", solution=solution, code=code)

    # --- Min Validations ---
    if min_limit_qty > 0 and total_qty < min_limit_qty:
        errors.add_error(field="financials.total_quantity", message=f"La cantidad total ({total_qty}) es inferior al mínimo requerido ({min_limit_qty}).", solution=solution, code=code)

    if min_limit_weight > 0 and total_net_weight < min_limit_weight:
        errors.add_error(field="financials.net_weight", message=f"El peso neto total ({total_net_weight}) es inferior al mínimo requerido ({min_limit_weight}).", solution=solution, code=code)

    if min_limit_value > 0 and total_value < min_limit_value:
        errors.add_error(field="financials.value_me", message=f"El valor total en USD ({total_value}) es inferior al mínimo requerido ({min_limit_value}).", solution=solution, code=code)


def limit_weight(lines: List[Any]) -> tuple[Decimal, Decimal]:
    """Sums exported quantity and net weight across all line items."""
    total_qty = Decimal(0)
    total_net_weight = Decimal(0)
    for line in lines:
        if line.quantity:
            total_qty += line.quantity.quantity or Decimal(0)
            total_net_weight += line.quantity.net_weight or Decimal(0)
    return total_qty, total_net_weight

def limit_value(lines: List[Any]) -> Decimal:
    """Sums (unit_cost_capture x quantity) across all line items."""
    total_value = Decimal(0)
    for line in lines:
        if line.financial and line.quantity:
            capture = line.financial.unit_cost_capture or Decimal(0)
            qty = line.quantity.quantity or Decimal(0)
            total_value += capture * qty
    return total_value
