"""
Saga Pattern Models.

Models for persisting saga execution state, steps, and execution logs.
"""
import uuid

from django.conf import settings
from django.db import models
from django.utils.translation import gettext_lazy as _

from apps.core.tenant.models import TenantAwareModel


# =============================================================================
# Enums
# =============================================================================

class SagaStatus(models.TextChoices):
    """Saga execution status."""
    PENDING = 'pending', _('در انتظار')
    RUNNING = 'running', _('در حال اجرا')
    COMPLETED = 'completed', _('تکمیل شده')
    COMPENSATING = 'compensating', _('در حال جبران')
    COMPENSATED = 'compensated', _('جبران شده')
    FAILED = 'failed', _('با خطا')
    PAUSED = 'paused', _('متوقف')


class StepStatus(models.TextChoices):
    """Step execution status."""
    PENDING = 'pending', _('در انتظار')
    RUNNING = 'running', _('در حال اجرا')
    COMPLETED = 'completed', _('تکمیل شده')
    FAILED = 'failed', _('با خطا')
    COMPENSATING = 'compensating', _('در حال جبران')
    COMPENSATED = 'compensated', _('جبران شده')
    SKIPPED = 'skipped', _('رد شده')


class SagaLogEventType(models.TextChoices):
    """Saga log event types."""
    SAGA_STARTED = 'saga_started', _('Saga شروع شد')
    SAGA_COMPLETED = 'saga_completed', _('Saga تکمیل شد')
    SAGA_FAILED = 'saga_failed', _('Saga با خطا مواجه شد')
    SAGA_COMPENSATING = 'saga_compensating', _('شروع جبران')
    SAGA_COMPENSATED = 'saga_compensated', _('جبران تکمیل شد')
    SAGA_PAUSED = 'saga_paused', _('Saga متوقف شد')
    SAGA_RESUMED = 'saga_resumed', _('Saga ادامه یافت')
    STEP_STARTED = 'step_started', _('گام شروع شد')
    STEP_COMPLETED = 'step_completed', _('گام تکمیل شد')
    STEP_FAILED = 'step_failed', _('گام با خطا مواجه شد')
    STEP_COMPENSATING = 'step_compensating', _('شروع جبران گام')
    STEP_COMPENSATED = 'step_compensated', _('جبران گام تکمیل شد')
    STEP_RETRYING = 'step_retrying', _('تلاش مجدد')


# =============================================================================
# Models
# =============================================================================

class SagaExecution(TenantAwareModel):
    """
    Saga Execution - tracks the overall execution of a saga.
    
    A saga is a sequence of steps that need to be executed atomically.
    If any step fails, compensation (rollback) actions are triggered
    for all previously completed steps in reverse order.
    """
    id = models.UUIDField(
        primary_key=True,
        default=uuid.uuid4,
        editable=False,
    )
    name = models.CharField(
        max_length=255,
        verbose_name=_('نام'),
        help_text=_('نام saga (مثلاً create_product_with_manufacturing)')
    )
    status = models.CharField(
        max_length=20,
        choices=SagaStatus.choices,
        default=SagaStatus.PENDING,
        verbose_name=_('وضعیت'),
    )
    context = models.JSONField(
        default=dict,
        blank=True,
        verbose_name=_('زمینه'),
        help_text=_('داده‌های مشترک بین تمام مراحل'),
    )
    result = models.JSONField(
        default=dict,
        blank=True,
        verbose_name=_('نتیجه'),
        help_text=_('نتیجه نهایی اجرای saga'),
    )
    idempotency_key = models.CharField(
        max_length=255,
        null=True,
        blank=True,
        unique=True,
        verbose_name=_('کلید یکتایی'),
        help_text=_('کلید برای جلوگیری از اجرای مکرر'),
    )
    correlation_id = models.CharField(
        max_length=255,
        null=True,
        blank=True,
        verbose_name=_('شناسه همبستگی'),
        help_text=_('شناسه برای ردیابی در سیستم‌های مختلف'),
    )
    # Optionally link to a workflow instance
    workflow_instance_id = models.UUIDField(
        null=True,
        blank=True,
        verbose_name=_('نمونه فرآیند'),
    )
    max_retries = models.PositiveIntegerField(
        default=3,
        verbose_name=_('حداکثر تلاش'),
    )
    current_step_order = models.PositiveIntegerField(
        default=0,
        verbose_name=_('ترتیب گام فعلی'),
    )
    error_message = models.TextField(
        blank=True,
        null=True,
        verbose_name=_('پیام خطا'),
    )
    started_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='started_sagas',
        verbose_name=_('شروع‌کننده'),
    )
    started_at = models.DateTimeField(
        null=True,
        blank=True,
        verbose_name=_('زمان شروع'),
    )
    completed_at = models.DateTimeField(
        null=True,
        blank=True,
        verbose_name=_('زمان پایان'),
    )
    created_at = models.DateTimeField(
        auto_now_add=True,
        verbose_name=_('تاریخ ایجاد'),
    )
    updated_at = models.DateTimeField(
        auto_now=True,
        verbose_name=_('تاریخ بروزرسانی'),
    )

    class Meta:
        db_table = 'workflow_saga_execution'
        verbose_name = _('اجرای Saga')
        verbose_name_plural = _('اجراهای Saga')
        ordering = ['-created_at']
        indexes = [
            models.Index(fields=['tenant', 'status']),
            models.Index(fields=['idempotency_key']),
            models.Index(fields=['correlation_id']),
            models.Index(fields=['workflow_instance_id']),
        ]

    def __str__(self):
        return f"{self.name} ({self.get_status_display()})"

    @property
    def is_active(self) -> bool:
        return self.status in [SagaStatus.PENDING, SagaStatus.RUNNING, SagaStatus.COMPENSATING]


class SagaStep(models.Model):
    """
    Saga Step - individual step within a saga execution.
    
    Each step has an action (forward) and a compensation action (rollback).
    Steps are executed in order; compensation is executed in reverse order.
    """
    id = models.UUIDField(
        primary_key=True,
        default=uuid.uuid4,
        editable=False,
    )
    saga = models.ForeignKey(
        SagaExecution,
        on_delete=models.CASCADE,
        related_name='steps',
        verbose_name=_('Saga'),
    )
    name = models.CharField(
        max_length=255,
        verbose_name=_('نام گام'),
        help_text=_('نام توصیفی (مثلاً create_part, register_in_manufacturing)'),
    )
    order = models.PositiveIntegerField(
        verbose_name=_('ترتیب'),
        help_text=_('ترتیب اجرای گام'),
    )
    action_type = models.CharField(
        max_length=255,
        verbose_name=_('نوع اکشن'),
        help_text=_('مسیر تابع اکشن (dotted path)'),
    )
    compensation_type = models.CharField(
        max_length=255,
        blank=True,
        null=True,
        verbose_name=_('نوع جبران'),
        help_text=_('مسیر تابع جبران (dotted path)'),
    )
    input_data = models.JSONField(
        default=dict,
        blank=True,
        verbose_name=_('داده ورودی'),
    )
    output_data = models.JSONField(
        default=dict,
        blank=True,
        verbose_name=_('داده خروجی'),
    )
    status = models.CharField(
        max_length=20,
        choices=StepStatus.choices,
        default=StepStatus.PENDING,
        verbose_name=_('وضعیت'),
    )
    retry_count = models.PositiveIntegerField(
        default=0,
        verbose_name=_('تعداد تلاش'),
    )
    max_retries = models.PositiveIntegerField(
        default=3,
        verbose_name=_('حداکثر تلاش'),
    )
    error_message = models.TextField(
        blank=True,
        null=True,
        verbose_name=_('پیام خطا'),
    )
    is_critical = models.BooleanField(
        default=True,
        verbose_name=_('بحرانی'),
        help_text=_('اگر فعال باشد، خطا در این گام باعث شروع جبران می‌شود'),
    )
    timeout_seconds = models.PositiveIntegerField(
        default=300,
        verbose_name=_('مهلت (ثانیه)'),
    )
    started_at = models.DateTimeField(
        null=True,
        blank=True,
        verbose_name=_('زمان شروع'),
    )
    completed_at = models.DateTimeField(
        null=True,
        blank=True,
        verbose_name=_('زمان پایان'),
    )

    class Meta:
        db_table = 'workflow_saga_step'
        verbose_name = _('گام Saga')
        verbose_name_plural = _('گام‌های Saga')
        ordering = ['order']
        unique_together = ['saga', 'order']

    def __str__(self):
        return f"{self.saga.name} - Step {self.order}: {self.name}"


class SagaLog(models.Model):
    """
    Saga Log - audit trail for saga execution events.
    
    Records every significant event during saga execution for
    debugging, monitoring, and replay.
    """
    id = models.UUIDField(
        primary_key=True,
        default=uuid.uuid4,
        editable=False,
    )
    saga = models.ForeignKey(
        SagaExecution,
        on_delete=models.CASCADE,
        related_name='logs',
        verbose_name=_('Saga'),
    )
    step = models.ForeignKey(
        SagaStep,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='logs',
        verbose_name=_('گام'),
    )
    event_type = models.CharField(
        max_length=50,
        choices=SagaLogEventType.choices,
        verbose_name=_('نوع رویداد'),
    )
    message = models.TextField(
        blank=True,
        null=True,
        verbose_name=_('پیام'),
    )
    payload = models.JSONField(
        default=dict,
        blank=True,
        verbose_name=_('داده'),
    )
    error_details = models.JSONField(
        default=dict,
        blank=True,
        verbose_name=_('جزئیات خطا'),
    )
    created_at = models.DateTimeField(
        auto_now_add=True,
        verbose_name=_('زمان'),
    )

    class Meta:
        db_table = 'workflow_saga_log'
        verbose_name = _('لاگ Saga')
        verbose_name_plural = _('لاگ‌های Saga')
        ordering = ['created_at']
        indexes = [
            models.Index(fields=['saga', 'created_at']),
            models.Index(fields=['event_type']),
        ]

    def __str__(self):
        return f"{self.get_event_type_display()} - {self.created_at}"
