from django.db import models
from django.contrib.auth.models import User


class IstatGuestType(models.Model):
    code = models.CharField(max_length=2, primary_key=True)
    description = models.CharField(max_length=64)

    class Meta:
        db_table = "istat_guest_type"
        ordering = ["code"]

    def __str__(self):
        return f"{self.code} - {self.description}"


class IstatGender(models.Model):
    code = models.CharField(max_length=1, primary_key=True)
    meaning = models.CharField(max_length=16)

    class Meta:
        db_table = "istat_gender"
        ordering = ["code"]

    def __str__(self):
        return f"{self.code} - {self.meaning}"


class IstatTourismType(models.Model):
    name = models.CharField(max_length=64, unique=True)

    class Meta:
        db_table = "istat_tourism_type"
        ordering = ["name"]

    def __str__(self):
        return self.name


class IstatTransportType(models.Model):
    name = models.CharField(max_length=64, unique=True)

    class Meta:
        db_table = "istat_transport_type"
        ordering = ["name"]

    def __str__(self):
        return self.name


class IstatCountry(models.Model):
    code = models.CharField(max_length=9, primary_key=True)
    name = models.CharField(max_length=128)
    iso_code = models.CharField(max_length=3, blank=True, null=True)

    class Meta:
        db_table = "istat_countries"
        ordering = ["name"]

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


class IstatMunicipality(models.Model):
    code = models.CharField(max_length=9, primary_key=True)
    name = models.CharField(max_length=128)
    normalized_name = models.CharField(max_length=128, blank=True, db_index=True)
    province = models.CharField(max_length=2, blank=True, null=True)
    region = models.CharField(max_length=128, blank=True, null=True)
    is_active = models.BooleanField(default=True)

    class Meta:
        db_table = "istat_municipalities"
        ordering = ["name"]
        indexes = [
            models.Index(fields=["province"], name="istat_muni_province_idx"),
            models.Index(
                fields=["province", "normalized_name"],
                name="istat_muni_prov_name_idx",
            ),
            models.Index(fields=["is_active"], name="istat_muni_active_idx"),
        ]

    def save(self, *args, **kwargs):
        from istat.municipalities import normalize_municipality_name

        self.normalized_name = normalize_municipality_name(self.name)
        if self.province:
            self.province = self.province.strip().upper()
        super().save(*args, **kwargs)

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


class IstatProvince(models.Model):
    code = models.CharField(max_length=2, primary_key=True)
    name = models.CharField(max_length=128)
    region = models.CharField(max_length=128, blank=True, null=True)

    class Meta:
        db_table = "istat_provinces"
        ordering = ["name"]

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


class IstatDocumentType(models.Model):
    code = models.CharField(max_length=5, primary_key=True)
    description = models.CharField(max_length=128)

    class Meta:
        db_table = "istat_document_types"
        ordering = ["code"]

    def __str__(self):
        return f"{self.code} - {self.description}"


class IstatReservationPosition(models.Model):
    reservation = models.ForeignKey(
        "bookings.Booking",
        on_delete=models.CASCADE,
        related_name="istat_positions",
    )
    guest = models.ForeignKey(
        "guests.Guest",
        on_delete=models.CASCADE,
        related_name="istat_positions",
    )
    istat_position_code = models.CharField(max_length=10, unique=True)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = "istat_reservation_positions"
        unique_together = ["reservation", "guest"]
        ordering = ["created_at"]

    def __str__(self):
        return f"{self.reservation_id}-{self.guest_id} => {self.istat_position_code}"


class IstatCredential(models.Model):
    structure = models.OneToOneField(
        "structures.Structure",
        on_delete=models.CASCADE,
        related_name="istat_credential",
    )
    username_encrypted = models.TextField()
    password_encrypted = models.TextField()
    created_by = models.ForeignKey(
        User,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="created_istat_credentials",
    )
    updated_by = models.ForeignKey(
        User,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="updated_istat_credentials",
    )
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        db_table = "istat_credentials"
        ordering = ["structure_id"]

    def __str__(self):
        return f"ISTAT credentials for {self.structure}"

    @property
    def username(self):
        from .security import decrypt_istat_secret

        return decrypt_istat_secret(self.username_encrypted)

    @username.setter
    def username(self, value):
        from .security import encrypt_istat_secret

        self.username_encrypted = encrypt_istat_secret(value)

    @property
    def password(self):
        from .security import decrypt_istat_secret

        return decrypt_istat_secret(self.password_encrypted)

    @password.setter
    def password(self, value):
        from .security import encrypt_istat_secret

        self.password_encrypted = encrypt_istat_secret(value)

    @property
    def masked_password(self):
        from .security import mask_istat_secret

        return mask_istat_secret(self.password_encrypted)


class IstatSyncHistory(models.Model):
    class Status(models.TextChoices):
        PENDING = "pending", "Pending"
        SUCCESS = "success", "Success"
        FAILED = "failed", "Failed"

    structure = models.ForeignKey(
        "structures.Structure",
        on_delete=models.CASCADE,
        related_name="istat_sync_history",
    )
    credential = models.ForeignKey(
        "IstatCredential",
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="sync_history",
    )
    triggered_by = models.ForeignKey(
        User,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="istat_sync_history",
    )
    status = models.CharField(
        max_length=16,
        choices=Status.choices,
        default=Status.PENDING,
    )
    message = models.CharField(max_length=255, blank=True)
    requested_period = models.JSONField(default=dict, blank=True)
    request_payload = models.JSONField(default=dict, blank=True)
    response_payload = models.JSONField(default=dict, blank=True)
    requested_at = models.DateTimeField(auto_now_add=True)
    completed_at = models.DateTimeField(null=True, blank=True)

    class Meta:
        db_table = "istat_sync_history"
        ordering = ["-requested_at"]

    def __str__(self):
        return f"{self.structure} | {self.status} | {self.requested_at:%Y-%m-%d %H:%M}"


class IstatAuditLog(models.Model):
    class Action(models.TextChoices):
        CREDENTIAL_CREATED = "credential_created", "Credential Created"
        CREDENTIAL_UPDATED = "credential_updated", "Credential Updated"
        CREDENTIAL_DELETED = "credential_deleted", "Credential Deleted"
        SYNC_TRIGGERED = "sync_triggered", "Sync Triggered"

    structure = models.ForeignKey(
        "structures.Structure",
        on_delete=models.CASCADE,
        related_name="istat_audit_logs",
    )
    credential = models.ForeignKey(
        "IstatCredential",
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="audit_logs",
    )
    sync_record = models.ForeignKey(
        "IstatSyncHistory",
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="audit_logs",
    )
    actor = models.ForeignKey(
        User,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="istat_audit_logs",
    )
    action = models.CharField(max_length=32, choices=Action.choices)
    message = models.CharField(max_length=255)
    metadata = models.JSONField(default=dict, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = "istat_audit_logs"
        ordering = ["-created_at"]

    def __str__(self):
        return f"{self.structure} | {self.action} | {self.created_at:%Y-%m-%d %H:%M}"
