from django.db import models
from django.contrib.auth import get_user_model
import uuid
from django.conf import settings
from cryptography.fernet import Fernet, InvalidToken

User = get_user_model()


class EncryptionConfigurationError(Exception):
    pass


def get_field_fernet() -> Fernet:
    key = getattr(settings, "FIELD_ENCRYPTION_KEY", None)
    if not key:
        raise EncryptionConfigurationError(
            "FIELD_ENCRYPTION_KEY is not configured. API key storage is unavailable."
        )

    key_bytes = key.encode() if isinstance(key, str) else key
    try:
        return Fernet(key_bytes)
    except (TypeError, ValueError) as exc:
        raise EncryptionConfigurationError(
            "FIELD_ENCRYPTION_KEY is invalid. Provide a valid Fernet key."
        ) from exc


class ImmichIntegration(models.Model):
    server_url = models.CharField(max_length=255)
    api_key = models.CharField(max_length=255)
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    copy_locally = models.BooleanField(
        default=True,
        help_text="Copy image to local storage, instead of just linking to the remote URL.",
    )
    id = models.UUIDField(
        default=uuid.uuid4, editable=False, unique=True, primary_key=True
    )

    def __str__(self):
        return self.user.username + " - " + self.server_url


class StravaToken(models.Model):
    user = models.ForeignKey(
        User, on_delete=models.CASCADE, related_name="strava_tokens"
    )
    access_token = models.CharField(max_length=255)
    refresh_token = models.CharField(max_length=255)
    expires_at = models.BigIntegerField()  # Unix timestamp
    athlete_id = models.BigIntegerField(null=True, blank=True)
    scope = models.CharField(max_length=255, null=True, blank=True)
    updated_at = models.DateTimeField(auto_now=True)


class WandererIntegration(models.Model):
    server_url = models.CharField(max_length=255)
    username = models.CharField(max_length=255)
    user = models.ForeignKey(
        User, on_delete=models.CASCADE, related_name="wanderer_integrations"
    )
    token = models.CharField(null=True, blank=True)
    token_expiry = models.DateTimeField(null=True, blank=True)
    id = models.UUIDField(
        default=uuid.uuid4, editable=False, unique=True, primary_key=True
    )

    def __str__(self):
        return self.user.username + " - " + self.server_url

    class Meta:
        verbose_name = "Wanderer Integration"
        verbose_name_plural = "Wanderer Integrations"


class UserAPIKey(models.Model):
    id = models.UUIDField(
        default=uuid.uuid4, editable=False, unique=True, primary_key=True
    )
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="api_keys")
    provider = models.CharField(max_length=100)
    encrypted_api_key = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        unique_together = ("user", "provider")

    def set_api_key(self, value: str) -> None:
        if value is None:
            raise ValueError("API key cannot be None")
        fernet = get_field_fernet()
        self.encrypted_api_key = fernet.encrypt(value.encode()).decode()

    def get_api_key(self) -> str | None:
        if not self.encrypted_api_key:
            return None
        fernet = get_field_fernet()
        try:
            return fernet.decrypt(self.encrypted_api_key.encode()).decode()
        except (InvalidToken, ValueError):
            return None

    @property
    def masked_api_key(self) -> str:
        plain = self.get_api_key() or ""
        if len(plain) <= 6:
            return "*" * len(plain)
        return f"{plain[:3]}{'*' * (len(plain) - 6)}{plain[-3:]}"


class UserRecommendationPreferenceProfile(models.Model):
    id = models.UUIDField(
        default=uuid.uuid4, editable=False, unique=True, primary_key=True
    )
    user = models.OneToOneField(
        User, on_delete=models.CASCADE, related_name="recommendation_profile"
    )
    cuisines = models.TextField(blank=True, null=True)
    interests = models.JSONField(default=list, blank=True)
    trip_style = models.CharField(max_length=120, blank=True, null=True)
    notes = models.TextField(blank=True, null=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)


class UserAISettings(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    user = models.OneToOneField(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name="ai_settings",
    )
    preferred_provider = models.CharField(max_length=100, blank=True, null=True)
    preferred_model = models.CharField(max_length=100, blank=True, null=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        verbose_name = "User AI Settings"
        verbose_name_plural = "User AI Settings"

    def __str__(self):
        return f"AI Settings for {self.user.username}"
