from django.contrib.auth.models import AbstractUser
from django.db import models
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
import random

def generate_random_id(model_class, id_field):
    """Generate a random ID starting at 4 digits, expanding to 5 if needed"""
    while True:
        # Try to get a 4-digit number first
        new_id = str(random.randint(1000, 9999))
        if not model_class.objects.filter(**{id_field: new_id}).exists():
            return new_id
        
        # If all 4-digit numbers are taken, try 5 digits
        new_id = str(random.randint(10000, 99999))
        if not model_class.objects.filter(**{id_field: new_id}).exists():
            return new_id

class User(AbstractUser):
    class Roles(models.TextChoices):
        USER = 'USER', _('User')
        MODERATOR = 'MODERATOR', _('Moderator')
        ADMIN = 'ADMIN', _('Admin')
        SUPERUSER = 'SUPERUSER', _('Superuser')

    class ThemePreference(models.TextChoices):
        LIGHT = 'light', _('Light')
        DARK = 'dark', _('Dark')

    # Read-only ID
    user_id = models.CharField(
        max_length=10,
        unique=True,
        editable=False,
        help_text='Unique identifier for this user that remains constant even if the username changes'
    )

    first_name = models.CharField(_('first name'), max_length=150, default='')
    last_name = models.CharField(_('last name'), max_length=150, default='')
    role = models.CharField(
        max_length=10,
        choices=Roles.choices,
        default=Roles.USER,
    )
    is_banned = models.BooleanField(default=False)
    ban_reason = models.TextField(blank=True)
    ban_date = models.DateTimeField(null=True, blank=True)
    pending_email = models.EmailField(blank=True, null=True)
    theme_preference = models.CharField(
        max_length=5,
        choices=ThemePreference.choices,
        default=ThemePreference.LIGHT,
    )

    def __str__(self):
        return self.get_display_name()

    def get_absolute_url(self):
        return reverse('profile', kwargs={'username': self.username})

    def get_display_name(self):
        """Get the user's display name, falling back to username if not set"""
        if hasattr(self, 'profile') and self.profile.display_name:
            return self.profile.display_name
        return self.username

    def save(self, *args, **kwargs):
        if not self.user_id:
            self.user_id = generate_random_id(User, 'user_id')
        super().save(*args, **kwargs)

class UserProfile(models.Model):
    # Read-only ID
    profile_id = models.CharField(
        max_length=10,
        unique=True,
        editable=False,
        help_text='Unique identifier for this profile that remains constant'
    )

    user = models.OneToOneField(
        User,
        on_delete=models.CASCADE,
        related_name='profile'
    )
    display_name = models.CharField(
        max_length=50,
        unique=True,
        help_text="This is the name that will be displayed on the site"
    )
    avatar = models.ImageField(upload_to='avatars/', blank=True)
    pronouns = models.CharField(max_length=50, blank=True)
    
    bio = models.TextField(max_length=500, blank=True)
    
    # Social media links
    twitter = models.URLField(blank=True)
    instagram = models.URLField(blank=True)
    youtube = models.URLField(blank=True)
    discord = models.CharField(max_length=100, blank=True)
    
    # Ride statistics
    coaster_credits = models.IntegerField(default=0)
    dark_ride_credits = models.IntegerField(default=0)
    flat_ride_credits = models.IntegerField(default=0)
    water_ride_credits = models.IntegerField(default=0)

    def save(self, *args, **kwargs):
        # If no display name is set, use the username
        if not self.display_name:
            self.display_name = self.user.username
        if not self.profile_id:
            self.profile_id = generate_random_id(UserProfile, 'profile_id')
        super().save(*args, **kwargs)
    
    def __str__(self):
        return self.display_name

class EmailVerification(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    token = models.CharField(max_length=64, unique=True)
    created_at = models.DateTimeField(auto_now_add=True)
    last_sent = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return f"Email verification for {self.user.username}"

    class Meta:
        verbose_name = "Email Verification"
        verbose_name_plural = "Email Verifications"

class PasswordReset(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    token = models.CharField(max_length=64)
    created_at = models.DateTimeField(auto_now_add=True)
    expires_at = models.DateTimeField()
    used = models.BooleanField(default=False)

    def __str__(self):
        return f"Password reset for {self.user.username}"

    class Meta:
        verbose_name = "Password Reset"
        verbose_name_plural = "Password Resets"

class TopList(models.Model):
    class Categories(models.TextChoices):
        ROLLER_COASTER = 'RC', _('Roller Coaster')
        DARK_RIDE = 'DR', _('Dark Ride')
        FLAT_RIDE = 'FR', _('Flat Ride')
        WATER_RIDE = 'WR', _('Water Ride')
        PARK = 'PK', _('Park')

    user = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        related_name='top_lists'
    )
    title = models.CharField(max_length=100)
    category = models.CharField(
        max_length=2,
        choices=Categories.choices
    )
    description = models.TextField(blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ['-updated_at']

    def __str__(self):
        return f"{self.user.get_display_name()}'s {self.get_category_display()} Top List: {self.title}"

class TopListItem(models.Model):
    top_list = models.ForeignKey(
        TopList,
        on_delete=models.CASCADE,
        related_name='items'
    )
    content_type = models.ForeignKey(
        'contenttypes.ContentType',
        on_delete=models.CASCADE
    )
    object_id = models.PositiveIntegerField()
    rank = models.PositiveIntegerField()
    notes = models.TextField(blank=True)

    class Meta:
        ordering = ['rank']
        unique_together = [['top_list', 'rank']]

    def __str__(self):
        return f"#{self.rank} in {self.top_list.title}"
