"""
Accounts models - Custom User model and roles
"""
import uuid

from django.contrib.auth.models import AbstractUser, Group, Permission, BaseUserManager
from django.db import models

from apps.core.models import TimeStampedModel, UUIDModel


class UserManager(BaseUserManager):
    """
    Custom user manager for email-based authentication.
    """
    def create_user(self, email, password=None, **extra_fields):
        """
        Create and save a regular user with the given email and password.
        """
        if not email:
            raise ValueError('The Email field must be set')
        email = self.normalize_email(email)
        user = self.model(email=email, **extra_fields)
        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_superuser(self, email, password=None, **extra_fields):
        """
        Create and save a superuser with the given email and password.
        """
        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_superuser', True)
        extra_fields.setdefault('is_active', True)

        if extra_fields.get('is_staff') is not True:
            raise ValueError('Superuser must have is_staff=True.')
        if extra_fields.get('is_superuser') is not True:
            raise ValueError('Superuser must have is_superuser=True.')

        return self.create_user(email, password, **extra_fields)


class User(AbstractUser, TimeStampedModel):
    """
    Custom User model extending Django's AbstractUser.
    Uses UUID as primary key and adds additional fields for PX360.
    """
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    
    # Override email to make it unique and required
    email = models.EmailField(unique=True, db_index=True)
    
    # Override username to be optional and non-unique (for backward compatibility)
    username = models.CharField(max_length=150, blank=True, null=True, unique=False)
    
    # Use email as username field for authentication
    USERNAME_FIELD = 'email'
    
    # Required fields when creating superuser
    REQUIRED_FIELDS = ['first_name', 'last_name']
    
    # Custom user manager
    objects = UserManager()
    
    # Additional fields
    phone = models.CharField(max_length=20, blank=True)
    employee_id = models.CharField(max_length=50, blank=True, db_index=True)
    
    # Organization relationships
    hospital = models.ForeignKey(
        'organizations.Hospital',
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='users'
    )
    department = models.ForeignKey(
        'organizations.Department',
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='users'
    )
    
    # Role - using Django's built-in Group for RBAC
    # Groups will represent roles: PX Admin, Hospital Admin, Department Manager, etc.
    
    # Profile
    avatar = models.ImageField(upload_to='avatars/', null=True, blank=True)
    bio = models.TextField(blank=True)
    
    # Preferences
    language = models.CharField(
        max_length=5,
        choices=[('en', 'English'), ('ar', 'Arabic')],
        default='en'
    )
    
    # Status
    is_active = models.BooleanField(default=True)
    
    # Onboarding / Acknowledgement
    is_provisional = models.BooleanField(
        default=False,
        help_text="User is in onboarding process"
    )
    invitation_token = models.CharField(
        max_length=100,
        unique=True,
        null=True,
        blank=True,
        help_text="Token for account activation"
    )
    invitation_expires_at = models.DateTimeField(
        null=True,
        blank=True,
        help_text="When the invitation token expires"
    )
    acknowledgement_completed = models.BooleanField(
        default=False,
        help_text="User has completed acknowledgement wizard"
    )
    acknowledgement_completed_at = models.DateTimeField(
        null=True,
        blank=True,
        help_text="When acknowledgement was completed"
    )
    current_wizard_step = models.IntegerField(
        default=0,
        help_text="Current step in onboarding wizard"
    )
    wizard_completed_steps = models.JSONField(
        default=list,
        blank=True,
        help_text="List of completed wizard step IDs"
    )
    
    class Meta:
        ordering = ['-date_joined']
        indexes = [
            models.Index(fields=['email']),
            models.Index(fields=['employee_id']),
            models.Index(fields=['is_active', '-date_joined']),
        ]
    
    def __str__(self):
        return f"{self.get_full_name()} ({self.email})"
    
    def get_role_names(self):
        """Get list of role names for this user"""
        return list(self.groups.values_list('name', flat=True))
    
    def has_role(self, role_name):
        """Check if user has a specific role"""
        return self.groups.filter(name=role_name).exists()
    
    def is_px_admin(self):
        """Check if user is PX Admin"""
        return self.has_role('PX Admin')
    
    def is_hospital_admin(self):
        """Check if user is Hospital Admin"""
        return self.has_role('Hospital Admin')
    
    def is_department_manager(self):
        """Check if user is Department Manager"""
        return self.has_role('Department Manager')
    
    def needs_onboarding(self):
        """Check if user needs to complete onboarding"""
        return self.is_provisional and not self.acknowledgement_completed
    
    def get_onboarding_progress_percentage(self):
        """Get onboarding progress percentage"""
        from .services import OnboardingService
        return OnboardingService.get_user_progress_percentage(self)


class AcknowledgementContent(UUIDModel, TimeStampedModel):
    """
    Acknowledgement content sections for onboarding wizard.
    Provides bilingual, role-specific educational content.
    """
    ROLE_CHOICES = [
        ('px_admin', 'PX Admin'),
        ('hospital_admin', 'Hospital Admin'),
        ('department_manager', 'Department Manager'),
        ('px_coordinator', 'PX Coordinator'),
        ('physician', 'Physician'),
        ('nurse', 'Nurse'),
        ('staff', 'Staff'),
        ('viewer', 'Viewer'),
    ]
    
    # Target role (leave blank for all roles)
    role = models.CharField(
        max_length=50,
        choices=ROLE_CHOICES,
        null=True,
        blank=True,
        help_text="Target role for this content"
    )
    
    # Content section
    code = models.CharField(
        max_length=100,
        unique=True,
        help_text="Unique code for this content section"
    )
    title_en = models.CharField(max_length=200)
    title_ar = models.CharField(max_length=200, blank=True)
    description_en = models.TextField()
    description_ar = models.TextField(blank=True)
    
    # Content details
    content_en = models.TextField(blank=True)
    content_ar = models.TextField(blank=True)
    
    # Visual elements
    icon = models.CharField(
        max_length=50,
        blank=True,
        help_text="Icon class (e.g., 'fa-user', 'fa-shield')"
    )
    color = models.CharField(
        max_length=7,
        blank=True,
        help_text="Hex color code (e.g., '#007bff')"
    )
    
    # Organization
    order = models.IntegerField(
        default=0,
        help_text="Display order in wizard"
    )
    
    # Status
    is_active = models.BooleanField(default=True)
    
    class Meta:
        ordering = ['role', 'order', 'code']
        indexes = [
            models.Index(fields=['role', 'is_active', 'order']),
            models.Index(fields=['code']),
        ]
    
    def __str__(self):
        role_text = self.get_role_display() if self.role else "All Roles"
        return f"{role_text} - {self.title_en}"


class AcknowledgementChecklistItem(UUIDModel, TimeStampedModel):
    """
    Checklist items that users must acknowledge during onboarding.
    Can be role-specific and linked to content sections.
    """
    ROLE_CHOICES = [
        ('px_admin', 'PX Admin'),
        ('hospital_admin', 'Hospital Admin'),
        ('department_manager', 'Department Manager'),
        ('px_coordinator', 'PX Coordinator'),
        ('physician', 'Physician'),
        ('nurse', 'Nurse'),
        ('staff', 'Staff'),
        ('viewer', 'Viewer'),
    ]
    
    # Target role (leave blank for all roles)
    role = models.CharField(
        max_length=50,
        choices=ROLE_CHOICES,
        null=True,
        blank=True,
        help_text="Target role for this item"
    )
    
    # Linked content (optional)
    content = models.ForeignKey(
        AcknowledgementContent,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='checklist_items',
        help_text="Related content section"
    )
    
    # Item details
    code = models.CharField(
        max_length=100,
        unique=True,
        help_text="Unique code for this checklist item"
    )
    text_en = models.CharField(max_length=500)
    text_ar = models.CharField(max_length=500, blank=True)
    description_en = models.TextField(blank=True)
    description_ar = models.TextField(blank=True)
    
    # Configuration
    is_required = models.BooleanField(
        default=True,
        help_text="Item must be acknowledged"
    )
    order = models.IntegerField(
        default=0,
        help_text="Display order in checklist"
    )
    
    # Status
    is_active = models.BooleanField(default=True)
    
    class Meta:
        ordering = ['role', 'order', 'code']
        indexes = [
            models.Index(fields=['role', 'is_active', 'order']),
            models.Index(fields=['code']),
        ]
    
    def __str__(self):
        role_text = self.get_role_display() if self.role else "All Roles"
        return f"{role_text} - {self.text_en}"


class UserAcknowledgement(UUIDModel, TimeStampedModel):
    """
    Records of user acknowledgements.
    Tracks when each user acknowledges specific items with digital signatures.
    """
    # User
    user = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        related_name='acknowledgements'
    )
    
    # Checklist item
    checklist_item = models.ForeignKey(
        AcknowledgementChecklistItem,
        on_delete=models.CASCADE,
        related_name='user_acknowledgements'
    )
    
    # Acknowledgement details
    is_acknowledged = models.BooleanField(default=True)
    acknowledged_at = models.DateTimeField(auto_now_add=True)
    
    # Digital signature
    signature = models.TextField(
        blank=True,
        help_text="Digital signature data (base64 encoded)"
    )
    signature_ip = models.GenericIPAddressField(
        null=True,
        blank=True,
        help_text="IP address when signed"
    )
    signature_user_agent = models.TextField(
        blank=True,
        help_text="User agent when signed"
    )
    
    # Metadata
    metadata = models.JSONField(
        default=dict,
        blank=True,
        help_text="Additional metadata"
    )
    
    class Meta:
        ordering = ['-acknowledged_at']
        unique_together = [['user', 'checklist_item']]
        indexes = [
            models.Index(fields=['user', '-acknowledged_at']),
            models.Index(fields=['checklist_item', '-acknowledged_at']),
        ]
    
    def __str__(self):
        return f"{self.user.email} - {self.checklist_item.text_en}"


class UserProvisionalLog(UUIDModel, TimeStampedModel):
    """
    Audit trail for provisional user lifecycle.
    Tracks all key events in the onboarding process.
    """
    EVENT_TYPES = [
        ('created', 'User Created'),
        ('invitation_sent', 'Invitation Sent'),
        ('invitation_resent', 'Invitation Resent'),
        ('wizard_started', 'Wizard Started'),
        ('step_completed', 'Wizard Step Completed'),
        ('wizard_completed', 'Wizard Completed'),
        ('user_activated', 'User Activated'),
        ('invitation_expired', 'Invitation Expired'),
    ]
    
    # User
    user = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        related_name='provisional_logs'
    )
    
    # Event details
    event_type = models.CharField(
        max_length=50,
        choices=EVENT_TYPES,
        db_index=True
    )
    description = models.TextField()
    
    # Context
    ip_address = models.GenericIPAddressField(null=True, blank=True)
    user_agent = models.TextField(blank=True)
    
    # Additional data
    metadata = models.JSONField(
        default=dict,
        blank=True,
        help_text="Additional event data"
    )
    
    class Meta:
        ordering = ['-created_at']
        indexes = [
            models.Index(fields=['user', '-created_at']),
            models.Index(fields=['event_type', '-created_at']),
        ]
    
    def __str__(self):
        return f"{self.user.email} - {self.get_event_type_display()} - {self.created_at}"


class Role(models.Model):
    """
    Role model for managing predefined roles and their permissions.
    This is a helper model - actual role assignment uses Django Groups.
    """
    ROLE_CHOICES = [
        ('px_admin', 'PX Admin'),
        ('hospital_admin', 'Hospital Admin'),
        ('department_manager', 'Department Manager'),
        ('px_coordinator', 'PX Coordinator'),
        ('physician', 'Physician'),
        ('nurse', 'Nurse'),
        ('staff', 'Staff'),
        ('viewer', 'Viewer'),
    ]
    
    name = models.CharField(max_length=50, unique=True, choices=ROLE_CHOICES)
    display_name = models.CharField(max_length=100)
    description = models.TextField(blank=True)
    
    # Link to Django Group
    group = models.OneToOneField(Group, on_delete=models.CASCADE, related_name='role_config')
    
    # Permissions
    permissions = models.ManyToManyField(Permission, blank=True)
    
    # Hierarchy level (for escalation logic)
    level = models.IntegerField(default=0, help_text="Higher number = higher authority")
    
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    
    class Meta:
        ordering = ['-level', 'name']
    
    def __str__(self):
        return self.display_name
