# apps/users/models.py
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin
from django.core.exceptions import ValidationError
import uuid
import random
import string
from apps.users.manager import UserManagerEmail
from apps.core.permissions.role_permission import (
    get_role_based_permissions
)
from django.conf import settings


class User(AbstractBaseUser, PermissionsMixin):
    ROLE_CHOICES = (
        ('admin', 'Admin'),
        ('user', 'User'),
    )

    username = None
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    
    refer_code = models.CharField(
        max_length=10, 
        unique=True, 
        blank=True,
        db_index=True,
        help_text="Auto-generated referral code"
    )
    
    name = models.CharField(max_length=255)
    email = models.EmailField(max_length=255, unique=True, blank=False, null=False)
    role = models.CharField(max_length=20, choices=ROLE_CHOICES, default='user')  
    permissions = models.JSONField(
        null=True,
        blank=True,
        default=dict 
    )
    
    is_staff = models.BooleanField(default=False)
    is_superuser = models.BooleanField(default=False)
    is_active = models.BooleanField(default=False)  
    
    is_email_verified = models.BooleanField(default=False)
    
    otp = models.CharField(max_length=6, blank=True, null=True)
    otp_expires_at = models.DateTimeField(blank=True, null=True)

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['name']  
    
    objects = UserManagerEmail()
    
    def clean(self):
        """Clean and validate the model"""
        super().clean()
        
        # Validate email format
        if self.email:
            if '@' not in self.email:
                raise ValidationError({'email': 'Enter a valid email address.'})
    

    def save(self, *args, **kwargs):
        is_new = self._state.adding

        if is_new and not self.refer_code:
            self.refer_code = self.generate_refer_code()

        self.clean()

        if self.is_superuser:
            from apps.core.permissions.permissions import get_permissions
            self.permissions = get_permissions()
        
        else:
            self.permissions = get_role_based_permissions(self.role)
        
        if self.is_superuser:
            self.is_staff = True
        
        super().save(*args, **kwargs)

    def generate_refer_code(self):
        """Generate a unique referral code"""
        while True:
            # Format: REF + 6 random alphanumeric characters
            chars = ''.join(random.choices(string.ascii_uppercase + string.digits, k=6))
            code = f"REF{chars}"
            
            # Check if code already exists
            if not User.objects.filter(refer_code=code).exists():
                return code
    
    def __str__(self):
        return f"{self.name} ({self.email})"

    class Meta:
        db_table = 'users_user'
        indexes = [
            models.Index(fields=['email']),
            models.Index(fields=['refer_code']),
            models.Index(fields=['is_active']),
            models.Index(fields=['role']),
        ]
        verbose_name = 'User'
        verbose_name_plural = 'Users'

    @property
    def referral_url(self):
        base_url = getattr(settings, 'FRONTEND_URL', 'http://localhost:5173').rstrip('/')
        return f"{base_url}/register?ref={self.refer_code}"