from django.db import models

from core.models import Provider, TimeStampedModel


class Server(TimeStampedModel):
    class Status(models.TextChoices):
        PROVISIONING = "provisioning", "Em configuração"
        ACTIVE = "active", "Operacional"
        DEGRADED = "degraded", "Desempenho degradado"
        MAINTENANCE = "maintenance", "Em manutenção"
        INCIDENT = "incident", "Incidente"
        OFFLINE = "offline", "Offline"
        RETIRED = "retired", "Desativado"

    name = models.CharField("Nome", max_length=150, unique=True)
    provider = models.ForeignKey(Provider, on_delete=models.SET_NULL, null=True, blank=True, related_name="servers", verbose_name="Fornecedor")
    hostname = models.CharField("Hostname", max_length=253, blank=True)
    ip_address = models.GenericIPAddressField("Endereço IP", null=True, blank=True)
    location = models.CharField("Localização", max_length=120, blank=True)
    control_panel = models.CharField("Painel", max_length=80, blank=True, help_text="Ex.: cPanel, Plesk, DirectAdmin")
    panel_url = models.URLField("URL do painel", blank=True)
    account_reference = models.CharField("Referência no cofre", max_length=150, blank=True)
    status = models.CharField("Estado", max_length=20, choices=Status.choices, default=Status.ACTIVE)
    notes = models.TextField("Notas", blank=True)

    class Meta:
        verbose_name = "Servidor"
        verbose_name_plural = "Servidores"
        ordering = ["name"]

    def __str__(self):
        return self.name


class TechnicalAsset(TimeStampedModel):
    class AssetType(models.TextChoices):
        WEBSITE = "website", "Website"
        DATABASE = "database", "Base de dados"
        MAILBOX = "mailbox", "Caixa de email"
        PANEL_ACCOUNT = "panel_account", "Conta de painel"
        SSL = "ssl", "Certificado SSL"
        BACKUP = "backup", "Backup"
        OTHER = "other", "Outro"

    class Status(models.TextChoices):
        ACTIVE = "active", "Saudável"
        ATTENTION = "attention", "Requer atenção"
        CRITICAL = "critical", "Crítico"
        MAINTENANCE = "maintenance", "Em manutenção"
        INACTIVE = "inactive", "Inativo"
        UNKNOWN = "unknown", "Por confirmar"

    service = models.ForeignKey("services.Service", on_delete=models.CASCADE, related_name="technical_assets", verbose_name="Serviço")
    server = models.ForeignKey(Server, on_delete=models.SET_NULL, null=True, blank=True, related_name="assets", verbose_name="Servidor")
    asset_type = models.CharField("Tipo", max_length=20, choices=AssetType.choices, default=AssetType.WEBSITE)
    label = models.CharField("Designação", max_length=180)
    domain_name = models.CharField("Domínio / hostname", max_length=253, blank=True)
    document_root = models.CharField("Pasta no servidor", max_length=500, blank=True)
    subdomain = models.CharField("Subdomínio", max_length=253, blank=True)
    php_version = models.CharField("Versão PHP", max_length=30, blank=True)
    cms = models.CharField("CMS", max_length=80, blank=True)
    cms_version = models.CharField("Versão do CMS", max_length=40, blank=True)
    ssl_active = models.BooleanField("SSL ativo", default=False)
    last_checked_at = models.DateTimeField("Última verificação", null=True, blank=True)
    status = models.CharField("Estado", max_length=20, choices=Status.choices, default=Status.UNKNOWN)
    notes = models.TextField("Notas técnicas", blank=True)

    class Meta:
        verbose_name = "Ativo técnico"
        verbose_name_plural = "Ativos técnicos"
        ordering = ["service__client__name", "label"]

    def __str__(self):
        return self.label


class DatabaseAsset(TimeStampedModel):
    class Engine(models.TextChoices):
        MYSQL = "mysql", "MySQL / MariaDB"
        POSTGRES = "postgres", "PostgreSQL"
        SQLITE = "sqlite", "SQLite"
        OTHER = "other", "Outro"

    technical_asset = models.ForeignKey(TechnicalAsset, on_delete=models.CASCADE, related_name="databases", verbose_name="Ativo técnico")
    name = models.CharField("Nome da base de dados", max_length=180)
    engine = models.CharField("Motor", max_length=20, choices=Engine.choices, default=Engine.MYSQL)
    size_mb = models.DecimalField("Tamanho (MB)", max_digits=12, decimal_places=2, null=True, blank=True)
    username_reference = models.CharField("Referência do utilizador", max_length=150, blank=True)
    notes = models.TextField("Notas", blank=True)

    class Meta:
        verbose_name = "Base de dados"
        verbose_name_plural = "Bases de dados"
        ordering = ["name"]

    def __str__(self):
        return self.name


class BackupRecord(TimeStampedModel):
    class BackupType(models.TextChoices):
        FULL = "full", "Completo"
        FILES = "files", "Ficheiros"
        DATABASE = "database", "Base de dados"
        INCREMENTAL = "incremental", "Incremental"

    class Status(models.TextChoices):
        SCHEDULED = "scheduled", "Agendado"
        RUNNING = "running", "Em execução"
        CREATED = "created", "Criado"
        VERIFIED = "verified", "Verificado"
        FAILED = "failed", "Falhou"
        EXPIRED = "expired", "Expirado"

    technical_asset = models.ForeignKey(TechnicalAsset, on_delete=models.CASCADE, related_name="backups", verbose_name="Ativo técnico")
    backup_type = models.CharField("Tipo", max_length=20, choices=BackupType.choices, default=BackupType.FULL)
    backup_date = models.DateTimeField("Data do backup")
    location_reference = models.CharField("Localização / referência", max_length=300, blank=True)
    size_mb = models.DecimalField("Tamanho (MB)", max_digits=12, decimal_places=2, null=True, blank=True)
    verified_at = models.DateTimeField("Verificado em", null=True, blank=True)
    status = models.CharField("Estado", max_length=20, choices=Status.choices, default=Status.CREATED)
    notes = models.TextField("Notas", blank=True)

    class Meta:
        verbose_name = "Backup"
        verbose_name_plural = "Backups"
        ordering = ["-backup_date"]

    def __str__(self):
        return f"{self.technical_asset} — {self.backup_date:%d/%m/%Y}"


class WordPressSite(TimeStampedModel):
    class HealthStatus(models.TextChoices):
        HEALTHY = "healthy", "Saudável"
        ATTENTION = "attention", "Requer atenção"
        CRITICAL = "critical", "Crítico"
        MAINTENANCE = "maintenance", "Em manutenção"
        UNKNOWN = "unknown", "Por verificar"

    technical_asset = models.OneToOneField(
        TechnicalAsset,
        on_delete=models.CASCADE,
        related_name="wordpress_site",
        verbose_name="Ativo técnico",
    )
    public_url = models.URLField("URL pública", blank=True)
    admin_url = models.URLField("URL de administração", blank=True)
    installed_version = models.CharField("Versão instalada", max_length=30, blank=True)
    available_version = models.CharField("Versão disponível", max_length=30, blank=True)
    php_version = models.CharField("Versão PHP", max_length=30, blank=True)
    multisite = models.BooleanField("WordPress Multisite", default=False)
    wp_cron_enabled = models.BooleanField("WP-Cron ativo", default=True)
    automatic_core_updates = models.BooleanField("Atualizações automáticas do núcleo", default=False)
    debug_mode = models.BooleanField("WP_DEBUG ativo", default=False)
    maintenance_mode = models.BooleanField("Modo de manutenção", default=False)
    credentials_reference = models.CharField(
        "Referência das credenciais",
        max_length=180,
        blank=True,
        help_text="Indique apenas a referência do cofre; nunca guarde palavras-passe.",
    )
    health_status = models.CharField(
        "Estado de saúde",
        max_length=20,
        choices=HealthStatus.choices,
        default=HealthStatus.UNKNOWN,
        db_index=True,
    )
    last_updated_at = models.DateTimeField("Última atualização", null=True, blank=True)
    last_scan_at = models.DateTimeField("Última análise", null=True, blank=True)
    notes = models.TextField("Notas", blank=True)

    class Meta:
        verbose_name = "Site WordPress"
        verbose_name_plural = "Sites WordPress"
        ordering = ["technical_asset__service__client__name", "technical_asset__label"]

    @property
    def update_required(self):
        return bool(self.available_version and self.installed_version and self.available_version != self.installed_version)

    def clean(self):
        if self.technical_asset_id and self.technical_asset.asset_type != TechnicalAsset.AssetType.WEBSITE:
            from django.core.exceptions import ValidationError
            raise ValidationError({"technical_asset": "O WordPress deve estar associado a um ativo técnico do tipo Website."})

    def __str__(self):
        return self.technical_asset.label


class WordPressPlugin(TimeStampedModel):
    class ActivationStatus(models.TextChoices):
        ACTIVE = "active", "Ativo"
        INACTIVE = "inactive", "Inativo"
        MUST_USE = "must_use", "Must-use"

    class SecurityStatus(models.TextChoices):
        SECURE = "secure", "Sem alertas conhecidos"
        ATTENTION = "attention", "Requer atenção"
        VULNERABLE = "vulnerable", "Vulnerável"
        UNKNOWN = "unknown", "Por verificar"

    wordpress_site = models.ForeignKey(
        WordPressSite,
        on_delete=models.CASCADE,
        related_name="plugins",
        verbose_name="Site WordPress",
    )
    name = models.CharField("Nome", max_length=180)
    slug = models.SlugField("Slug", max_length=180, blank=True)
    installed_version = models.CharField("Versão instalada", max_length=40, blank=True)
    available_version = models.CharField("Versão disponível", max_length=40, blank=True)
    activation_status = models.CharField(
        "Estado",
        max_length=20,
        choices=ActivationStatus.choices,
        default=ActivationStatus.ACTIVE,
        db_index=True,
    )
    automatic_updates = models.BooleanField("Atualização automática", default=False)
    premium = models.BooleanField("Premium", default=False)
    provider = models.CharField("Fornecedor", max_length=150, blank=True)
    license_reference = models.CharField("Referência da licença", max_length=180, blank=True)
    license_expires_on = models.DateField("Licença válida até", null=True, blank=True, db_index=True)
    security_status = models.CharField(
        "Segurança",
        max_length=20,
        choices=SecurityStatus.choices,
        default=SecurityStatus.UNKNOWN,
        db_index=True,
    )
    last_checked_at = models.DateTimeField("Última verificação", null=True, blank=True)
    notes = models.TextField("Notas", blank=True)

    class Meta:
        verbose_name = "Plugin WordPress"
        verbose_name_plural = "Plugins WordPress"
        ordering = ["wordpress_site", "name"]
        constraints = [
            models.UniqueConstraint(fields=["wordpress_site", "slug"], condition=~models.Q(slug=""), name="uniq_wordpress_plugin_slug_per_site")
        ]

    @property
    def update_required(self):
        return bool(self.available_version and self.installed_version and self.available_version != self.installed_version)

    def __str__(self):
        return f"{self.name} — {self.wordpress_site}"


class WordPressTheme(TimeStampedModel):
    wordpress_site = models.ForeignKey(
        WordPressSite,
        on_delete=models.CASCADE,
        related_name="themes",
        verbose_name="Site WordPress",
    )
    name = models.CharField("Nome", max_length=180)
    slug = models.SlugField("Slug", max_length=180, blank=True)
    installed_version = models.CharField("Versão instalada", max_length=40, blank=True)
    available_version = models.CharField("Versão disponível", max_length=40, blank=True)
    is_active = models.BooleanField("Tema ativo", default=False, db_index=True)
    is_child_theme = models.BooleanField("Tema filho", default=False)
    parent_theme = models.CharField("Tema principal", max_length=180, blank=True)
    automatic_updates = models.BooleanField("Atualização automática", default=False)
    premium = models.BooleanField("Premium", default=False)
    provider = models.CharField("Fornecedor", max_length=150, blank=True)
    license_reference = models.CharField("Referência da licença", max_length=180, blank=True)
    license_expires_on = models.DateField("Licença válida até", null=True, blank=True, db_index=True)
    last_checked_at = models.DateTimeField("Última verificação", null=True, blank=True)
    notes = models.TextField("Notas", blank=True)

    class Meta:
        verbose_name = "Tema WordPress"
        verbose_name_plural = "Temas WordPress"
        ordering = ["wordpress_site", "-is_active", "name"]
        constraints = [
            models.UniqueConstraint(fields=["wordpress_site", "slug"], condition=~models.Q(slug=""), name="uniq_wordpress_theme_slug_per_site")
        ]

    @property
    def update_required(self):
        return bool(self.available_version and self.installed_version and self.available_version != self.installed_version)

    def __str__(self):
        return f"{self.name} — {self.wordpress_site}"


class SSLCertificate(TimeStampedModel):
    class CertificateType(models.TextChoices):
        LETS_ENCRYPT = "lets_encrypt", "Let's Encrypt"
        COMMERCIAL = "commercial", "Comercial"
        CLOUDFLARE = "cloudflare", "Cloudflare"
        SELF_SIGNED = "self_signed", "Autoassinado"
        OTHER = "other", "Outro"

    class ValidationMethod(models.TextChoices):
        HTTP = "http", "HTTP"
        DNS = "dns", "DNS"
        EMAIL = "email", "Email"
        MANAGED = "managed", "Gerido pelo fornecedor"
        UNKNOWN = "unknown", "Por confirmar"

    class Status(models.TextChoices):
        PENDING = "pending", "Pendente"
        VALID = "valid", "Válido"
        EXPIRING = "expiring", "A expirar"
        EXPIRED = "expired", "Expirado"
        INVALID = "invalid", "Inválido"
        REVOKED = "revoked", "Revogado"
        UNKNOWN = "unknown", "Por verificar"

    technical_asset = models.OneToOneField(
        TechnicalAsset,
        on_delete=models.CASCADE,
        related_name="ssl_certificate",
        verbose_name="Ativo técnico",
    )
    primary_domain = models.CharField("Domínio principal", max_length=253, db_index=True)
    covered_domains = models.TextField("Domínios abrangidos", blank=True, help_text="Um domínio por linha.")
    issuer = models.CharField("Emissor", max_length=180, blank=True)
    certificate_type = models.CharField("Tipo", max_length=20, choices=CertificateType.choices, default=CertificateType.LETS_ENCRYPT)
    issued_at = models.DateTimeField("Emitido em", null=True, blank=True)
    expires_at = models.DateTimeField("Expira em", null=True, blank=True, db_index=True)
    automatic_renewal = models.BooleanField("Renovação automática", default=True)
    validation_method = models.CharField("Validação", max_length=20, choices=ValidationMethod.choices, default=ValidationMethod.MANAGED)
    status = models.CharField("Estado", max_length=20, choices=Status.choices, default=Status.UNKNOWN, db_index=True)
    last_checked_at = models.DateTimeField("Última verificação", null=True, blank=True)
    error_message = models.TextField("Último erro", blank=True)
    notes = models.TextField("Notas", blank=True)

    class Meta:
        verbose_name = "Certificado SSL"
        verbose_name_plural = "Certificados SSL"
        ordering = ["expires_at", "primary_domain"]

    @property
    def days_remaining(self):
        if not self.expires_at:
            return None
        from django.utils import timezone
        return (self.expires_at.date() - timezone.localdate()).days

    def clean(self):
        from django.core.exceptions import ValidationError
        if self.issued_at and self.expires_at and self.expires_at <= self.issued_at:
            raise ValidationError({"expires_at": "A validade deve ser posterior à emissão."})

    def __str__(self):
        return self.primary_domain
