import asyncio
from datetime import datetime
from typing import Optional, Tuple

from api.v1.modules.a76.general_catalogs.company.models import Company
from api.v1.modules.a76.general_catalogs.fractions.historical_tariff_fractions.models import HistoricalTariffFraction
from api.v1.modules.sitar.tlcs import TLCSService
from api.v1.modules.sitar.prosec import ProsecService
from api.v1.modules.sitar.fracciones import FraccionesService
from sqlalchemy.orm import Session
from sqlalchemy import exists
from core.exceptions import ErrorCollector

def search_historical_fraction(db: Session, fraction: str, country: str, fraction_type: str, sector: str, invoice_date: Optional[datetime], errors: Optional[ErrorCollector]) -> Tuple[Optional[str], float]:
    """Search for historical fraction data    
    This corresponds to BUSCA_FRACCION_HISTORICA in original Clarion code

    Returns:
        Tuple of (rate_im, adv_impo)
    """
    # Placeholder for historical search
    historical_exists = db.query(exists().where(HistoricalTariffFraction.historical_fraction == fraction)).scalar()
    if not historical_exists:       
        errors.add_error(
            field=f"fraction, country, fraction_type, sector",
            message=f"La fraccion {fraction}, con pais {country}, con preferencia {fraction_type} y sector {sector} no existe.",
            solution=["Revisar que si exista la preferencia para esta fracción en caso de ser historico, registrarlo en el catálogo de fracciones historicas."],
            code="HISTORICAL_FRACTION_NOT_FOUND",
        )
    else:
        historical_exists = db.query(HistoricalTariffFraction).filter(
            HistoricalTariffFraction.historical_fraction == fraction, 
            HistoricalTariffFraction.country == country,
            HistoricalTariffFraction.fraction_type == fraction_type,
            HistoricalTariffFraction.sector == sector,
            HistoricalTariffFraction.publication_date <= invoice_date,
            ).first()
                
    return historical_exists.import_tax_rate, historical_exists.import_tax_rate


def search_fraction_preference(
    db: Session,
    country: str,
    fraccion: str,
    fraction_type: str,    
    sector: Optional[str] = None,
    invoice_date: Optional[datetime] = None,
    errors: Optional[ErrorCollector] = None
) -> Tuple[Optional[str], float]:
    """Search fraction preference and return rate_im and adv_impo

    Args:
        country: Country code
        fraction_type: Type of fraction (e.g., 'TLCS', 'PROSEC')
        company: Company object with configuration
        fraccion: Tariff fraction code to search
        sector: Sector code (required for PROSEC searches)

    Returns:
        Tuple of (rate_im, adv_impo) where:
            - rate_im: Tax rate as string (e.g., "EXE", "5.0%")
            - adv_impo: Numeric ad valorem rate
    """
    rate_im = None
    adv_impo = 0.0
    fraccion_8 = fraccion[:8]

    country_group = "USA" if country == "MEX" else country

    """" TLCS Search """
    if fraction_type.upper() == "TLCS":
        try:
            # Get TLCS service instance
            tlcs_service = TLCSService.get_instance()

            # Fetch TLCS data using the service
            tlcs_data = asyncio.run(
                tlcs_service.search(fraccion=fraccion_8, pais=country_group, limit=100)
            )

            if not tlcs_data:
                rate_im, adv_impo = search_historical_fraction(db=db, fraction=fraccion_8, country=country, fraction_type=fraction_type, sector=sector, invoice_date=invoice_date, errors=errors)
            else:
                first_record = tlcs_data[0]
                rate_im = first_record.TASATXT
                adv_impo = float(first_record.TASA1NUM or 0.0)

        except Exception as e:
            print(f"Error fetching Fracciones data from SITAR API: {e}")

    """ ALADI Search """
    if fraction_type.upper() == "ALADI":
        rate_im, adv_impo = search_historical_fraction(db=db, fraction=fraccion_8, country=country, fraction_type=fraction_type, sector=sector, invoice_date=invoice_date, errors=errors)

    """ PROSEC Search """
    if fraction_type.upper() == "PROSEC":
        try:
            # Búsqueda en API de PROSEC (TARIFA_AS..sProsec)
            prosec_service = ProsecService.get_instance()

            # Buscar primero con ARTICULO = '4to'
            prosec_data = asyncio.run(
                prosec_service.search(
                    fraccion=fraccion_8, sector=sector, articulo="4to", limit=100
                )
            )

            # Si no se encuentra con '4to', buscar con '5to'
            if not prosec_data:
                prosec_data = asyncio.run(
                    prosec_service.search(
                        fraccion=fraccion_8, sector=sector, articulo="5to", limit=100
                    )
                )

            if not prosec_data:
                rate_im, adv_impo = search_historical_fraction(db=db, fraction=fraccion_8, country=country, fraction_type=fraction_type, sector=sector, invoice_date=invoice_date, errors=errors)
            else:
                first_record = prosec_data[0]
                rate_im = first_record.TASATXT
                adv_impo = float(first_record.TASANUM or 0.0)

        except Exception as e:
            print(f"Error fetching Fracciones data from SITAR API: {e}")

    """ General search fallback """
    if fraction_type.upper() == "GENERAL":
        # Búsqueda en API de Fracciones (sFracciones)
        try:
            fracciones_service = FraccionesService.get_instance()

            # Extraer fracción (primeros 8 caracteres) e nico (caracteres 9-10)
            nico = fraccion[8:10] if len(fraccion) >= 10 else None

            # Buscar por fracción e histórico
            fracciones_data = asyncio.run(
                fracciones_service.search(
                    fraccion=fraccion_8, nico=nico, limit=100
                )
            )

            if not fracciones_data:                
                rate_im, adv_impo = search_historical_fraction(db=db, fraction=fraccion_8, country=country, fraction_type=fraction_type, sector=sector, invoice_date=invoice_date, errors=errors)
            else:
                # Se encontraron registros, tomar el primero
                first_record = fracciones_data[0]
                rate_im = first_record.ADVIMPOTXT  # AdvImpoTxt                                
                adv_impo = float(first_record.ADVIMPONUM or 0.0)


        except Exception as e:
            print(f"Error fetching Fracciones data from SITAR API: {e}")

    return rate_im, adv_impo
