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

logger = logging.getLogger(__name__)

def review_limits(
    invoice: InvoiceHeader,
    settings: Dict[str, Any],
    errors: ErrorCollector
) -> None:
    """
    Valida que los totales de la factura no excedan los límites configurados 
    en SisImpo o SisDef.
    """
    if not invoice.financials:
        logger.warning(f"LIMIT_CHECK: No financials found for invoice {invoice.id}")
        return

    # Determinamos qué categoría de parámetros usar según el tipo de factura
    invoice_type = (invoice.invoice_type or "").strip().upper()
    op_type = "imp" # Por ahora enfocado en importación

    # 1. Intentar obtener de la raíz (ssisimpo/ssisdef)
    if invoice_type in {"DEF", "MEX"}:
        params = settings.get("ssisdef", {})
        cat_name = "ssisdef"
    else:
        params = settings.get("ssisimpo", {})
        cat_name = "ssisimpo"

    # 2. Si no están en la raíz, intentar en la estructura profunda (invoices.types...)
    # Esta es la estructura que viene del frontend según el JSON "hermoso"
    if not params.get("CantLimite") and not params.get("cantlimite"):
        invoice_map = settings.get("invoices", {}).get("types", {}).get(op_type, {}).get(invoice_type, {})
        # Buscar en ssimpFormData 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))

    # Totales actuales de la factura
    current_qty = Decimal(str(invoice.financials.total_quantity or 0))
    current_weight = Decimal(str(invoice.financials.net_weight or 0))
    current_value = Decimal(str(invoice.financials.value_me or 0))

    logger.info(f"LIMIT_CHECK: Invoice={invoice.invoice_number} Type={invoice_type} Cat={cat_name}")
    logger.info(f"LIMIT_CHECK: Qty: Current={current_qty} Max={limit_qty} Min={min_limit_qty}")
    logger.info(f"LIMIT_CHECK: Weight: Current={current_weight} Max={limit_weight} Min={min_limit_weight}")
    logger.info(f"LIMIT_CHECK: Value: Current={current_value} Max={limit_value} Min={min_limit_value}")

    # --- Validaciones de Máximos ---
    if limit_qty > 0 and current_qty > limit_qty:
        errors.add_error(field="financials.total_quantity", message=f"La cantidad total ({current_qty}) excede el máximo permitido ({limit_qty}).", solution=["Ajuste las cantidades."], code="LIMIT_QTY_EXCEEDED")

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

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

    # --- Validaciones de Mínimos ---
    if min_limit_qty > 0 and current_qty < min_limit_qty:
        errors.add_error(field="financials.total_quantity", message=f"La cantidad total ({current_qty}) es inferior al mínimo requerido ({min_limit_qty}).", solution=["Aumente las cantidades."], code="MIN_LIMIT_QTY_NOT_MET")

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

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