"""
Capa de servicio para lógica de negocio de líneas de activos fijos (FA Item Lines)
"""

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 FaLineItemCreateDTO, FaLineItemResponseDTO, FaLineItemUpdateDTO
from .models import FaLineItem

logger = logging.getLogger(__name__)


class FaLineItemService:
    """Servicio para gestión de líneas 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[FaLineItem], int]:
        """
        Obtener todas las líneas de activos fijos con paginación y filtros
        """
        query = db.query(FaLineItem).filter(
            FaLineItem.tenant_id == tenant_id, FaLineItem.company_id == company_id
        )

        if filters:
            if filters.get("asset_number"):
                query = query.filter(
                    FaLineItem.asset_number.ilike(f"%{filters['asset_number']}%")
                )
            if filters.get("invoice_type_asset"):
                query = query.filter(
                    FaLineItem.invoice_type_asset == filters["invoice_type_asset"]
                )
            if filters.get("own_equipment") is not None:
                query = query.filter(
                    FaLineItem.own_equipment == filters["own_equipment"]
                )
            if filters.get("discharge") is not None:
                query = query.filter(FaLineItem.discharge == filters["discharge"])

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

        return items, total

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

    @staticmethod
    def get_by_line_item_id(
        db: Session, line_item_id: int, tenant_id: int, company_id: int
    ) -> Optional[FaLineItem]:
        """Obtener una línea de activo fijo por line_item_id de a76"""
        return (
            db.query(FaLineItem)
            .filter(
                FaLineItem.id == line_item_id,
                FaLineItem.tenant_id == tenant_id,
                FaLineItem.company_id == company_id,
            )
            .first()
        )

    @staticmethod
    def create(
        db: Session,
        fa_line_item_data: FaLineItemCreateDTO,
        tenant_id: int,
        company_id: int,
    ) -> FaLineItem:
        """Crear una nueva línea de activo fijo"""
        try:
            # Verificar que la línea base existe en a76.item_lines
            from api.v1.modules.a76.items.models import LineItem

            base_line_item = (
                db.query(LineItem)
                .filter(
                    LineItem.id == fa_line_item_data.line_item_id,
                    LineItem.tenant_id == tenant_id,
                    LineItem.company_id == company_id,
                )
                .first()
            )

            if not base_line_item:
                raise HTTPException(
                    status_code=404,
                    detail=f"Base line item with id {fa_line_item_data.line_item_id} not found",
                )

            # Verificar si ya existe una línea FA para esta línea base
            existing_fa = (
                db.query(FaLineItem)
                .filter(
                    FaLineItem.id == fa_line_item_data.line_item_id,
                    FaLineItem.tenant_id == tenant_id,
                    FaLineItem.company_id == company_id,
                )
                .first()
            )

            if existing_fa:
                raise HTTPException(
                    status_code=400,
                    detail=f"FA line item already exists for line_item_id {fa_line_item_data.line_item_id}",
                )

            # Crear nueva línea FA
            fa_line_item = FaLineItem(
                id=fa_line_item_data.line_item_id,  # Usa el mismo ID que la línea base
                tenant_id=tenant_id,
                company_id=company_id,
                asset_number=fa_line_item_data.asset_number,
                asset_photo=fa_line_item_data.asset_photo,
                equipment_message=fa_line_item_data.equipment_message,
                invoice_type_asset=fa_line_item_data.invoice_type_asset,
                return_import_invoice=fa_line_item_data.return_import_invoice,
                return_import_date=fa_line_item_data.return_import_date,
                movement_type_import=fa_line_item_data.movement_type_import,
                search_invoice=fa_line_item_data.search_invoice,
                search_line=fa_line_item_data.search_line,
                search_type=fa_line_item_data.search_type,
                discharge=fa_line_item_data.discharge,
                own_equipment=fa_line_item_data.own_equipment,
                omit_annex31=fa_line_item_data.omit_annex31,
            )

            db.add(fa_line_item)
            db.commit()
            db.refresh(fa_line_item)

            logger.info(
                f"FA line item created: id={fa_line_item.id}, tenant={tenant_id}, company={company_id}"
            )

            return fa_line_item

        except IntegrityError as e:
            db.rollback()
            logger.error(f"IntegrityError creating FA line item: {str(e)}")
            raise HTTPException(
                status_code=400,
                detail="Error creating FA line item. Constraint violation.",
            )
        except HTTPException:
            db.rollback()
            raise
        except Exception as e:
            db.rollback()
            logger.error(f"Error creating FA line item: {str(e)}")
            raise HTTPException(
                status_code=500, detail="Internal server error creating FA line item"
            )

    @staticmethod
    def update(
        db: Session,
        fa_line_item_id: int,
        fa_line_item_data: FaLineItemUpdateDTO,
        tenant_id: int,
        company_id: int,
    ) -> FaLineItem:
        """Actualizar una línea de activo fijo existente"""
        try:
            fa_line_item = FaLineItemService.get_by_id(
                db, fa_line_item_id, tenant_id, company_id
            )

            if not fa_line_item:
                raise HTTPException(
                    status_code=404,
                    detail=f"FA line item with id {fa_line_item_id} not found",
                )

            # Actualizar solo los campos proporcionados
            update_data = fa_line_item_data.model_dump(exclude_unset=True)
            for field, value in update_data.items():
                setattr(fa_line_item, field, value)

            db.commit()
            db.refresh(fa_line_item)

            logger.info(
                f"FA line item updated: id={fa_line_item.id}, tenant={tenant_id}, company={company_id}"
            )

            return fa_line_item

        except HTTPException:
            db.rollback()
            raise
        except Exception as e:
            db.rollback()
            logger.error(f"Error updating FA line item: {str(e)}")
            raise HTTPException(
                status_code=500, detail="Internal server error updating FA line item"
            )

    @staticmethod
    def delete(
        db: Session, fa_line_item_id: int, tenant_id: int, company_id: int
    ) -> bool:
        """Eliminar una línea de activo fijo"""
        try:
            fa_line_item = FaLineItemService.get_by_id(
                db, fa_line_item_id, tenant_id, company_id
            )

            if not fa_line_item:
                raise HTTPException(
                    status_code=404,
                    detail=f"FA line item with id {fa_line_item_id} not found",
                )

            db.delete(fa_line_item)
            db.commit()

            logger.info(
                f"FA line item deleted: id={fa_line_item_id}, tenant={tenant_id}, company={company_id}"
            )

            return True

        except HTTPException:
            db.rollback()
            raise
        except Exception as e:
            db.rollback()
            logger.error(f"Error deleting FA line item: {str(e)}")
            raise HTTPException(
                status_code=500, detail="Internal server error deleting FA line item"
            )
