"""
Observations models - Staff observation reporting for Al Hammadi.

This module implements the observation reporting system that:
- Allows anonymous submission (no login required)
- Supports optional staff identification
- Tracks observation lifecycle with status changes
- Links to departments and action center
- Maintains audit trail with notes and status logs
"""
import secrets
import string

from django.conf import settings
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.db import models
from django.utils import timezone

from apps.core.models import TimeStampedModel, UUIDModel


def generate_tracking_code():
    """Generate a unique tracking code for observations."""
    # Format: OBS-XXXXXX (6 alphanumeric characters)
    chars = string.ascii_uppercase + string.digits
    code = ''.join(secrets.choice(chars) for _ in range(6))
    return f"OBS-{code}"


class ObservationSeverity(models.TextChoices):
    """Observation severity choices."""
    LOW = 'low', 'Low'
    MEDIUM = 'medium', 'Medium'
    HIGH = 'high', 'High'
    CRITICAL = 'critical', 'Critical'


class ObservationStatus(models.TextChoices):
    """Observation status choices."""
    NEW = 'new', 'New'
    TRIAGED = 'triaged', 'Triaged'
    ASSIGNED = 'assigned', 'Assigned'
    IN_PROGRESS = 'in_progress', 'In Progress'
    RESOLVED = 'resolved', 'Resolved'
    CLOSED = 'closed', 'Closed'
    REJECTED = 'rejected', 'Rejected'
    DUPLICATE = 'duplicate', 'Duplicate'


class ObservationCategory(UUIDModel, TimeStampedModel):
    """
    Observation category for classifying reported issues.

    Supports bilingual names (English and Arabic).
    """
    name_en = models.CharField(max_length=200, verbose_name="Name (English)")
    name_ar = models.CharField(max_length=200, blank=True, verbose_name="Name (Arabic)")
    description = models.TextField(blank=True)

    # Status and ordering
    is_active = models.BooleanField(default=True, db_index=True)
    sort_order = models.IntegerField(default=0, help_text="Lower numbers appear first")

    # Icon for UI (optional)
    icon = models.CharField(max_length=50, blank=True, help_text="Bootstrap icon class")

    class Meta:
        ordering = ['sort_order', 'name_en']
        verbose_name = 'Observation Category'
        verbose_name_plural = 'Observation Categories'

    def __str__(self):
        return self.name_en

    @property
    def name(self):
        """Return English name as default."""
        return self.name_en


class Observation(UUIDModel, TimeStampedModel):
    """
    Observation - Staff-reported issue or concern.

    Key features:
    - Anonymous submission supported (no login required)
    - Optional reporter identification (staff_id, name)
    - Unique tracking code for public lookup
    - Full lifecycle management with status tracking
    - Links to departments and action center
    """
    # Tracking
    tracking_code = models.CharField(
        max_length=20,
        unique=True,
        db_index=True,
        default=generate_tracking_code,
        help_text="Unique code for tracking this observation"
    )

    # Classification
    category = models.ForeignKey(
        ObservationCategory,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='observations'
    )

    # Content
    title = models.CharField(
        max_length=300,
        blank=True,
        help_text="Optional short title"
    )
    description = models.TextField(
        help_text="Detailed description of the observation"
    )

    # Severity
    severity = models.CharField(
        max_length=20,
        choices=ObservationSeverity.choices,
        default=ObservationSeverity.MEDIUM,
        db_index=True
    )

    # Location and timing
    location_text = models.CharField(
        max_length=500,
        blank=True,
        help_text="Where the issue was observed (building, floor, room, etc.)"
    )
    incident_datetime = models.DateTimeField(
        default=timezone.now,
        help_text="When the issue was observed"
    )

    # Optional reporter information (anonymous supported)
    reporter_staff_id = models.CharField(
        max_length=50,
        blank=True,
        help_text="Optional staff ID of the reporter"
    )
    reporter_name = models.CharField(
        max_length=200,
        blank=True,
        help_text="Optional name of the reporter"
    )
    reporter_phone = models.CharField(
        max_length=20,
        blank=True,
        help_text="Optional phone number for follow-up"
    )
    reporter_email = models.EmailField(
        blank=True,
        help_text="Optional email for follow-up"
    )

    # Status and workflow
    status = models.CharField(
        max_length=20,
        choices=ObservationStatus.choices,
        default=ObservationStatus.NEW,
        db_index=True
    )

    # Organization (required for tenant isolation)
    hospital = models.ForeignKey(
        'organizations.Hospital',
        on_delete=models.CASCADE,
        related_name='observations',
        help_text="Hospital where observation was made"
    )

    # Staff member mentioned in observation (optional, for AI-matching like complaints)
    staff = models.ForeignKey(
        'organizations.Staff',
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='observations',
        help_text="Staff member mentioned in observation"
    )

    # Source tracking
    source = models.CharField(
        max_length=50,
        choices=[
            ('staff_portal', 'Staff Portal'),
            ('web_form', 'Web Form'),
            ('mobile_app', 'Mobile App'),
            ('email', 'Email'),
            ('call_center', 'Call Center'),
            ('other', 'Other'),
        ],
        default='staff_portal',
        help_text="How the observation was submitted"
    )

    # Internal routing
    assigned_department = models.ForeignKey(
        'organizations.Department',
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='assigned_observations',
        help_text="Department responsible for handling this observation"
    )
    assigned_to = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='assigned_observations',
        help_text="User assigned to handle this observation"
    )

    # Triage information
    triaged_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='triaged_observations'
    )
    triaged_at = models.DateTimeField(null=True, blank=True)

    # Resolution
    resolved_at = models.DateTimeField(null=True, blank=True)
    resolved_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='resolved_observations'
    )
    resolution_notes = models.TextField(blank=True)

    # Closure
    closed_at = models.DateTimeField(null=True, blank=True)
    closed_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='closed_observations'
    )

    # Link to Action Center (if converted to action)
    # Using GenericForeignKey on PXAction side, store action_id here for quick reference
    action_id = models.UUIDField(
        null=True,
        blank=True,
        help_text="ID of linked PX Action if converted"
    )

    # Metadata
    client_ip = 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=['hospital', 'status', '-created_at']),
            models.Index(fields=['status', '-created_at']),
            models.Index(fields=['severity', '-created_at']),
            models.Index(fields=['tracking_code']),
            models.Index(fields=['assigned_department', 'status']),
            models.Index(fields=['assigned_to', 'status']),
        ]
        permissions = [
            ('triage_observation', 'Can triage observations'),
            ('manage_categories', 'Can manage observation categories'),
        ]

    def __str__(self):
        return f"{self.tracking_code} - {self.title or self.description[:50]}"

    def save(self, *args, **kwargs):
        """Ensure tracking code is unique."""
        if not self.tracking_code:
            self.tracking_code = generate_tracking_code()

        # Ensure uniqueness
        while Observation.objects.filter(tracking_code=self.tracking_code).exclude(pk=self.pk).exists():
            self.tracking_code = generate_tracking_code()

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

    @property
    def is_anonymous(self):
        """Check if the observation was submitted anonymously."""
        return not (self.reporter_staff_id or self.reporter_name)

    @property
    def reporter_display(self):
        """Get display name for reporter."""
        if self.reporter_name:
            return self.reporter_name
        if self.reporter_staff_id:
            return f"Staff ID: {self.reporter_staff_id}"
        return "Anonymous"

    def get_severity_color(self):
        """Get Bootstrap color class for severity."""
        colors = {
            'low': 'success',
            'medium': 'warning',
            'high': 'danger',
            'critical': 'dark',
        }
        return colors.get(self.severity, 'secondary')

    def get_status_color(self):
        """Get Bootstrap color class for status."""
        colors = {
            'new': 'primary',
            'triaged': 'info',
            'assigned': 'info',
            'in_progress': 'warning',
            'resolved': 'success',
            'closed': 'secondary',
            'rejected': 'danger',
            'duplicate': 'secondary',
        }
        return colors.get(self.status, 'secondary')


class ObservationAttachment(UUIDModel, TimeStampedModel):
    """
    Attachment for an observation (photos, documents, etc.).
    """
    observation = models.ForeignKey(
        Observation,
        on_delete=models.CASCADE,
        related_name='attachments'
    )

    file = models.FileField(
        upload_to='observations/%Y/%m/%d/',
        help_text="Uploaded file"
    )
    filename = models.CharField(max_length=500, blank=True)
    file_type = models.CharField(max_length=100, blank=True)
    file_size = models.IntegerField(
        default=0,
        help_text="File size in bytes"
    )

    description = models.CharField(max_length=500, blank=True)

    class Meta:
        ordering = ['-created_at']

    def __str__(self):
        return f"{self.observation.tracking_code} - {self.filename}"

    def save(self, *args, **kwargs):
        """Extract file metadata on save."""
        if self.file:
            if not self.filename:
                self.filename = self.file.name
            if not self.file_size and hasattr(self.file, 'size'):
                self.file_size = self.file.size
            if not self.file_type:
                import mimetypes
                self.file_type = mimetypes.guess_type(self.file.name)[0] or ''
        super().save(*args, **kwargs)


class ObservationNote(UUIDModel, TimeStampedModel):
    """
    Internal note on an observation.

    Used by PX360 staff to add comments and updates.
    """
    observation = models.ForeignKey(
        Observation,
        on_delete=models.CASCADE,
        related_name='notes'
    )

    note = models.TextField()

    created_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        related_name='observation_notes'
    )

    # Flag for internal-only notes
    is_internal = models.BooleanField(
        default=True,
        help_text="Internal notes are not visible to public"
    )

    class Meta:
        ordering = ['-created_at']

    def __str__(self):
        return f"Note on {self.observation.tracking_code} by {self.created_by}"


class ObservationStatusLog(UUIDModel, TimeStampedModel):
    """
    Status change log for observations.

    Tracks all status transitions for audit trail.
    """
    observation = models.ForeignKey(
        Observation,
        on_delete=models.CASCADE,
        related_name='status_logs'
    )

    from_status = models.CharField(
        max_length=20,
        choices=ObservationStatus.choices,
        blank=True
    )
    to_status = models.CharField(
        max_length=20,
        choices=ObservationStatus.choices
    )

    changed_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='observation_status_changes'
    )

    comment = models.TextField(
        blank=True,
        help_text="Optional comment about the status change"
    )

    class Meta:
        ordering = ['-created_at']
        verbose_name = 'Observation Status Log'
        verbose_name_plural = 'Observation Status Logs'

    def __str__(self):
        return f"{self.observation.tracking_code}: {self.from_status} → {self.to_status}"
