from sqlalchemy import func
from sqlalchemy.orm import Session, joinedload
from api.v1.modules.a76.invoices.models import InvoiceHeader, InvoiceStatus
from api.v1.modules.a76.items.models import LineItem
from api.v1.modules.a76.parts.models import Part
from api.v1.modules.a76.general_catalogs.fractions.warning_fractions.models import WarningFraction
from api.v1.modules.a76.app_settings.service import AppSettingsService
from core.exceptions import ErrorCollector

from api.v1.modules.a76.invoices.common.common_validators import validate_invoice_items_decimals

def pre_validators(db: Session, invoice: InvoiceHeader, tenant_id: str, company_id: str,  errors: ErrorCollector):
    if invoice.status == InvoiceStatus.PROCESSED:
        errors.add_error(
            "status",
            "La factura ya fue procesada y no puede volver a actualizarse. Desactualícela primero.",
            solution=["Use el botón 'Desactualizar' antes de volver a procesar la factura."],
            code="ALREADY_PROCESSED",
            value=invoice.status,
        )
        errors.raise_if_errors()
        return

    if not invoice.invoice_date:
        errors.add_required_error("invoice_date")
    
    if not invoice.document_type:
        errors.add_required_error("document_type")
        
    if not invoice.compliance_mx.provider_id:
        errors.add_required_error("compliance_mx.provider_id")
    
    if not invoice.compliance_mx.sold_to_id:
        errors.add_required_error("compliance_mx.sold_to_id")  
        
    if not invoice.compliance_mx.shipped_to_id:
        errors.add_required_error("compliance_mx.shipped_to_id")
              
    if not invoice.compliance_mx.customs_broker_id:
        errors.add_required_error("compliance_mx.customs_broker_id")    
            
    # Validación de estatus de pedimento (CERRADO / PAGADO)
    if invoice.compliance_mx and invoice.compliance_mx.pedimento:
        ped = invoice.compliance_mx.pedimento
        if ped.pedimento_dates and ped.pedimento_dates.payment_date:
            from datetime import datetime
            today = datetime.now().date()
            pay_date = ped.pedimento_dates.payment_date.date()
            
            # Obtener parámetros de seguridad
            settings = AppSettingsService.get_resolved_settings(db, int(tenant_id), int(company_id))
            # Revisar actseguridad en ssisgen o qsisgen (según el sistema origen)
            gen_params = settings.get("ssisgen", {})
            if not gen_params:
                gen_params = settings.get("qsisgen", {})
            
            act_seguridad = int(gen_params.get("actseguridad", 1))
            
            # Si la fecha es futura (> hoy) o si la seguridad está desactivada (0), permitimos con advertencia
            if pay_date > today or act_seguridad == 0:
                pass # Permitir la actualización, el proceso continuará
            else:
                errors.add_error(
                    field="compliance_mx.pedimento",
                    message=f"No se puede procesar la factura porque el pedimento {ped.pedimento_number} ya se encuentra pagado el {pay_date}.",
                    solution=["Si requiere hacer cambios, desactive 'Solicitar Autorización para Actualizar Facturas' en la configuración general o rectifique el pedimento."],
                    code="PEDIMENTO_ALREADY_PAID"
                )
                errors.raise_if_errors()
    
    
    if not invoice.financials.exchange_rate or invoice.financials.exchange_rate <= 0:
        errors.add_range_error(
            "financials.exchange_rate",
            min_value=0.0001,
        )
       
    if not invoice.financials.currency:
        errors.add_required_error("El Tipo de Moneda esta vacio no se puede actualizar")        
    elif invoice.financials.currency == "manual" and not invoice.financials.currency_type:
        errors.add_required_error("financials.currency_type")
        
    # 3.- Validacion que deber de existir un pedimento cuando es requerido
    if not invoice.compliance_mx.is_pedimento_pending and not invoice.compliance_mx.pedimento_id:
        errors.add_required_error("compliance_mx.pedimento_number")
        
    # 4.- Verificacion de que existan partidas para la factura, si no hay partidas no se puede procesar    
    item_count = (
        db.query(func.count(LineItem.id))
        .filter(
            LineItem.invoice_id == invoice.id,
            LineItem.tenant_id == invoice.tenant_id,
            LineItem.company_id == invoice.company_id,
        )
        .scalar()
    )
    if item_count == 0:
        errors.add_error(
            field="items",
            message="La factura no tiene partidas capturadas.",
            solution=["Capture al menos una partida antes de procesar la factura."],
            code="NO_ITEMS_FOUND",
        )
        
    # Advertencias para las fracciones y su horario
    lines = (
        db.query(LineItem)
        .options(
            joinedload(LineItem.unit_of_measure_info),
            joinedload(LineItem.quantity),
            joinedload(LineItem.part_info).joinedload(Part.unit_of_measure_info)
        )
        .filter(
            LineItem.invoice_id == invoice.id,
            LineItem.tenant_id == tenant_id,
            LineItem.company_id == company_id,
        )
        .all()
    )
    
    # Validar decimales en piezas (Parámetro validadecencant)
    validate_invoice_items_decimals(db, lines, int(tenant_id), int(company_id), errors)

    fractions = {line.customs.fraction for line in lines if line.customs.fraction}
    if fractions:
        warned_fractions = {
            row.fraction
            for row in db.query(WarningFraction.fraction)
            .filter(WarningFraction.fraction.in_(fractions), WarningFraction.tenant_id == tenant_id)
            .all()
        }
        for line in lines:
            if line.customs.fraction in warned_fractions:
                errors.add_warning(
                    field="fraction",
                    message="Advertencia: Esta mercancía, sólo podrá entrar al territorio nacional por las aduanas del país, de lunes a sábado de 8:00 a 13:00 hrs. Ley 10, 18, LIGIE 1, Capítulo 87, RGCE 4.5.31., Anexo 4.",
                    solution=[""],
                    code="WARNING_FRACTION",
                )
                
    return lines
    
            
        
        
        
        
        
    