"""
Capa de servicio para lógica de negocio de DODA
"""

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

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

from .dto import (
    DodaCreateDTO,
    DodaResponseDTO,
    DodaUpdateDTO,
    DodaContainerCreateDTO,
    DodaContainerUpdateDTO,
    DodaAmericanPedimentoCreateDTO,
    DodaAmericanPedimentoUpdateDTO,
    DodaPedimentoCreateDTO,
    DodaPedimentoUpdateDTO,
)
from .models import (
    Doda,
    DodaContainer,
    DodaContainerSeal,
    DodaAmericanPedimento,
    DodaPedimento,
)

logger = logging.getLogger(__name__)


class DodaService:
    """Servicio para gestión de DODA"""

    @staticmethod
    def get_all(
        db: Session,
        tenant_id: int,
        company_id: int,
        skip: int = 0,
        limit: int = 50,
        filters: Optional[Dict[str, Any]] = None,
    ) -> Tuple[List[Doda], int]:
        """Get all DODAs with pagination"""
        query = db.query(Doda).filter(
            Doda.tenant_id == tenant_id,
            Doda.company_id == company_id
        )

        if filters:
            if filters.get("integration_number"):
                query = query.filter(
                    Doda.integration_number.ilike(
                        f"%{filters['integration_number']}%")
                )
            if filters.get("status"):
                query = query.filter(
                    Doda.status.ilike(f"%{filters['status']}%"))
            if filters.get("patent"):
                query = query.filter(
                    Doda.patent.ilike(f"%{filters['patent']}%"))
            if filters.get("operation_type"):
                query = query.filter(
                    Doda.operation_type == filters["operation_type"])

        total = query.count()
        dodas = query.offset(skip).limit(limit).all()
        return dodas, total

    @staticmethod
    def get_by_id(
        db: Session, id: int, tenant_id: int, company_id: int
    ) -> Optional[Doda]:
        """Get DODA by ID"""
        return db.query(Doda).filter(
            Doda.id == id,
            Doda.tenant_id == tenant_id,
            Doda.company_id == company_id
        ).first()

    @staticmethod
    def create(
        db: Session, doda_data: DodaCreateDTO, tenant_id: int, company_id: int
    ) -> Doda:
        """Create a new DODA"""
        try:
            db_doda = Doda(
                **doda_data.model_dump(exclude_unset=True),
                tenant_id=tenant_id,
                company_id=company_id
            )
            db.add(db_doda)
            db.commit()
            db.refresh(db_doda)
            return db_doda
        except IntegrityError as e:
            db.rollback()
            logger.error(f"IntegrityError creating DODA: {str(e)}")
            raise HTTPException(status_code=400, detail="Error creating DODA")
        except Exception as e:
            db.rollback()
            logger.error(f"Error creating DODA: {str(e)}")
            raise HTTPException(status_code=500, detail="Error creating DODA")

    @staticmethod
    def update(
        db: Session, id: int, tenant_id: int, doda_data: DodaUpdateDTO, company_id: int
    ) -> Optional[Doda]:
        """Update a DODA"""
        try:
            db_doda = DodaService.get_by_id(db, id, tenant_id, company_id)
            if not db_doda:
                return None

            for key, value in doda_data.model_dump(exclude_unset=True).items():
                setattr(db_doda, key, value)

            db.commit()
            db.refresh(db_doda)
            return db_doda
        except IntegrityError as e:
            db.rollback()
            logger.error(f"IntegrityError updating DODA: {str(e)}")
            raise HTTPException(status_code=400, detail="Error updating DODA")
        except Exception as e:
            db.rollback()
            logger.error(f"Error updating DODA: {str(e)}")
            raise HTTPException(status_code=500, detail="Error updating DODA")

    @staticmethod
    def delete(
        db: Session, id: int, tenant_id: int, company_id: int
    ) -> bool:
        """Delete a DODA"""
        db_doda = DodaService.get_by_id(db, id, tenant_id, company_id)
        if not db_doda:
            return False

        try:
            db.delete(db_doda)
            db.commit()
            return True
        except IntegrityError as e:
            db.rollback()
            logger.error(f"Error de integridad al eliminar DODA {id}: {str(e)}")
            raise HTTPException(
                status_code=400,
                detail="No se puede eliminar este DODA porque tiene registros relacionados. Primero debe eliminar o reasignar esos registros."
            )
        except Exception as e:
            db.rollback()
            logger.error(f"Error deleting DODA: {str(e)}")
            raise HTTPException(status_code=500, detail="Error deleting DODA")

    # ============ CONTAINERS ============
    @staticmethod
    def add_container(
        db: Session, doda_id: int, container_data: DodaContainerCreateDTO
    ) -> Optional[DodaContainer]:
        """Add a container to a DODA"""
        try:
            doda = db.query(Doda).filter(Doda.id == doda_id).first()
            if not doda:
                return None

            # Get max line number
            max_line = (
                db.query(DodaContainer)
                .filter(DodaContainer.doda_id == doda_id)
                .count()
            )

            db_container = DodaContainer(
                doda_id=doda_id,
                container_line=max_line + 1,
                **{
                    k: v
                    for k, v in container_data.model_dump(exclude_unset=True).items()
                    if k != "seals_detail"
                },
            )
            db.add(db_container)
            db.commit()
            db.refresh(db_container)
            return db_container
        except Exception as e:
            db.rollback()
            logger.error(f"Error adding container: {str(e)}")
            raise HTTPException(
                status_code=500, detail="Error adding container")

    @staticmethod
    def update_container(
        db: Session,
        doda_id: int,
        container_line: int,
        container_data: DodaContainerUpdateDTO,
    ) -> Optional[DodaContainer]:
        """Update a container"""
        try:
            db_container = (
                db.query(DodaContainer)
                .filter(
                    DodaContainer.doda_id == doda_id,
                    DodaContainer.container_line == container_line,
                )
                .first()
            )
            if not db_container:
                return None

            for key, value in container_data.model_dump(exclude_unset=True).items():
                setattr(db_container, key, value)

            db.commit()
            db.refresh(db_container)
            return db_container
        except Exception as e:
            db.rollback()
            logger.error(f"Error updating container: {str(e)}")
            raise HTTPException(
                status_code=500, detail="Error updating container")

    @staticmethod
    def get_containers(db: Session, doda_id: int) -> List[DodaContainer]:
        """Get all containers for a DODA"""
        return (
            db.query(DodaContainer)
            .filter(DodaContainer.doda_id == doda_id)
            .all()
        )

    # ============ AMERICAN PEDIMENTOS ============
    @staticmethod
    def add_american_pedimento(
        db: Session, doda_id: int, pedimento_data: DodaAmericanPedimentoCreateDTO
    ) -> Optional[DodaAmericanPedimento]:
        """Add an American pedimento to a DODA"""
        try:
            doda = db.query(Doda).filter(Doda.id == doda_id).first()
            if not doda:
                return None

            max_line = (
                db.query(DodaAmericanPedimento)
                .filter(DodaAmericanPedimento.doda_id == doda_id)
                .count()
            )

            db_pedimento = DodaAmericanPedimento(
                doda_id=doda_id,
                american_pedimento_line=max_line + 1,
                **pedimento_data.model_dump(exclude_unset=True),
            )
            db.add(db_pedimento)
            db.commit()
            db.refresh(db_pedimento)
            return db_pedimento
        except Exception as e:
            db.rollback()
            logger.error(f"Error adding American pedimento: {str(e)}")
            raise HTTPException(
                status_code=500, detail="Error adding American pedimento"
            )

    @staticmethod
    def get_american_pedimentos(db: Session, doda_id: int) -> List[DodaAmericanPedimento]:
        """Get all American pedimentos for a DODA"""
        return (
            db.query(DodaAmericanPedimento)
            .filter(DodaAmericanPedimento.doda_id == doda_id)
            .all()
        )

    # ============ PEDIMENTOS ============
    @staticmethod
    def add_pedimento(
        db: Session, doda_id: int, pedimento_data: DodaPedimentoCreateDTO
    ) -> Optional[DodaPedimento]:
        """Add a pedimento to a DODA"""
        try:
            doda = db.query(Doda).filter(Doda.id == doda_id).first()
            if not doda:
                return None

            max_line = (
                db.query(DodaPedimento)
                .filter(DodaPedimento.doda_id == doda_id)
                .count()
            )

            db_pedimento = DodaPedimento(
                doda_id=doda_id,
                pedimento_line=max_line + 1,
                **pedimento_data.model_dump(exclude_unset=True),
            )
            db.add(db_pedimento)
            db.commit()
            db.refresh(db_pedimento)
            return db_pedimento
        except Exception as e:
            db.rollback()
            logger.error(f"Error adding pedimento: {str(e)}")
            raise HTTPException(
                status_code=500, detail="Error adding pedimento")

    @staticmethod
    def get_pedimentos(db: Session, doda_id: int) -> List[DodaPedimento]:
        """Get all pedimentos for a DODA"""
        return (
            db.query(DodaPedimento).filter(
                DodaPedimento.doda_id == doda_id).all()
        )
