"""
Journeys models - Patient journey templates and instances

This module implements the core journey tracking system:
- Journey templates define the stages for EMS/Inpatient/OPD pathways
- Journey instances track actual patient encounters
- Stage instances track completion of each stage
- Integration events trigger stage completions
"""

from django.db import models

from apps.core.models import BaseChoices, StatusChoices, TimeStampedModel, UUIDModel


class JourneyType(BaseChoices):
    """Journey type choices"""

    EMS = "ems", "EMS (Emergency Medical Services)"
    INPATIENT = "inpatient", "Inpatient"
    OPD = "opd", "OPD (Outpatient Department)"
    DAY_CASE = "day_case", "Day Case"


class StageStatus(BaseChoices):
    """Stage instance status choices"""

    PENDING = "pending", "Pending"
    IN_PROGRESS = "in_progress", "In Progress"
    COMPLETED = "completed", "Completed"
    SKIPPED = "skipped", "Skipped"
    CANCELLED = "cancelled", "Cancelled"


class PatientJourneyTemplate(UUIDModel, TimeStampedModel):
    """
    Journey template defines the stages for a patient journey type.

    Example: OPD journey with stages:
    1. MD Consultation (trigger: OPD_VISIT_COMPLETED)
    2. Lab (trigger: LAB_ORDER_COMPLETED)
    3. Radiology (trigger: RADIOLOGY_REPORT_FINALIZED)
    4. Pharmacy (trigger: PHARMACY_DISPENSED)
    """

    name = models.CharField(max_length=200)
    name_ar = models.CharField(max_length=200, blank=True, verbose_name="Name (Arabic)")
    journey_type = models.CharField(max_length=20, choices=JourneyType.choices, db_index=True)
    description = models.TextField(blank=True)

    # Configuration
    hospital = models.ForeignKey(
        "organizations.Hospital",
        on_delete=models.CASCADE,
        related_name="journey_templates",
        help_text="Hospital this template belongs to",
    )
    is_active = models.BooleanField(default=True, db_index=True)
    is_default = models.BooleanField(default=False, help_text="Default template for this journey type in this hospital")

    # Post-discharge survey configuration
    send_post_discharge_survey = models.BooleanField(
        default=False, help_text="Send a comprehensive survey after patient discharge"
    )
    post_discharge_survey_delay_hours = models.IntegerField(
        default=1, help_text="Hours after discharge to send the survey"
    )

    class Meta:
        ordering = ["hospital", "journey_type", "name"]
        unique_together = [["hospital", "journey_type", "name"]]
        indexes = [
            models.Index(fields=["hospital", "journey_type", "is_active"]),
        ]

    def __str__(self):
        return f"{self.hospital.name} - {self.get_journey_type_display()} - {self.name}"


class PatientJourneyStageTemplate(UUIDModel, TimeStampedModel):
    """
    Stage template defines a stage within a journey.

    Each stage:
    - Has a trigger_event_code that maps to integration events
    - Can optionally send a survey when completed
    - Has an order for sequencing

    Example: "MD Consultation" stage
    - trigger_event_code: "OPD_VISIT_COMPLETED"
    - survey_template: MD Consultation Survey
    - auto_send_survey: True
    """

    journey_template = models.ForeignKey(PatientJourneyTemplate, on_delete=models.CASCADE, related_name="stages")

    # Stage identification
    name = models.CharField(max_length=200)
    name_ar = models.CharField(max_length=200, blank=True)
    code = models.CharField(
        max_length=50, help_text="Unique code for this stage (e.g., OPD_MD_CONSULT, LAB, RADIOLOGY)"
    )
    order = models.IntegerField(default=0, help_text="Order of this stage in the journey")

    # Event trigger configuration
    trigger_event_code = models.CharField(
        max_length=100,
        help_text="Event code that triggers completion of this stage (e.g., OPD_VISIT_COMPLETED)",
        db_index=True,
    )

    # Survey configuration
    # Note: survey_template is used for post-discharge survey question merging
    # Auto-sending surveys after each stage has been removed
    survey_template = models.ForeignKey(
        "surveys.SurveyTemplate",
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="journey_stages",
        help_text="Survey template containing questions for this stage (merged into post-discharge survey)",
    )

    # Configuration
    is_optional = models.BooleanField(default=False, help_text="Can this stage be skipped?")
    is_active = models.BooleanField(default=True)

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

    def __str__(self):
        return f"{self.journey_template.name} - {self.name} (Order: {self.order})"


class PatientJourneyInstance(UUIDModel, TimeStampedModel):
    """
    Journey instance tracks an actual patient's journey through a pathway.

    Linked to:
    - Journey template (defines the stages)
    - Patient (who is going through the journey)
    - Encounter ID (from HIS system)
    """

    journey_template = models.ForeignKey(PatientJourneyTemplate, on_delete=models.PROTECT, related_name="instances")

    # Patient and encounter information
    patient = models.ForeignKey("organizations.Patient", on_delete=models.CASCADE, related_name="journeys")
    encounter_id = models.CharField(max_length=100, unique=True, help_text="Unique encounter ID from HIS system")

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

    # Status tracking
    status = models.CharField(max_length=20, choices=StatusChoices.choices, default=StatusChoices.ACTIVE, db_index=True)

    # Timestamps
    started_at = models.DateTimeField(auto_now_add=True)
    completed_at = models.DateTimeField(null=True, blank=True)

    # Metadata
    metadata = models.JSONField(default=dict, blank=True, help_text="Additional metadata from HIS system")

    class Meta:
        ordering = ["-started_at"]
        indexes = [
            models.Index(fields=["patient", "-started_at"]),
            models.Index(fields=["hospital", "status", "-started_at"]),
        ]

    def __str__(self):
        return f"{self.patient.get_full_name()} - {self.journey_template.name} ({self.encounter_id})"

    def get_completion_percentage(self):
        """Calculate journey completion percentage"""
        total_stages = self.stage_instances.count()
        if total_stages == 0:
            return 0
        completed_stages = self.stage_instances.filter(status=StageStatus.COMPLETED).count()
        return int((completed_stages / total_stages) * 100)

    def is_complete(self):
        """Check if all required stages are completed"""
        required_stages = self.stage_instances.filter(stage_template__is_optional=False)
        return not required_stages.exclude(status=StageStatus.COMPLETED).exists()


class PatientJourneyStageInstance(UUIDModel, TimeStampedModel):
    """
    Stage instance tracks completion of a specific stage in a patient's journey.

    Status flow:
    1. PENDING - Stage created but not started
    2. IN_PROGRESS - Event received, processing
    3. COMPLETED - Stage completed successfully
    4. SKIPPED - Stage skipped (optional stages only)
    5. CANCELLED - Journey cancelled

    When completed:
    - If auto_send_survey=True, create SurveyInstance
    - Record completion timestamp
    - Attach physician/department if provided
    """

    journey_instance = models.ForeignKey(
        PatientJourneyInstance, on_delete=models.CASCADE, related_name="stage_instances"
    )
    stage_template = models.ForeignKey(PatientJourneyStageTemplate, on_delete=models.PROTECT, related_name="instances")

    # Status
    status = models.CharField(max_length=20, choices=StageStatus.choices, default=StageStatus.PENDING, db_index=True)

    # Completion details
    completed_at = models.DateTimeField(null=True, blank=True, db_index=True)

    # Context from event
    staff = models.ForeignKey(
        "organizations.Staff",
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="journey_stages",
        help_text="Staff member associated with this stage",
    )
    department = models.ForeignKey(
        "organizations.Department",
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="journey_stages",
        help_text="Department where this stage occurred",
    )

    # Metadata
    metadata = models.JSONField(default=dict, blank=True, help_text="Additional data from integration event")

    class Meta:
        ordering = ["journey_instance", "stage_template__order"]
        unique_together = [["journey_instance", "stage_template"]]
        indexes = [
            models.Index(fields=["journey_instance", "status"]),
            models.Index(fields=["status", "completed_at"]),
        ]

    def __str__(self):
        return f"{self.journey_instance.encounter_id} - {self.stage_template.name} ({self.status})"

    def can_complete(self):
        """Check if this stage can be completed"""
        return self.status in [StageStatus.PENDING, StageStatus.IN_PROGRESS]

    def complete(self, staff=None, department=None, metadata=None):
        """
        Mark stage as completed.

        This method should be called by event processing task.
        It will:
        1. Update status to COMPLETED
        2. Set completion timestamp
        3. Attach staff, department
        """
        from django.utils import timezone

        if not self.can_complete():
            return False

        self.status = StageStatus.COMPLETED
        self.completed_at = timezone.now()

        if staff:
            self.staff = staff
        if department:
            self.department = department
        if metadata:
            self.metadata.update(metadata)

        self.save()

        # Check if journey is complete
        if self.journey_instance.is_complete():
            self.journey_instance.status = StatusChoices.COMPLETED
            self.journey_instance.completed_at = timezone.now()
            self.journey_instance.save()

        return True
