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

import uuid

from django.contrib.auth.models import AbstractUser, Group, Permission, BaseUserManager
from django.contrib.contenttypes.fields import GenericForeignKey
from django.db import models
from django.utils.translation import gettext_lazy as _

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)

    # Override username to be optional and non-unique (for backward compatibility)
    # Note: Using email as USERNAME_FIELD for authentication
    username = models.CharField(max_length=150, blank=True, default="", 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)

    # 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")

    # Notification preferences
    notification_email_enabled = models.BooleanField(default=True, help_text="Enable email notifications")
    notification_sms_enabled = models.BooleanField(default=False, help_text="Enable SMS notifications")
    preferred_notification_channel = models.CharField(
        max_length=10,
        choices=[("email", "Email"), ("sms", "SMS"), ("both", "Both")],
        default="email",
        help_text="Preferred notification channel for general notifications",
    )
    explanation_notification_channel = models.CharField(
        max_length=10,
        choices=[("email", "Email"), ("sms", "SMS"), ("both", "Both")],
        default="email",
        help_text="Preferred channel for explanation requests",
    )

    # 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=["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 is_champion(self):
        """Check if user is Champion (assigned as champion on any department)"""
        return hasattr(self, 'staff_profile') and self.staff_profile is not None and self.staff_profile.champion_departments.exists()

    def is_champion_of(self, department):
        """Check if user is Champion of a specific department"""
        return (
            hasattr(self, 'staff_profile')
            and self.staff_profile is not None
            and self.staff_profile.champion_departments.filter(pk=department.pk).exists()
        )

    def is_department_respondent(self):
        """Alias for is_champion() - Champion is the department respondent role"""
        return self.is_champion()

    def is_px_management(self):
        """Check if user is PX Management"""
        return self.has_role("PX Management")

    def is_px_employee(self):
        """Check if user is PX Employee"""
        return self.has_role("PX Employee")

    def is_source_user(self):
        """Check if user is a PX Source User"""
        return self.has_role("PX Source User")

    def is_executive(self):
        """Check if user is Executive (C-Suite/Top Management)"""
        return self.has_role("Executive")

    def is_director(self):
        """Check if user is Director (manages multiple departments via report_to hierarchy)"""
        return self.has_role("Director")

    def get_directed_departments(self):
        """Get departments where this user's direct reports (via report_to) work."""
        from apps.organizations.models import Department

        try:
            my_staff = self.staff_profile
        except Exception:
            return Department.objects.none()

        if not my_staff:
            return Department.objects.none()

        dept_ids = (
            my_staff.__class__.objects.filter(report_to=my_staff)
            .exclude(department__isnull=True)
            .values_list("department_id", flat=True)
        )
        return Department.objects.filter(id__in=dept_ids).distinct()

    def is_basic_staff(self):
        """Check if user only has basic Staff role with no elevated permissions."""
        elevated_roles = [
            "PX Admin", "Hospital Admin", "Department Manager",
            "PX Management", "PX Employee", "Executive", "Director",
        ]
        return not any(self.has_role(r) for r in elevated_roles) and not self.is_champion()

    def get_source_user_profile_active(self):
        """Get active source user profile if exists"""
        if hasattr(self, "source_user_profile"):
            profile = self.source_user_profile
            if profile and profile.is_active:
                return profile
        return None

    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 AcknowledgementCategory(UUIDModel, TimeStampedModel):
    """
    Categories/Departments for acknowledgements.
    Admins can add, edit, or deactivate categories.
    Replaces hardcoded department choices with database-driven categories.
    """

    name_en = models.CharField(max_length=200)
    name_ar = models.CharField(max_length=200, blank=True, help_text="Arabic name")
    code = models.CharField(max_length=50, unique=True, help_text="Unique code (e.g., CLINICS, ADMISSIONS)")
    description = models.TextField(blank=True, help_text="Category description")

    # Display & ordering
    icon = models.CharField(max_length=50, blank=True, help_text="Icon class (e.g., 'building', 'user')")
    color = models.CharField(max_length=7, default="#007bbd", help_text="Hex color code")
    order = models.IntegerField(default=0, help_text="Display order")

    # Status
    is_active = models.BooleanField(default=True, db_index=True)
    is_default = models.BooleanField(default=False, help_text="One of the 14 default categories")

    class Meta:
        ordering = ["order", "name_en"]
        verbose_name_plural = "Acknowledgement Categories"
        indexes = [
            models.Index(fields=["is_active", "order"]),
            models.Index(fields=["is_default"]),
        ]

    def __str__(self):
        return self.name_en

    def get_localized_name(self):
        from django.utils.translation import get_language

        if get_language() == "ar" and self.name_ar:
            return self.name_ar
        return self.name_en

    def activate(self):
        self.is_active = True
        self.save(update_fields=["is_active"])

    def deactivate(self):
        self.is_active = False
        self.save(update_fields=["is_active"])


class AcknowledgementContent(UUIDModel, TimeStampedModel):
    """
    Acknowledgement content sections.
    Provides bilingual educational content for each acknowledgement category.
    """

    # Link to category (replaces role field)
    category = models.ForeignKey(
        AcknowledgementCategory,
        on_delete=models.CASCADE,
        related_name="content_sections",
        help_text="Category this content belongs to",
    )

    # 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")

    # Status
    is_active = models.BooleanField(default=True)

    class Meta:
        ordering = ["category", "order", "code"]
        indexes = [
            models.Index(fields=["category", "is_active", "order"]),
        ]

    def __str__(self):
        return f"{self.category.name_en} - {self.title_en}"

    def get_localized_title(self):
        from django.utils.translation import get_language

        if get_language() == "ar" and self.title_ar:
            return self.title_ar
        return self.title_en

    def get_localized_description(self):
        from django.utils.translation import get_language

        if get_language() == "ar" and self.description_ar:
            return self.description_ar
        return self.description_en

    def get_localized_content(self):
        from django.utils.translation import get_language

        if get_language() == "ar" and self.content_ar:
            return self.content_ar
        return self.content_en


class AcknowledgementChecklistItem(UUIDModel, TimeStampedModel):
    """
    Checklist items that users must acknowledge.
    Each item is linked to a category (department).
    """

    # Link to category (replaces role field)
    category = models.ForeignKey(
        AcknowledgementCategory,
        on_delete=models.PROTECT,
        related_name="checklist_items",
        help_text="Category/Department this acknowledgement belongs to",
    )

    # 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 = ["category", "order", "code"]
        indexes = [
            models.Index(fields=["category", "is_active", "order"]),
        ]

    def __str__(self):
        return f"{self.category.name_en} - {self.text_en}"

    def get_localized_text(self):
        from django.utils.translation import get_language

        if get_language() == "ar" and self.text_ar:
            return self.text_ar
        return self.text_en

    def get_localized_description(self):
        from django.utils.translation import get_language

        if get_language() == "ar" and self.description_ar:
            return self.description_ar
        return self.description_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")

    # PDF document
    pdf_file = models.FileField(
        upload_to="acknowledgements/pdfs/", null=True, blank=True, help_text="PDF document of signed acknowledgement"
    )

    # 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")),
        ("director", _("Director")),
        ("px_management", _("PX Management")),
        ("px_employee", _("PX Employee")),
        ("staff", _("Staff")),
        ("viewer", _("Viewer")),
        ("executive", _("Executive")),
    ]

    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


# Import version models to ensure they are registered with Django
from .version_models import ContentVersion, ChecklistItemVersion, ContentChangeLog


# ============================================================================
# SIMPLE ACKNOWLEDGEMENT MODELS
# ============================================================================


class SimpleAcknowledgement(UUIDModel, TimeStampedModel):
    """
    Simple acknowledgement item that employees must sign.
    """

    title = models.CharField(max_length=200, help_text="Acknowledgement title")
    description = models.TextField(blank=True, help_text="Detailed description")
    pdf_document = models.FileField(
        upload_to="acknowledgements/documents/", null=True, blank=True, help_text="PDF document for employees to review"
    )

    # Status
    is_active = models.BooleanField(default=True, help_text="Show in employee checklist")
    is_required = models.BooleanField(default=True, help_text="Must be signed by all employees")

    # Display order
    order = models.IntegerField(default=0)

    class Meta:
        ordering = ["order", "title"]
        verbose_name = "Acknowledgement"
        verbose_name_plural = "Acknowledgements"

    def __str__(self):
        return self.title

    @property
    def signed_count(self):
        """Number of employees who have signed this acknowledgement."""
        return self.employee_signatures.filter(is_signed=True).count()


class EmployeeAcknowledgement(UUIDModel, TimeStampedModel):
    """
    Records which employees have signed which acknowledgements.
    """

    employee = models.ForeignKey(
        "accounts.User",
        on_delete=models.CASCADE,
        related_name="employee_acknowledgements",
        help_text="Employee who signed",
    )
    acknowledgement = models.ForeignKey(
        SimpleAcknowledgement,
        on_delete=models.CASCADE,
        related_name="employee_signatures",
        help_text="Acknowledgement that was signed",
    )

    # Sent tracking
    sent_at = models.DateTimeField(null=True, blank=True, help_text="When acknowledgement was sent to employee")
    sent_by = models.ForeignKey(
        "accounts.User",
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="sent_acknowledgements",
        help_text="Admin who sent this acknowledgement",
    )

    # Signature details
    is_signed = models.BooleanField(default=False)
    signed_at = models.DateTimeField(null=True, blank=True)
    signature_name = models.CharField(max_length=200, blank=True, help_text="Name used when signing")
    signature_employee_id = models.CharField(max_length=100, blank=True, help_text="Employee ID when signing")

    # Signed PDF
    signed_pdf = models.FileField(
        upload_to="acknowledgements/signed/%Y/%m/", null=True, blank=True, help_text="PDF with employee signature"
    )

    # IP and user agent for audit
    ip_address = models.GenericIPAddressField(null=True, blank=True)
    user_agent = models.TextField(blank=True)

    # Notes
    notes = models.TextField(blank=True, help_text="Admin notes about this acknowledgement")

    class Meta:
        ordering = ["-sent_at", "-signed_at"]
        unique_together = [["employee", "acknowledgement"]]
        verbose_name = "Employee Acknowledgement"
        verbose_name_plural = "Employee Acknowledgements"

    def __str__(self):
        if self.is_signed:
            return f"✓ {self.employee.get_full_name()} - {self.acknowledgement.title}"
        elif self.sent_at:
            return f"→ {self.employee.get_full_name()} - {self.acknowledgement.title} (Sent)"
        return f"○ {self.employee.get_full_name()} - {self.acknowledgement.title}"


class StaffActivityLog(UUIDModel, TimeStampedModel):
    """
    Tracks staff activity for audit and performance monitoring.
    Logs CRUD operations, login/logout, and key workflow actions.
    """

    class ActivityType(models.TextChoices):
        LOGIN = "login", "Login"
        LOGOUT = "logout", "Logout"
        CREATE = "create", "Create"
        UPDATE = "update", "Update"
        DELETE = "delete", "Delete"
        VIEW = "view", "View"
        ASSIGN = "assign", "Assign"
        TRANSFER = "transfer", "Transfer"
        SEND = "send", "Send"
        APPROVE = "approve", "Approve"
        REJECT = "reject", "Reject"
        RESOLVE = "resolve", "Resolve"
        REOPEN = "reopen", "Reopen"
        EXPORT = "export", "Export"
        ANALYZE = "analyze", "Analyze"

    user = models.ForeignKey(
        "accounts.User", on_delete=models.SET_NULL, null=True, blank=True, related_name="activity_logs"
    )

    activity_type = models.CharField(max_length=20, choices=ActivityType.choices, db_index=True)
    description = models.TextField(blank=True)

    content_type = models.ForeignKey(
        "contenttypes.ContentType", on_delete=models.SET_NULL, null=True, blank=True
    )
    object_id = models.UUIDField(null=True, blank=True)
    content_object = GenericForeignKey("content_type", "object_id")

    module = models.CharField(max_length=50, blank=True, help_text="App/module name (e.g., complaints, surveys)")
    action = models.CharField(max_length=100, blank=True, help_text="Specific action identifier")

    ip_address = models.GenericIPAddressField(null=True, blank=True)
    user_agent = models.TextField(blank=True)

    metadata = models.JSONField(default=dict, blank=True)

    class Meta:
        ordering = ["-created_at"]
        indexes = [
            models.Index(fields=["user", "-created_at"]),
            models.Index(fields=["activity_type", "-created_at"]),
            models.Index(fields=["module", "-created_at"]),
            models.Index(fields=["content_type", "object_id"]),
        ]
        verbose_name = "Staff Activity Log"
        verbose_name_plural = "Staff Activity Logs"

    def __str__(self):
        user_name = self.user.get_full_name() if self.user else "System"
        return f"{user_name} - {self.get_activity_type_display()} - {self.description[:50]}"
