"""
Themis models — user preferences, API key management, and notifications.
"""
import uuid
from zoneinfo import available_timezones

from django.conf import settings
from django.db import models
from django.urls import reverse


# Build sorted timezone choices once at module load
TIMEZONE_CHOICES = [(tz, tz) for tz in sorted(available_timezones())]

# DaisyUI theme choices
DAISYUI_THEMES = [
    ("light", "Light"),
    ("dark", "Dark"),
    ("cupcake", "Cupcake"),
    ("bumblebee", "Bumblebee"),
    ("emerald", "Emerald"),
    ("corporate", "Corporate"),
    ("synthwave", "Synthwave"),
    ("retro", "Retro"),
    ("cyberpunk", "Cyberpunk"),
    ("valentine", "Valentine"),
    ("halloween", "Halloween"),
    ("garden", "Garden"),
    ("forest", "Forest"),
    ("aqua", "Aqua"),
    ("lofi", "Lo-Fi"),
    ("pastel", "Pastel"),
    ("fantasy", "Fantasy"),
    ("wireframe", "Wireframe"),
    ("black", "Black"),
    ("luxury", "Luxury"),
    ("dracula", "Dracula"),
    ("cmyk", "CMYK"),
    ("autumn", "Autumn"),
    ("business", "Business"),
    ("acid", "Acid"),
    ("lemonade", "Lemonade"),
    ("night", "Night"),
    ("coffee", "Coffee"),
    ("winter", "Winter"),
    ("dim", "Dim"),
    ("nord", "Nord"),
    ("sunset", "Sunset"),
]


class UserProfile(models.Model):
    """
    Extends Django's User model with display preferences and theme settings.
    Automatically created via signal when a User is created.

    Supports dual timezones for traveling users: a permanent home timezone
    and an optional current timezone that takes precedence when set.
    """

    # Theme mode choices
    THEME_MODE_CHOICES = [
        ("light", "Light"),
        ("dark", "Dark"),
        ("auto", "Auto (System)"),
    ]

    # Date format choices
    DATE_FORMAT_CHOICES = [
        ("YYYY-MM-DD", "2024-12-25"),
        ("DD/MM/YYYY", "25/12/2024"),
        ("MM/DD/YYYY", "12/25/2024"),
        ("DD.MM.YYYY", "25.12.2024"),
        ("DD-MM-YYYY", "25-12-2024"),
    ]

    # Time format choices
    TIME_FORMAT_CHOICES = [
        ("12-hour", "12-hour (3:30 PM)"),
        ("24-hour", "24-hour (15:30)"),
    ]

    # Thousand separator choices
    SEPARATOR_CHOICES = [
        ("comma", "Comma (1,000)"),
        ("period", "Period (1.000)"),
        ("space", "Space (1 000)"),
        ("none", "None (1000)"),
    ]

    # Week start choices
    WEEK_START_CHOICES = [
        ("monday", "Monday"),
        ("sunday", "Sunday"),
        ("saturday", "Saturday"),
    ]

    # Core relationship
    user = models.OneToOneField(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name="profile",
    )

    # Timezone settings
    home_timezone = models.CharField(
        max_length=50,
        default="UTC",
        choices=TIMEZONE_CHOICES,
        help_text="User's home/permanent timezone",
    )
    current_timezone = models.CharField(
        max_length=50,
        blank=True,
        default="",
        choices=[("", "---------")] + TIMEZONE_CHOICES,
        help_text="User's current timezone when traveling (leave blank if at home)",
    )

    # Display preferences
    date_format = models.CharField(
        max_length=20,
        choices=DATE_FORMAT_CHOICES,
        default="YYYY-MM-DD",
        help_text="Preferred date display format",
    )
    time_format = models.CharField(
        max_length=10,
        choices=TIME_FORMAT_CHOICES,
        default="24-hour",
        help_text="12-hour or 24-hour time format",
    )
    thousand_separator = models.CharField(
        max_length=10,
        choices=SEPARATOR_CHOICES,
        default="comma",
        help_text="Number formatting preference",
    )
    week_start = models.CharField(
        max_length=10,
        choices=WEEK_START_CHOICES,
        default="monday",
        help_text="First day of the week",
    )

    # Theme settings (DaisyUI)
    theme_mode = models.CharField(
        max_length=10,
        choices=THEME_MODE_CHOICES,
        default="auto",
        help_text="Theme mode: light, dark, or auto (follows system)",
    )
    theme_name = models.CharField(
        max_length=30,
        choices=DAISYUI_THEMES,
        default="corporate",
        help_text="DaisyUI theme for light mode",
    )
    dark_theme_name = models.CharField(
        max_length=30,
        choices=DAISYUI_THEMES,
        default="business",
        help_text="DaisyUI theme for dark mode",
    )

    # Notification preferences
    NOTIFICATION_LEVEL_CHOICES = [
        ("info", "All notifications"),
        ("warning", "Warnings and errors only"),
        ("danger", "Errors only"),
    ]

    notifications_enabled = models.BooleanField(
        default=True,
        help_text="Enable in-app notifications",
    )
    notifications_min_level = models.CharField(
        max_length=10,
        choices=NOTIFICATION_LEVEL_CHOICES,
        default="info",
        help_text="Minimum notification level to display",
    )
    browser_notifications_enabled = models.BooleanField(
        default=False,
        help_text="Enable browser desktop notifications (requires permission)",
    )
    notification_retention_days = models.PositiveIntegerField(
        default=30,
        help_text="Days to keep read notifications before auto-cleanup",
    )

    # Metadata
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        verbose_name = "User Profile"
        verbose_name_plural = "User Profiles"

    def __str__(self):
        return f"{self.user.username}'s Profile"

    def get_absolute_url(self):
        return reverse("themis:profile-settings")

    @property
    def effective_timezone(self):
        """Return current timezone if set, otherwise home timezone."""
        return self.current_timezone or self.home_timezone

    @property
    def is_traveling(self):
        """Check if user has a current timezone different from home."""
        return bool(
            self.current_timezone and self.current_timezone != self.home_timezone
        )


class UserAPIKey(models.Model):
    """
    Stores encrypted API keys, MCP credentials, DAV passwords, and other
    service credentials for a user. Keys are encrypted at rest using Fernet.

    This model does not define what the keys are for — consuming apps
    register which key types they need. The instructions field allows
    per-key documentation so users know how to obtain and use each key.
    """

    KEY_TYPE_CHOICES = [
        ("api", "API Key"),
        ("dav", "DAV Credentials"),
        ("token", "Access Token"),
        ("secret", "Secret Key"),
        ("other", "Other"),
    ]

    id = models.UUIDField(
        primary_key=True,
        default=uuid.uuid4,
        editable=False,
    )
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name="api_keys",
    )

    # Key identity
    service_name = models.CharField(
        max_length=100,
        help_text="Service this key belongs to (e.g. OpenAI, Anthropic, CalDAV)",
    )
    key_type = models.CharField(
        max_length=30,
        choices=KEY_TYPE_CHOICES,
        default="api",
        help_text="Type of credential",
    )
    label = models.CharField(
        max_length=100,
        blank=True,
        default="",
        help_text="Your nickname for this key (e.g. 'Work account')",
    )

    # Encrypted key value
    encrypted_value = models.TextField(
        help_text="Fernet-encrypted credential value",
    )

    # Documentation
    instructions = models.TextField(
        blank=True,
        default="",
        help_text="How to obtain and use this key",
    )
    help_url = models.URLField(
        blank=True,
        default="",
        help_text="Link to service documentation",
    )

    # Status
    is_active = models.BooleanField(
        default=True,
        help_text="Whether this key is currently in use",
    )
    last_used_at = models.DateTimeField(
        null=True,
        blank=True,
        help_text="Last time this key was used",
    )
    expires_at = models.DateTimeField(
        null=True,
        blank=True,
        help_text="When this key expires (if applicable)",
    )

    # Metadata
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        verbose_name = "API Key"
        verbose_name_plural = "API Keys"

    def __str__(self):
        return f"{self.service_name} ({self.key_type}) — {self.user.username}"

    def get_absolute_url(self):
        return reverse("themis:key-detail", kwargs={"pk": self.pk})

    @property
    def masked_value(self):
        """Return masked version of the decrypted key, showing only last 4 chars."""
        from themis.encryption import decrypt_value

        try:
            value = decrypt_value(self.encrypted_value)
            if len(value) <= 4:
                return "****"
            return f"{'*' * (len(value) - 4)}{value[-4:]}"
        except Exception:
            return "****"

    @property
    def display_name(self):
        """Return label if set, otherwise service_name."""
        return self.label or self.service_name


class UserNotification(models.Model):
    """
    In-app notification for a user.

    Notifications are created by consuming apps via ``themis.notifications.notify_user()``
    and displayed in the notification bell dropdown. Source tracking fields
    (``source_app``, ``source_model``, ``source_id``) enable deduplication and
    bulk cleanup when the originating object is deleted.
    """

    LEVEL_CHOICES = [
        ("info", "Info"),
        ("success", "Success"),
        ("warning", "Warning"),
        ("danger", "Danger"),
    ]

    # Numeric weights for level comparison
    LEVEL_WEIGHTS = {
        "info": 0,
        "success": 0,
        "warning": 1,
        "danger": 2,
    }

    id = models.UUIDField(
        primary_key=True,
        default=uuid.uuid4,
        editable=False,
    )
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name="notifications",
    )

    # Content
    title = models.CharField(
        max_length=200,
        help_text="Short notification headline",
    )
    message = models.TextField(
        blank=True,
        default="",
        help_text="Notification body text",
    )
    level = models.CharField(
        max_length=10,
        choices=LEVEL_CHOICES,
        default="info",
        help_text="Notification severity level",
    )
    url = models.CharField(
        max_length=500,
        blank=True,
        default="",
        help_text="URL to navigate to when notification is clicked",
    )

    # Source tracking (for dedup and cleanup)
    source_app = models.CharField(
        max_length=100,
        blank=True,
        default="",
        db_index=True,
        help_text="App label that created this notification",
    )
    source_model = models.CharField(
        max_length=100,
        blank=True,
        default="",
        help_text="Model name that triggered this notification",
    )
    source_id = models.CharField(
        max_length=100,
        blank=True,
        default="",
        help_text="Primary key of the source object",
    )

    # State
    is_read = models.BooleanField(
        default=False,
        db_index=True,
        help_text="Whether the user has read this notification",
    )
    read_at = models.DateTimeField(
        null=True,
        blank=True,
        help_text="When the notification was read",
    )
    is_dismissed = models.BooleanField(
        default=False,
        help_text="Whether the user has dismissed this notification",
    )
    dismissed_at = models.DateTimeField(
        null=True,
        blank=True,
        help_text="When the notification was dismissed",
    )
    expires_at = models.DateTimeField(
        null=True,
        blank=True,
        help_text="Auto-dismiss after this time (optional)",
    )

    # Metadata
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        verbose_name = "Notification"
        verbose_name_plural = "Notifications"
        ordering = ["-created_at"]
        indexes = [
            models.Index(
                fields=["user", "is_read", "is_dismissed"],
                name="themis_notif_user_state",
            ),
            models.Index(
                fields=["user", "created_at"],
                name="themis_notif_user_created",
            ),
            models.Index(
                fields=["source_app", "source_model", "source_id"],
                name="themis_notif_source",
            ),
        ]

    def __str__(self):
        return f"[{self.level}] {self.title} → {self.user.username}"

    def get_absolute_url(self):
        return reverse("themis:notification-list")

    @property
    def level_weight(self):
        """Numeric weight for level comparison."""
        return self.LEVEL_WEIGHTS.get(self.level, 0)

    @property
    def is_expired(self):
        """Check if notification has passed its expiry time."""
        if not self.expires_at:
            return False
        from django.utils import timezone
        return timezone.now() >= self.expires_at

    @property
    def level_css_class(self):
        """Return DaisyUI alert class for this notification level."""
        return {
            "info": "alert-info",
            "success": "alert-success",
            "warning": "alert-warning",
            "danger": "alert-error",
        }.get(self.level, "alert-info")

    @property
    def level_badge_class(self):
        """Return DaisyUI badge class for this notification level."""
        return {
            "info": "badge-info",
            "success": "badge-success",
            "warning": "badge-warning",
            "danger": "badge-error",
        }.get(self.level, "badge-info")
