"""
Capa de servicio para lógica de negocio de clases de activos fijos (FA)
"""

import logging
from typing import Any, Dict, List, Optional

from fastapi import HTTPException
from sqlalchemy import and_
from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm import Session

from .dto import FAClassCreateDTO, FAClassResponseDTO, FAClassUpdateDTO
from .models import QClasses

logger = logging.getLogger(__name__)


class FAClassService:
    """Servicio para gestión de clases de activos fijos"""

    @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[QClasses], int]:
        """
        Obtener todas las clases de activos fijos con paginación y filtros
        """
        query = db.query(QClasses).filter(
            QClasses.tenant_id == tenant_id, QClasses.company_id == company_id
        )

        if filters:
            if filters.get("class_id"):
                query = query.filter(QClasses.class_id == filters["class_id"])
            if filters.get("fda_code"):
                query = query.filter(
                    QClasses.fda_code.ilike(f"%{filters['fda_code']}%")
                )
            if filters.get("class_enabled") is not None:
                query = query.filter(
                    QClasses.class_enabled == filters["class_enabled"]
                )

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

        return items, total

    @staticmethod
    def get_by_id(
        db: Session, fa_class_id: int, tenant_id: int, company_id: int
    ) -> Optional[QClasses]:
        """Obtener una clase de activo fijo por ID"""
        return (
            db.query(QClasses)
            .filter(
                QClasses.id == fa_class_id,
                QClasses.tenant_id == tenant_id,
                QClasses.company_id == company_id,
            )
            .first()
        )

    @staticmethod
    def get_by_class_id(
        db: Session, class_id: int, tenant_id: int, company_id: int
    ) -> Optional[QClasses]:
        """Obtener una clase de activo fijo por class_id de a76"""
        return (
            db.query(QClasses)
            .filter(
                QClasses.class_id == class_id,
                QClasses.tenant_id == tenant_id,
                QClasses.company_id == company_id,
            )
            .first()
        )

    @staticmethod
    def create(
        db: Session, fa_class_data: FAClassCreateDTO, tenant_id: int, company_id: int
    ) -> QClasses:
        """Crear una nueva clase de activo fijo"""
        try:
            # Verificar que la clase base existe en a76.classes
            from api.v1.modules.a76.classes.models import Class
            
            base_class = (
                db.query(Class)
                .filter(
                    Class.id == fa_class_data.class_id,
                    Class.tenant_id == tenant_id,
                    Class.company_id == company_id,
                )
                .first()
            )
            
            if not base_class:
                raise HTTPException(
                    status_code=404,
                    detail=f"Base class with id {fa_class_data.class_id} not found"
                )

            # Verificar que no exista ya una clase de activo fijo para esta clase base
            existing = FAClassService.get_by_class_id(
                db, fa_class_data.class_id, tenant_id, company_id
            )
            if existing:
                raise HTTPException(
                    status_code=400,
                    detail=f"Fixed asset class already exists for class_id {fa_class_data.class_id}"
                )

            data_dict = fa_class_data.model_dump()
            
            new_fa_class = QClasses(
                **data_dict,
                tenant_id=tenant_id,
                company_id=company_id,
            )
            
            db.add(new_fa_class)
            db.commit()
            db.refresh(new_fa_class)
            
            return new_fa_class
            
        except IntegrityError as e:
            db.rollback()
            logger.error(f"IntegrityError creating fixed asset class: {str(e)}")
            raise HTTPException(
                status_code=400,
                detail=f"Database constraint violation: {str(e.orig)}"
            )
        except HTTPException:
            raise
        except Exception as e:
            db.rollback()
            logger.error(f"Error creating fixed asset class: {str(e)}")
            raise HTTPException(status_code=500, detail=str(e))

    @staticmethod
    def update(
        db: Session,
        fa_class_id: int,
        tenant_id: int,
        fa_class_data: FAClassUpdateDTO,
        company_id: int,
    ) -> QClasses:
        """Actualizar una clase de activo fijo"""
        fa_class = FAClassService.get_by_id(db, fa_class_id, tenant_id, company_id)
        
        if not fa_class:
            raise HTTPException(
                status_code=404,
                detail=f"Fixed asset class {fa_class_id} not found"
            )

        try:
            update_data = fa_class_data.model_dump(exclude_unset=True)
            
            for key, value in update_data.items():
                setattr(fa_class, key, value)
            
            db.commit()
            db.refresh(fa_class)
            
            return fa_class
            
        except IntegrityError as e:
            db.rollback()
            logger.error(f"IntegrityError updating fixed asset class: {str(e)}")
            raise HTTPException(
                status_code=400,
                detail=f"Database constraint violation: {str(e.orig)}"
            )
        except Exception as e:
            db.rollback()
            logger.error(f"Error updating fixed asset class: {str(e)}")
            raise HTTPException(status_code=500, detail=str(e))

    @staticmethod
    def delete(
        db: Session, fa_class_id: int, tenant_id: int, company_id: int
    ) -> None:
        """Eliminar una clase de activo fijo"""
        fa_class = FAClassService.get_by_id(db, fa_class_id, tenant_id, company_id)
        
        if not fa_class:
            raise HTTPException(
                status_code=404,
                detail=f"Fixed asset class {fa_class_id} not found"
            )

        try:
            db.delete(fa_class)
            db.commit()
            
        except IntegrityError as e:
            db.rollback()
            logger.error(f"IntegrityError deleting fixed asset class: {str(e)}")
            raise HTTPException(
                status_code=400,
                detail="Cannot delete: Fixed asset class is referenced by other records"
            )
        except Exception as e:
            db.rollback()
            logger.error(f"Error deleting fixed asset class: {str(e)}")
            raise HTTPException(status_code=500, detail=str(e))
