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

from .models import ClassificationConcept
from .dto import ClassificationConceptCreate, ClassificationConceptUpdate

logger = logging.getLogger(__name__)


class ClassificationConceptService:
    @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[ClassificationConcept], int]:
        query = db.query(ClassificationConcept).filter(
            ClassificationConcept.tenant_id == tenant_id,
            ClassificationConcept.company_id == company_id
        )

        if filters:
            if filters.get("classification"):
                query = query.filter(ClassificationConcept.classification.ilike(f"%{filters['classification']}%"))
            if filters.get("description"):
                query = query.filter(ClassificationConcept.description.ilike(f"%{filters['description']}%"))

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

        return items, total

    @staticmethod
    def get_by_id(
        db: Session, id: int, tenant_id: int, company_id: int
    ) -> Optional[ClassificationConcept]:
        return db.query(ClassificationConcept).filter(
            ClassificationConcept.id == id,
            ClassificationConcept.tenant_id == tenant_id,
            ClassificationConcept.company_id == company_id
        ).first()

    @staticmethod
    def create(
        db: Session, data: ClassificationConceptCreate, tenant_id: int, company_id: int
    ) -> ClassificationConcept:
        db_obj = ClassificationConcept(
            **data.model_dump(),
            tenant_id=tenant_id,
            company_id=company_id
        )
        db.add(db_obj)
        db.commit()
        db.refresh(db_obj)
        return db_obj

    @staticmethod
    def update(
        db: Session, id: int, tenant_id: int, data: ClassificationConceptUpdate, company_id: int
    ) -> Optional[ClassificationConcept]:
        db_obj = ClassificationConceptService.get_by_id(
            db, id, tenant_id, company_id)
        if not db_obj:
            return None

        update_dict = data.model_dump(exclude_unset=True)
        for key, value in update_dict.items():
            setattr(db_obj, key, value)

        db.commit()
        db.refresh(db_obj)
        return db_obj

    @staticmethod
    def delete(
        db: Session, id: int, tenant_id: int, company_id: int
    ) -> bool:
        db_obj = ClassificationConceptService.get_by_id(
            db, id, tenant_id, company_id)
        if not db_obj:
            return False

        try:
            db.delete(db_obj)
            db.commit()
            return True
        except IntegrityError as e:
            db.rollback()
            logger.error(f"Error de integridad al eliminar clasificación de concepto {id}: {str(e)}")
            raise HTTPException(
                status_code=400,
                detail="No se puede eliminar esta clasificación porque tiene registros relacionados (pedimentos, facturas, etc.). Primero debe eliminar o reasignar esos registros."
            )
