"""
References models - Reference Section for document management

This module implements a file server system for managing reference documents
with folder categorization, version control, and role-based access control.
"""
import os

from django.contrib.auth import get_user_model
from django.core.exceptions import ValidationError
from django.db import models

from apps.core.models import TenantModel, TimeStampedModel, UUIDModel, SoftDeleteModel

User = get_user_model()


def document_upload_path(instance, filename):
    """
    Generate upload path for reference documents.

    Format: references/<hospital_id>/YYYY/MM/DD/<uuid>_<filename>
    """
    hospital_id = instance.hospital.id if instance.hospital else 'default'
    from django.utils import timezone
    date_str = timezone.now().strftime('%Y/%m/%d')
    # Get file extension
    ext = os.path.splitext(filename)[1]
    return f'references/{hospital_id}/{date_str}/{instance.id}{ext}'


class ReferenceFolder(UUIDModel, TimeStampedModel, SoftDeleteModel, TenantModel):
    """
    Reference Folder model for organizing documents into hierarchical folders.

    Features:
    - Hospital-specific folders (via TenantModel)
    - Nested folder hierarchy via self-referential parent field
    - Bilingual support (English/Arabic)
    - Role-based access control
    - Soft delete support
    """
    # Bilingual folder name
    name = models.CharField(max_length=200, db_index=True)
    name_ar = models.CharField(max_length=200, blank=True, verbose_name="Name (Arabic)")

    # Description
    description = models.TextField(blank=True)
    description_ar = models.TextField(blank=True, verbose_name="Description (Arabic)")

    # Hierarchy - self-referential for nested folders
    parent = models.ForeignKey(
        'self',
        on_delete=models.CASCADE,
        null=True,
        blank=True,
        related_name='subfolders',
        help_text="Parent folder for nested structure"
    )

    # UI customization
    icon = models.CharField(
        max_length=50,
        blank=True,
        help_text="Icon class (e.g., 'fa-folder', 'fa-file-pdf')"
    )
    color = models.CharField(
        max_length=7,
        blank=True,
        help_text="Hex color code (e.g., '#007bff')"
    )

    # Ordering
    order = models.IntegerField(
        default=0,
        help_text="Display order within parent folder"
    )

    # Role-based access control
    access_roles = models.ManyToManyField(
        'auth.Group',
        blank=True,
        related_name='accessible_folders',
        help_text="Roles that can access this folder (empty = all roles)"
    )

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

    class Meta:
        ordering = ['parent__order', 'order', 'name']
        verbose_name = 'Reference Folder'
        verbose_name_plural = 'Reference Folders'
        indexes = [
            models.Index(fields=['hospital', 'parent', 'order']),
            models.Index(fields=['hospital', 'is_active']),
        ]

    def __str__(self):
        hospital_name = self.hospital.name if self.hospital else 'No Hospital'
        return f"{hospital_name} - {self.name}"

    def get_full_path(self):
        """Get full folder path as a list of folder names"""
        path = [self.name]
        parent = self.parent
        while parent:
            path.insert(0, parent.name)
            parent = parent.parent
        return ' / '.join(path)

    def has_access(self, user):
        """
        Check if user has access to this folder.

        Returns True if:
        - Folder has no access_roles (public to all)
        - User belongs to any of the access_roles
        """
        if not self.access_roles.exists():
            return True
        return user.groups.filter(id__in=self.access_roles.all()).exists()

    def get_subfolders(self):
        """Get all immediate subfolders"""
        return self.subfolders.filter(is_active=True, is_deleted=False)

    def get_documents(self):
        """Get all documents in this folder"""
        return self.documents.filter(is_published=True, is_deleted=False)

    def get_document_count(self):
        """Get count of documents in this folder (including subfolders)"""
        count = self.get_documents().count()
        for subfolder in self.get_subfolders():
            count += subfolder.get_document_count()
        return count


class ReferenceDocument(UUIDModel, TimeStampedModel, SoftDeleteModel, TenantModel):
    """
    Reference Document model for storing and managing documents.

    Features:
    - Multi-version support
    - Multiple file types (PDF, Word, Excel, etc.)
    - Role-based access control
    - Download tracking
    - Bilingual support
    - Soft delete support
    """
    # Folder association
    folder = models.ForeignKey(
        ReferenceFolder,
        on_delete=models.CASCADE,
        related_name='documents',
        null=True,
        blank=True,
        help_text="Folder containing this document"
    )

    # Bilingual title
    title = models.CharField(max_length=500, db_index=True)
    title_ar = models.CharField(max_length=500, blank=True, verbose_name="Title (Arabic)")

    # File information
    file = models.FileField(upload_to=document_upload_path, max_length=500)
    filename = models.CharField(max_length=500, help_text="Original filename")
    file_type = models.CharField(
        max_length=50,
        blank=True,
        help_text="File extension/type (e.g., pdf, docx, xlsx)"
    )
    file_size = models.IntegerField(help_text="File size in bytes")

    # Description
    description = models.TextField(blank=True)
    description_ar = models.TextField(blank=True, verbose_name="Description (Arabic)")

    # Versioning
    version = models.CharField(
        max_length=20,
        default='1.0',
        help_text="Document version (e.g., 1.0, 1.1, 2.0)"
    )
    is_latest_version = models.BooleanField(
        default=True,
        db_index=True,
        help_text="Is this the latest version?"
    )
    parent_document = models.ForeignKey(
        'self',
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='versions',
        help_text="Previous version of this document"
    )

    # Upload tracking
    uploaded_by = models.ForeignKey(
        User,
        on_delete=models.SET_NULL,
        null=True,
        related_name='uploaded_documents'
    )

    # Usage tracking
    download_count = models.IntegerField(default=0, help_text="Number of downloads")
    last_accessed_at = models.DateTimeField(null=True, blank=True)

    # Visibility
    is_published = models.BooleanField(
        default=True,
        db_index=True,
        help_text="Is this document visible to users?"
    )

    # Role-based access control
    access_roles = models.ManyToManyField(
        'auth.Group',
        blank=True,
        related_name='accessible_documents',
        help_text="Roles that can access this document (empty = all roles)"
    )

    # Tags for search
    tags = models.CharField(
        max_length=500,
        blank=True,
        help_text="Comma-separated tags for search (e.g., policy, procedure, handbook)"
    )

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

    class Meta:
        ordering = ['title', '-created_at']
        verbose_name = 'Reference Document'
        verbose_name_plural = 'Reference Documents'
        indexes = [
            models.Index(fields=['hospital', 'folder', 'is_latest_version']),
            models.Index(fields=['hospital', 'is_published']),
            models.Index(fields=['folder', 'title']),
        ]

    def __str__(self):
        title = self.title or self.filename
        version = f" v{self.version}" if self.version else ""
        return f"{title}{version}"

    def clean(self):
        """Validate file type"""
        if self.file:
            ext = os.path.splitext(self.file.name)[1].lower().lstrip('.')
            # Allowed file types - can be extended as needed
            allowed_types = [
                'pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx',
                'txt', 'rtf', 'csv', 'jpg', 'jpeg', 'png', 'gif'
            ]
            if ext not in allowed_types:
                raise ValidationError({
                    'file': f'File type "{ext}" is not allowed. Allowed types: {", ".join(allowed_types)}'
                })

    def save(self, *args, **kwargs):
        """Auto-populate file_type and file_size"""
        if self.file:
            # Extract file extension
            ext = os.path.splitext(self.file.name)[1].lower().lstrip('.')
            self.file_type = ext

            # Get file size if not already set
            if not self.file_size and hasattr(self.file, 'size'):
                self.file_size = self.file.size

        super().save(*args, **kwargs)

    def has_access(self, user):
        """
        Check if user has access to this document.

        Returns True if:
        - Document has no access_roles (public to all)
        - User belongs to any of the access_roles
        """
        if not self.access_roles.exists():
            return True
        return user.groups.filter(id__in=self.access_roles.all()).exists()

    def increment_download_count(self):
        """Increment download count and update last_accessed_at"""
        self.download_count += 1
        from django.utils import timezone
        self.last_accessed_at = timezone.now()
        self.save(update_fields=['download_count', 'last_accessed_at'])

    def get_tags_list(self):
        """Get tags as a list"""
        return [tag.strip() for tag in self.tags.split(',') if tag.strip()]

    def get_file_icon(self):
        """Get icon class based on file type"""
        icon_map = {
            'pdf': 'fa-file-pdf text-danger',
            'doc': 'fa-file-word text-primary',
            'docx': 'fa-file-word text-primary',
            'xls': 'fa-file-excel text-success',
            'xlsx': 'fa-file-excel text-success',
            'ppt': 'fa-file-powerpoint text-warning',
            'pptx': 'fa-file-powerpoint text-warning',
            'jpg': 'fa-file-image text-info',
            'jpeg': 'fa-file-image text-info',
            'png': 'fa-file-image text-info',
            'gif': 'fa-file-image text-info',
            'txt': 'fa-file-lines text-secondary',
        }
        return icon_map.get(self.file_type.lower(), 'fa-file text-secondary')

    def get_file_size_display(self):
        """Get human-readable file size"""
        size = self.file_size
        for unit in ['B', 'KB', 'MB', 'GB']:
            if size < 1024:
                return f"{size:.2f} {unit}"
            size /= 1024
        return f"{size:.2f} TB"

    def get_version_history(self):
        """Get all versions of this document"""
        versions = list(self.versions.all())
        versions.append(self)
        return sorted(versions, key=lambda x: x.version, reverse=True)


class ReferenceDocumentAccess(UUIDModel, TimeStampedModel):
    """
    Reference Document Access model for tracking document access.

    Features:
    - Audit trail for document downloads/views
    - Track user actions on documents
    - IP address logging
    """
    ACTION_CHOICES = [
        ('view', 'Viewed'),
        ('download', 'Downloaded'),
        ('preview', 'Previewed'),
    ]

    # Document reference
    document = models.ForeignKey(
        ReferenceDocument,
        on_delete=models.CASCADE,
        related_name='access_logs'
    )

    # User who accessed the document
    user = models.ForeignKey(
        User,
        on_delete=models.SET_NULL,
        null=True,
        related_name='document_accesses'
    )

    # Action type
    action = models.CharField(
        max_length=20,
        choices=ACTION_CHOICES,
        db_index=True
    )

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

    class Meta:
        ordering = ['-created_at']
        verbose_name = 'Document Access Log'
        verbose_name_plural = 'Document Access Logs'
        indexes = [
            models.Index(fields=['document', '-created_at']),
            models.Index(fields=['user', '-created_at']),
            models.Index(fields=['action', '-created_at']),
        ]

    def __str__(self):
        user_str = self.user.email if self.user else 'Anonymous'
        return f"{user_str} - {self.get_action_display()} - {self.document}"
