"""
PX Action Center models - Action tracking with SLA and escalation

This module implements the PX Action Center that:
- Creates actions automatically from negative feedback
- Tracks SLA deadlines
- Sends reminders before due date
- Escalates overdue actions
- Manages approval workflow
- Tracks evidence and attachments
"""

from datetime import timedelta

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 PriorityChoices, SeverityChoices, TimeStampedModel, UUIDModel


class ActionStatus(models.TextChoices):
    """PX Action status choices"""

    OPEN = "open", "Open"
    IN_PROGRESS = "in_progress", "In Progress"
    PENDING_APPROVAL = "pending_approval", "Pending Approval"
    APPROVED = "approved", "Approved"
    CLOSED = "closed", "Closed"
    CANCELLED = "cancelled", "Cancelled"


class ActionSource(models.TextChoices):
    """PX Action source choices"""

    SURVEY = "survey", "Negative Survey"
    COMPLAINT = "complaint", "Complaint"
    COMPLAINT_RESOLUTION = "complaint_resolution", "Negative Complaint Resolution"
    SOCIAL_MEDIA = "social_media", "Social Media"
    CALL_CENTER = "call_center", "Call Center"
    KPI = "kpi", "KPI Decline"
    MANUAL = "manual", "Manual Entry"

    # Meeting sources
    PATIENT_FAMILY_COMMITTEE = "patient_family_committee", "Patient & Family Rights Committee Meeting"
    EXECUTIVE_COMMITTEE = "executive_committee", "Executive Committee Meeting"
    DEPARTMENT_MEETING = "department_meeting", "Department Meeting"
    ROUNDS = "rounds", "Ward/Department Rounds"
    STAFF_FEEDBACK = "staff_feedback", "Staff Feedback/Comments"
    PATIENT_OBSERVATION = "patient_observation", "Patient Observation"
    QUALITY_AUDIT = "quality_audit", "Quality Audit"
    MANAGEMENT_REVIEW = "management_review", "Management Review"


class PXAction(UUIDModel, TimeStampedModel):
    """
    PX Action - tracks improvement actions with SLA.

    Actions are created automatically from:
    - Negative stage survey scores
    - Negative complaint resolution satisfaction
    - Complaints (if configured)
    - Negative social media sentiment
    - Low call center ratings
    - KPI declines

    Workflow:
    1. OPEN - Action created
    2. IN_PROGRESS - Being worked on
    3. PENDING_APPROVAL - Awaiting PX approval
    4. APPROVED - Approved by PX
    5. CLOSED - Completed
    """

    # Source information (generic foreign key)
    source_type = models.CharField(max_length=50, choices=ActionSource.choices, db_index=True)
    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE, null=True, blank=True)
    object_id = models.UUIDField(null=True, blank=True)
    source_object = GenericForeignKey("content_type", "object_id")

    # Action details
    title = models.CharField(max_length=500)
    description = models.TextField()

    # Organization
    hospital = models.ForeignKey("organizations.Hospital", on_delete=models.CASCADE, related_name="px_actions")
    department = models.ForeignKey(
        "organizations.Department", on_delete=models.SET_NULL, null=True, blank=True, related_name="px_actions"
    )

    # Classification
    category = models.CharField(
        max_length=100,
        choices=[
            ("clinical_quality", "Clinical Quality"),
            ("patient_safety", "Patient Safety"),
            ("service_quality", "Service Quality"),
            ("staff_behavior", "Staff Behavior"),
            ("facility", "Facility & Environment"),
            ("process_improvement", "Process Improvement"),
            ("other", "Other"),
        ],
        db_index=True,
    )

    priority = models.CharField(
        max_length=20, choices=PriorityChoices.choices, default=PriorityChoices.MEDIUM, db_index=True
    )
    severity = models.CharField(
        max_length=20, choices=SeverityChoices.choices, default=SeverityChoices.MEDIUM, db_index=True
    )

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

    # Assignment
    assigned_to = models.ForeignKey(
        "accounts.User", on_delete=models.SET_NULL, null=True, blank=True, related_name="assigned_actions"
    )
    assigned_at = models.DateTimeField(null=True, blank=True)

    # SLA tracking
    due_at = models.DateTimeField(db_index=True, help_text="SLA deadline")
    is_overdue = models.BooleanField(default=False, db_index=True)
    reminder_sent_at = models.DateTimeField(null=True, blank=True)
    escalated_at = models.DateTimeField(null=True, blank=True)
    escalation_level = models.IntegerField(default=0, help_text="Number of times escalated")

    # Approval
    requires_approval = models.BooleanField(default=True, help_text="Requires PX Admin approval before closure")
    approved_by = models.ForeignKey(
        "accounts.User", on_delete=models.SET_NULL, null=True, blank=True, related_name="approved_actions"
    )
    approved_at = models.DateTimeField(null=True, blank=True)

    # Rejection
    rejected_by = models.ForeignKey(
        "accounts.User", on_delete=models.SET_NULL, null=True, blank=True, related_name="rejected_actions"
    )
    rejected_at = models.DateTimeField(null=True, blank=True)
    rejection_reason = models.TextField(blank=True)

    # Closure
    closed_at = models.DateTimeField(null=True, blank=True)
    closed_by = models.ForeignKey(
        "accounts.User", on_delete=models.SET_NULL, null=True, blank=True, related_name="closed_actions"
    )

    # Action plan and outcome
    action_plan = models.TextField(blank=True)
    outcome = models.TextField(blank=True)

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

    class Meta:
        ordering = ["-created_at"]
        indexes = [
            models.Index(fields=["status", "-created_at"]),
            models.Index(fields=["hospital", "status", "-created_at"]),
            models.Index(fields=["assigned_to", "status", "-created_at"]),
            models.Index(fields=["department", "status", "-created_at"]),
            models.Index(fields=["is_overdue", "status"]),
            models.Index(fields=["due_at", "status"]),
            models.Index(fields=["source_type", "-created_at"]),
        ]

    def __str__(self):
        return f"{self.title} ({self.status})"

    def save(self, *args, **kwargs):
        """Calculate SLA due date on creation"""
        if not self.due_at:
            self.due_at = self.calculate_sla_due_date()
        super().save(*args, **kwargs)

    def calculate_sla_due_date(self):
        """Calculate SLA due date based on severity"""
        sla_hours = settings.SLA_DEFAULTS["action"].get(self.severity, settings.SLA_DEFAULTS["action"]["medium"])
        return timezone.now() + timedelta(hours=sla_hours)

    def check_overdue(self):
        """Check if action is overdue"""
        if self.status in [ActionStatus.CLOSED, ActionStatus.CANCELLED]:
            return False

        if timezone.now() > self.due_at:
            if not self.is_overdue:
                self.is_overdue = True
                self.save(update_fields=["is_overdue"])
            return True
        return False


class PXActionLog(UUIDModel, TimeStampedModel):
    """
    Action log entry - tracks updates and discussions.
    """

    action = models.ForeignKey(PXAction, on_delete=models.CASCADE, related_name="logs")

    log_type = models.CharField(
        max_length=50,
        choices=[
            ("status_change", "Status Change"),
            ("assignment", "Assignment"),
            ("escalation", "Escalation"),
            ("note", "Note"),
            ("evidence", "Evidence Added"),
            ("approval", "Approval"),
            ("sla_reminder", "SLA Reminder"),
        ],
        db_index=True,
    )

    message = models.TextField()

    created_by = models.ForeignKey("accounts.User", on_delete=models.SET_NULL, null=True, related_name="action_logs")

    # Status change tracking
    old_status = models.CharField(max_length=20, blank=True)
    new_status = models.CharField(max_length=20, blank=True)

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

    class Meta:
        ordering = ["-created_at"]
        indexes = [
            models.Index(fields=["action", "-created_at"]),
        ]

    def __str__(self):
        return f"{self.action} - {self.log_type} - {self.created_at.strftime('%Y-%m-%d %H:%M')}"


class PXActionAttachment(UUIDModel, TimeStampedModel):
    """Action attachment - evidence, documents, etc."""

    action = models.ForeignKey(PXAction, on_delete=models.CASCADE, related_name="attachments")

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

    uploaded_by = models.ForeignKey(
        "accounts.User", on_delete=models.SET_NULL, null=True, related_name="action_attachments"
    )

    description = models.TextField(blank=True)
    is_evidence = models.BooleanField(default=False, help_text="Mark as evidence for closure")

    class Meta:
        ordering = ["-created_at"]

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


class PXActionSLAConfig(UUIDModel, TimeStampedModel):
    """
    SLA configuration for PX Actions.

    Allows per-hospital or per-department SLA customization.
    """

    name = models.CharField(max_length=200)

    # Scope
    hospital = models.ForeignKey(
        "organizations.Hospital", on_delete=models.CASCADE, null=True, blank=True, related_name="action_sla_configs"
    )
    department = models.ForeignKey(
        "organizations.Department", on_delete=models.CASCADE, null=True, blank=True, related_name="action_sla_configs"
    )

    # SLA durations (in hours) by severity
    critical_hours = models.IntegerField(default=24)
    high_hours = models.IntegerField(default=48)
    medium_hours = models.IntegerField(default=72)
    low_hours = models.IntegerField(default=120)

    # Reminder configuration
    reminder_hours_before = models.IntegerField(default=4, help_text="Send reminder X hours before due")

    # Escalation configuration
    auto_escalate = models.BooleanField(default=True, help_text="Automatically escalate when overdue")
    escalation_delay_hours = models.IntegerField(default=2, help_text="Hours after overdue before escalation")

    is_active = models.BooleanField(default=True)

    class Meta:
        ordering = ["hospital", "name"]

    def __str__(self):
        scope = self.hospital.name if self.hospital else "Global"
        return f"{self.name} ({scope})"


class RoutingRule(UUIDModel, TimeStampedModel):
    """
    Routing rule - determines where actions are assigned.

    Rules can be based on:
    - Source type
    - Category
    - Severity
    - Hospital/Department
    """

    name = models.CharField(max_length=200)
    description = models.TextField(blank=True)

    # Conditions
    source_type = models.CharField(max_length=50, choices=ActionSource.choices, blank=True)
    category = models.CharField(max_length=100, blank=True)
    severity = models.CharField(max_length=20, choices=SeverityChoices.choices, blank=True)

    hospital = models.ForeignKey(
        "organizations.Hospital", on_delete=models.CASCADE, null=True, blank=True, related_name="routing_rules"
    )
    department = models.ForeignKey(
        "organizations.Department", on_delete=models.CASCADE, null=True, blank=True, related_name="routing_rules"
    )

    # Routing target
    assign_to_role = models.CharField(max_length=50, blank=True, help_text="Role to assign to (e.g., 'PX Employee')")
    assign_to_user = models.ForeignKey(
        "accounts.User", on_delete=models.SET_NULL, null=True, blank=True, related_name="routing_rules"
    )
    assign_to_department = models.ForeignKey(
        "organizations.Department",
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="routing_target_rules",
        help_text="Department to assign to",
    )

    # Priority
    priority = models.IntegerField(default=0, help_text="Higher priority rules are evaluated first")

    is_active = models.BooleanField(default=True)

    class Meta:
        ordering = ["-priority", "name"]

    def __str__(self):
        return self.name
