"""
Servicio de lógica de negocio para licencias
"""

import logging
from datetime import datetime, timezone
from typing import Optional

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

from .dto import (
    LicenseCreateDTO,
    LicenseResponseDTO,
    LicenseUpdateDTO,
    LicenseUsageResponseDTO,
)
from .models import License, LicensePlan, LicenseStatus, LicenseUsage

logger = logging.getLogger(__name__)


class LicenseService:
    """Servicio para gestión de licencias"""

    def __init__(self, db: Session):
        self.db = db

    def create_license(self, license_data: LicenseCreateDTO) -> LicenseResponseDTO:
        """
        Crea una nueva licencia para un tenant

        Args:
            license_data: Datos de la licencia

        Returns:
            LicenseResponseDTO

        Raises:
            HTTPException: Si el tenant ya tiene licencia o hay error
        """
        try:
            # Verificar que el tenant no tenga ya una licencia
            existing = (
                self.db.query(License)
                .filter(License.tenant_id == license_data.tenant_id)
                .first()
            )

            if existing:
                raise HTTPException(
                    status_code=400,
                    detail=f"Tenant {license_data.tenant_id} already has a license",
                )

            # Crear licencia
            db_license = License(
                tenant_id=license_data.tenant_id,
                plan=LicensePlan(license_data.plan.value),
                status=LicenseStatus.ACTIVE,
                max_users=license_data.max_users,
                max_storage_gb=license_data.max_storage_gb,
                max_monthly_operations=license_data.max_monthly_operations,
                feature_api_access=license_data.feature_api_access,
                feature_advanced_reports=license_data.feature_advanced_reports,
                feature_integrations=license_data.feature_integrations,
                feature_dedicated_support=license_data.feature_dedicated_support,
                starts_at=license_data.starts_at,
                expires_at=license_data.expires_at,
            )

            self.db.add(db_license)
            self.db.commit()
            self.db.refresh(db_license)

            return LicenseResponseDTO.model_validate(db_license)

        except IntegrityError as e:
            self.db.rollback()
            logger.error(f"IntegrityError creating license: {str(e)}")
            raise HTTPException(status_code=400, detail="Database integrity error")
        except HTTPException:
            raise
        except Exception as e:
            self.db.rollback()
            logger.error(f"Error creating license: {str(e)}")
            raise HTTPException(status_code=500, detail="Error creating license")

    def get_license_by_tenant(self, tenant_id: int) -> Optional[LicenseResponseDTO]:
        """
        Obtiene la licencia de un tenant

        Args:
            tenant_id: ID del tenant

        Returns:
            LicenseResponseDTO o None si no existe
        """
        license = self.db.query(License).filter(License.tenant_id == tenant_id).first()
        if not license:
            return None
        return LicenseResponseDTO.model_validate(license)

    def update_license(
        self, tenant_id: int, license_data: LicenseUpdateDTO
    ) -> Optional[LicenseResponseDTO]:
        """
        Actualiza una licencia

        Args:
            tenant_id: ID del tenant
            license_data: Datos a actualizar

        Returns:
            LicenseResponseDTO actualizado o None si no existe
        """
        license = self.db.query(License).filter(License.tenant_id == tenant_id).first()
        if not license:
            return None

        # Actualizar campos proporcionados
        update_data = license_data.model_dump(exclude_unset=True)
        for field, value in update_data.items():
            if field in ["plan", "status"]:
                # Convertir enums
                value = LicensePlan(value) if field == "plan" else LicenseStatus(value)
            setattr(license, field, value)

        try:
            self.db.commit()
            self.db.refresh(license)
            return LicenseResponseDTO.model_validate(license)
        except Exception as e:
            self.db.rollback()
            logger.error(f"Error updating license for tenant {tenant_id}: {str(e)}")
            raise HTTPException(status_code=500, detail="Error updating license")

    def validate_license(self, tenant_id: int) -> dict:
        """
        Valida si la licencia de un tenant está activa y vigente

        Args:
            tenant_id: ID del tenant

        Returns:
            Dict con información de validación
        """
        license = self.db.query(License).filter(License.tenant_id == tenant_id).first()

        if not license:
            return {
                "is_valid": False,
                "status": "not_found",
                "plan": None,
                "expires_at": None,
                "reason": "License not found",
            }

        now = datetime.now(timezone.utc)

        # Verificar estado
        if license.status != LicenseStatus.ACTIVE:
            return {
                "is_valid": False,
                "status": license.status.value,
                "plan": license.plan.value,
                "expires_at": license.expires_at,
                "reason": f"License status is {license.status.value}",
            }

        # Verificar vigencia
        if license.expires_at < now:
            # Auto-actualizar a expirada
            license.status = LicenseStatus.EXPIRED
            self.db.commit()

            return {
                "is_valid": False,
                "status": "expired",
                "plan": license.plan.value,
                "expires_at": license.expires_at,
                "reason": "License has expired",
            }

        # Licencia válida
        return {
            "is_valid": True,
            "status": license.status.value,
            "plan": license.plan.value,
            "expires_at": license.expires_at,
            "reason": None,
        }

    def get_usage(self, tenant_id: int) -> Optional[LicenseUsageResponseDTO]:
        """
        Obtiene el uso actual de la licencia de un tenant

        Args:
            tenant_id: ID del tenant

        Returns:
            LicenseUsageResponseDTO o None
        """
        license = self.db.query(License).filter(License.tenant_id == tenant_id).first()
        if not license:
            return None

        # Obtener último registro de uso
        usage = (
            self.db.query(LicenseUsage)
            .filter(LicenseUsage.tenant_id == tenant_id)
            .order_by(LicenseUsage.created_at.desc())
            .first()
        )

        if not usage:
            # Crear registro inicial si no existe
            usage = LicenseUsage(
                tenant_id=tenant_id,
                period_start=datetime.now(timezone.utc),
                period_end=datetime.now(timezone.utc),
                active_users=0,
                storage_used_gb=0,
                operations_count=0,
                api_calls_count=0,
            )

        # Calcular porcentajes
        users_usage = (
            (usage.active_users / license.max_users * 100)
            if license.max_users > 0
            else 0
        )
        storage_usage = (
            (usage.storage_used_gb / license.max_storage_gb * 100)
            if license.max_storage_gb > 0
            else 0
        )
        operations_usage = (
            (usage.operations_count / license.max_monthly_operations * 100)
            if license.max_monthly_operations > 0
            else 0
        )

        return LicenseUsageResponseDTO(
            tenant_id=tenant_id,
            period_start=usage.period_start,
            period_end=usage.period_end,
            active_users=usage.active_users,
            storage_used_gb=usage.storage_used_gb,
            operations_count=usage.operations_count,
            api_calls_count=usage.api_calls_count,
            max_users=license.max_users,
            max_storage_gb=license.max_storage_gb,
            max_monthly_operations=license.max_monthly_operations,
            users_usage_percent=round(users_usage, 2),
            storage_usage_percent=round(storage_usage, 2),
            operations_usage_percent=round(operations_usage, 2),
        )
