import secrets
import string
import uuid

from django.db import models
from django.utils import timezone

from clients.models import Client


def generate_license_key():
    alphabet = string.ascii_uppercase + string.digits
    segments = []
    for length in (3, 3, 3):
        seg = "".join(secrets.choice(alphabet) for _ in range(length))
        segments.append(seg)
    return "PRB-" + "-".join(segments)


DEFAULT_CAPABILITIES = {
    "cases_create": True,
    "cases_delete": True,
    "cases_duplicate": True,
    "cases_edit": True,
    "reports": True,
    "simulations": False,
    "ai_reports": False,
}

DEMO_CAPABILITIES = {
    "cases_create": False,
    "cases_delete": False,
    "cases_duplicate": False,
    "cases_edit": True,
    "reports": True,
    "simulations": True,
    "ai_reports": True,
}


class License(models.Model):
    class LicenseType(models.TextChoices):
        DEMO = "demo", "Demo"
        INDIVIDUAL = "individual", "Individual"
        ENTERPRISE = "enterprise", "Enterprise"

    class Status(models.TextChoices):
        ACTIVE = "active", "Activa"
        INACTIVE = "inactive", "Inactiva"
        EXPIRED = "expired", "Vencida"
        SUSPENDED = "suspendida", "Suspendida"

    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    license_key = models.CharField(
        "Código de licencia",
        max_length=30,
        unique=True,
        default=generate_license_key,
        editable=False,
    )
    client = models.ForeignKey(
        Client,
        on_delete=models.PROTECT,
        related_name="licenses",
        verbose_name="Cliente",
    )
    license_type = models.CharField(
        "Tipo de licencia",
        max_length=20,
        choices=LicenseType.choices,
        default=LicenseType.INDIVIDUAL,
    )
    status = models.CharField(
        "Estado",
        max_length=20,
        choices=Status.choices,
        default=Status.ACTIVE,
    )
    activated_at = models.DateTimeField("Fecha de activación", null=True, blank=True)
    expires_at = models.DateTimeField("Fecha de vencimiento", null=True, blank=True)
    max_users = models.PositiveIntegerField(
        "Cantidad máxima de usuarios",
        default=1,
        help_text="Número máximo de usuarios permitidos por esta licencia",
    )
    demo_mode = models.BooleanField(
        "Modo DEMO",
        default=False,
        help_text="Activa el modo demostración. Controlado exclusivamente desde el Administrador de Licencias.",
    )
    notes = models.TextField("Observaciones", blank=True, default="")
    created_at = models.DateTimeField("Fecha de creación", auto_now_add=True)
    updated_at = models.DateTimeField("Fecha de actualización", auto_now=True)

    class Meta:
        verbose_name = "licencia"
        verbose_name_plural = "licencias"
        ordering = ["-created_at"]

    def __str__(self):
        return f"{self.license_key} ({self.get_license_type_display()})"

    def clean(self):
        from django.core.exceptions import ValidationError
        if self.license_type == self.LicenseType.DEMO and not self.demo_mode:
            raise ValidationError(
                {"demo_mode": "Las licencias DEMO deben tener el Modo DEMO activado."}
            )
        if self.license_type != self.LicenseType.DEMO and self.demo_mode:
            raise ValidationError(
                {"demo_mode": "El Modo DEMO solo puede activarse en licencias de tipo DEMO."}
            )

    def get_capabilities(self):
        caps = LicenseCapability.objects.filter(license=self)
        if caps.exists():
            return {c.key: c.value for c in caps}
        defaults = DEMO_CAPABILITIES if self.license_type == self.LicenseType.DEMO else DEFAULT_CAPABILITIES
        return dict(defaults)

    def is_valid(self):
        now = timezone.now()
        if self.status != self.Status.ACTIVE:
            return False
        if self.expires_at and self.expires_at < now:
            return False
        return True

    def activate(self):
        self.status = self.Status.ACTIVE
        if not self.activated_at:
            self.activated_at = timezone.now()
        self.save(update_fields=["status", "activated_at", "updated_at"])

    def deactivate(self):
        self.status = self.Status.INACTIVE
        self.save(update_fields=["status", "updated_at"])

    def suspend(self):
        self.status = self.Status.SUSPENDED
        self.save(update_fields=["status", "updated_at"])

    def mark_expired(self):
        self.status = self.Status.EXPIRED
        self.save(update_fields=["status", "updated_at"])


class Installation(models.Model):
    class Status(models.TextChoices):
        ACTIVE = "active", "Activa"
        INACTIVE = "inactive", "Inactiva"

    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    installation_id = models.CharField(
        "Installation ID",
        max_length=100,
        unique=True,
        editable=False,
        help_text="Identificador único de la instalación de Probalis",
    )
    installation_secret = models.CharField(
        "Installation Secret",
        max_length=128,
        help_text="Clave secreta para autenticación de la instalación",
    )
    license = models.ForeignKey(
        License,
        on_delete=models.PROTECT,
        related_name="installations",
        verbose_name="Licencia",
    )
    domain = models.CharField(
        "Dominio autorizado",
        max_length=253,
        help_text="Dominio autorizado para esta instalación",
    )
    status = models.CharField(
        "Estado",
        max_length=20,
        choices=Status.choices,
        default=Status.ACTIVE,
    )
    registered_at = models.DateTimeField("Fecha de registro", auto_now_add=True)
    last_validated_at = models.DateTimeField(
        "Última validación",
        null=True,
        blank=True,
    )
    probalis_version = models.CharField(
        "Versión de Probalis",
        max_length=30,
        blank=True,
        default="",
    )
    ip_address = models.GenericIPAddressField(
        "IP de origen",
        null=True,
        blank=True,
    )
    notes = models.TextField("Observaciones", blank=True, default="")

    class Meta:
        verbose_name = "instalación"
        verbose_name_plural = "instalaciones"
        ordering = ["-registered_at"]

    def __str__(self):
        return f"{self.installation_id} ({self.domain})"

    def save(self, *args, **kwargs):
        if not self.installation_secret:
            self.installation_secret = secrets.token_hex(32)
        super().save(*args, **kwargs)


class LicenseCapability(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    license = models.ForeignKey(
        License,
        on_delete=models.CASCADE,
        related_name="capabilities",
        verbose_name="Licencia",
    )
    key = models.CharField(
        "Capacidad",
        max_length=50,
        help_text="Identificador de la capacidad (ej: cases_create, reports)",
    )
    value = models.BooleanField("Habilitada", default=True)

    class Meta:
        verbose_name = "capacidad"
        verbose_name_plural = "capacidades"
        unique_together = ["license", "key"]
        ordering = ["key"]

    def __str__(self):
        return f"{self.key}={'on' if self.value else 'off'} ({self.license.license_key})"


class LicenseValidation(models.Model):
    class Result(models.TextChoices):
        SUCCESS = "success", "Exitoso"
        FAILURE = "failure", "Fallido"

    class RejectionReason(models.TextChoices):
        LICENSE_NOT_FOUND = "license_not_found", "Licencia no encontrada"
        INSTALLATION_NOT_FOUND = "installation_not_found", "Instalación no encontrada"
        DOMAIN_MISMATCH = "domain_mismatch", "Dominio no coincide"
        LICENSE_EXPIRED = "license_expired", "Licencia vencida"
        LICENSE_INACTIVE = "license_inactive", "Licencia inactiva"
        INSTALLATION_INACTIVE = "installation_inactive", "Instalación inactiva"
        INVALID_CREDENTIALS = "invalid_credentials", "Credenciales inválidas"

    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    installation = models.ForeignKey(
        Installation,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="validations",
        verbose_name="Instalación",
    )
    validated_at = models.DateTimeField("Fecha/hora de validación", auto_now_add=True)
    result = models.CharField(
        "Resultado",
        max_length=20,
        choices=Result.choices,
    )
    rejection_reason = models.CharField(
        "Motivo de rechazo",
        max_length=50,
        choices=RejectionReason.choices,
        blank=True,
        default="",
    )
    ip_address = models.GenericIPAddressField("IP de origen", null=True, blank=True)
    probalis_version = models.CharField("Versión de Probalis", max_length=30, blank=True, default="")
    license_key_used = models.CharField("Código de licencia consultado", max_length=30, blank=True, default="")
    installation_id_used = models.CharField("Installation ID consultado", max_length=100, blank=True, default="")
    domain_used = models.CharField("Dominio consultado", max_length=253, blank=True, default="")
    user_agent = models.CharField("User-Agent", max_length=500, blank=True, default="")

    class Meta:
        verbose_name = "validación"
        verbose_name_plural = "validaciones"
        ordering = ["-validated_at"]

    def __str__(self):
        return f"{self.validated_at} - {self.get_result_display()}"
