from typing import List, Optional, Tuple, Dict, Any
from sqlalchemy.orm import Session
from sqlalchemy.exc import IntegrityError
from fastapi import HTTPException
import logging
from decimal import Decimal

from .models import USTariffFraction
from .dto import USTariffFractionCreateDTO, USTariffFractionUpdateDTO

logger = logging.getLogger(__name__)


class USTariffFractionService:
    """Service para gestionar fracciones arancelarias americanas"""

    @staticmethod
    def get_all(
        db: Session,
        tenant_id: int,
        company_id: int,
        skip: int = 0,
        limit: int = 100,
        filters: Optional[Dict[str, Any]] = None,
    ) -> Tuple[List[USTariffFraction], int]:
        """Obtiene todas las fracciones locales con filtros opcionales."""
        query = db.query(USTariffFraction).filter(
            USTariffFraction.tenant_id == tenant_id,
            USTariffFraction.company_id == company_id,
        )

        # Aplicar filtros
        if filters:
            # Si hay un filtro 'search', buscar en múltiples campos
            if filters.get("search"):
                search_term = f"%{filters['search']}%"
                query = query.filter(
                    USTariffFraction.code.ilike(search_term) |
                    USTariffFraction.description.ilike(search_term) |
                    USTariffFraction.prefix.ilike(search_term)
                )

        total = query.count()
        items = query.order_by(USTariffFraction.code).offset(skip).limit(limit).all()

        return items, total

        return items, total

    @staticmethod
    def get_by_id(
        db: Session, fraction_id: int, tenant_id: int, company_id: int
    ) -> Optional[USTariffFraction]:
        """
        Obtiene por ID local.
        """
        return (
            db.query(USTariffFraction)
            .filter(
                USTariffFraction.id == fraction_id,
                USTariffFraction.tenant_id == tenant_id,
                USTariffFraction.company_id == company_id,
            )
            .first()
        )

    @staticmethod
    def create(
        db: Session,
        fraction_data: USTariffFractionCreateDTO,
        tenant_id: int,
        company_id: int,
    ) -> USTariffFraction:
        try:
            db_fraction = USTariffFraction(
                tenant_id=tenant_id,
                company_id=company_id,
                **fraction_data.model_dump(),
            )
            db.add(db_fraction)
            db.commit()
            db.refresh(db_fraction)
            return db_fraction
        except IntegrityError as e:
            db.rollback()
            logger.error(f"Error creando fracción americana: {e}")
            raise HTTPException(
                status_code=400,
                detail="Ya existe una fracción americana con este código",
            )

    @staticmethod
    def update(
        db: Session,
        fraction_id: int,
        tenant_id: int,
        fraction_data: USTariffFractionUpdateDTO,
        company_id: int,
    ) -> Optional[USTariffFraction]:
        db_fraction = USTariffFractionService.get_by_id(
            db, fraction_id, tenant_id, company_id
        )
        if not db_fraction:
            return None

        update_data = fraction_data.model_dump(exclude_unset=True)
        for field, value in update_data.items():
            setattr(db_fraction, field, value)

        db.commit()
        db.refresh(db_fraction)
        return db_fraction

    @staticmethod
    def delete(
        db: Session, fraction_id: int, tenant_id: int, company_id: int
    ) -> bool:
        db_fraction = USTariffFractionService.get_by_id(
            db, fraction_id, tenant_id, company_id
        )
        if not db_fraction:
            return False

        db.delete(db_fraction)
        db.commit()
        return True
