"""Delegation Engine domain models.

Model inventory
---------------
DelegationScope  — enum: all / assignments / approvals / tasks
DelegationRule   — core entity: delegation rule with date range
DelegationLog    — audit trail of delegation activations
"""

from __future__ import annotations

from typing import ClassVar

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.translation import gettext_lazy as _

from simorgh.core.models import (
    TenantScopedModel,
    TimeStampedModel,
    UUIDModel,
)


class DelegationScope(models.TextChoices):
    ALL         = "all",         _("All")
    ASSIGNMENTS = "assignments", _("Assignments")
    APPROVALS   = "approvals",   _("Approvals")
    TASKS       = "tasks",       _("Tasks")


class DelegationRule(UUIDModel, TenantScopedModel):
    """A delegation rule defining work rerouting for a date range."""

    delegator = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name="delegations_given",
        verbose_name=_("delegator"),
    )
    delegate_to = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.PROTECT,
        related_name="delegations_received",
        verbose_name=_("delegate to"),
    )
    delegate_role = models.ForeignKey(
        "iam.Role",
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="delegations",
        verbose_name=_("delegate role"),
    )

    start_date = models.DateTimeField(_("start date"), db_index=True)
    end_date   = models.DateTimeField(_("end date"), db_index=True)

    is_active = models.BooleanField(_("active"), default=True, db_index=True)

    scope = models.CharField(
        _("scope"),
        max_length=16,
        choices=DelegationScope.choices,
        default=DelegationScope.ALL,
        db_index=True,
    )

    reason = models.TextField(_("reason"), blank=True, default="")

    created_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="+",
        verbose_name=_("created by"),
        editable=False,
    )

    class Meta(TenantScopedModel.Meta):
        verbose_name        = _("delegation rule")
        verbose_name_plural = _("delegation rules")
        ordering            = ("-created_at",)
        indexes: ClassVar = [
            *TenantScopedModel.Meta.indexes,
            models.Index(fields=("tenant", "delegator", "is_active"), name="deleg_ten_dlgr_actv"),
            models.Index(fields=("tenant", "delegate_to", "is_active"), name="deleg_ten_dlgee_actv"),
            models.Index(fields=("tenant", "start_date", "end_date"), name="deleg_ten_dates"),
        ]
        constraints = (
            models.CheckConstraint(
                check=models.Q(start_date__lt=models.F("end_date")),
                name="delegations_rule_start_before_end",
            ),
        )

    def __str__(self) -> str:
        return _("Delegation: {delegator} → {delegate}").format(
            delegator=self.delegator,
            delegate=self.delegate_to,
        )


class DelegationAction(models.TextChoices):
    REROUTED = "rerouted", _("Rerouted")
    RETURNED = "returned", _("Returned")
    EXPIRED  = "expired",  _("Expired")


class DelegationLog(UUIDModel, TimeStampedModel):
    """Records each time a delegation rule is activated or expires."""

    tenant = models.ForeignKey(
        "tenants.Tenant",
        on_delete=models.CASCADE,
        related_name="+",
        verbose_name=_("tenant"),
    )
    rule = models.ForeignKey(
        DelegationRule,
        on_delete=models.CASCADE,
        related_name="logs",
        verbose_name=_("delegation rule"),
    )
    action = models.CharField(
        _("action"),
        max_length=16,
        choices=DelegationAction.choices,
        db_index=True,
    )

    content_type = models.ForeignKey(
        ContentType,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        verbose_name=_("entity type"),
    )
    object_id = models.PositiveIntegerField(_("entity id"), null=True, blank=True)
    content_object = GenericForeignKey("content_type", "object_id")

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

    class Meta:
        verbose_name        = _("delegation log")
        verbose_name_plural = _("delegation logs")
        ordering            = ("-created_at",)
        indexes: ClassVar = [
            models.Index(fields=("tenant", "rule", "action"), name="deleg_log_ten_rule_actn"),
            models.Index(fields=("content_type", "object_id"), name="deleg_log_content_obj"),
        ]

    def __str__(self) -> str:
        return f"DelegationLog(rule={self.rule_id}, action={self.action})"
