"""PCF Taxonomy models — APQC Process Classification Framework.

Three models form the global (tenant-independent) PCF library:

* ``PCFFramework``  — a versioned PCF edition (e.g. Cross-Industry v7.2.1,
                     Automotive v7.2.1, Healthcare v7.2.0 …).
* ``PCFElement``    — a single node in the 4-level hierarchy
                     (Category → Process Group → Process → Activity).
                     Self-referential FK enables arbitrary depth.
* ``PCFMetric``     — APQC standard metrics attached to a PCFElement;
                     used for benchmarking and KPI mapping in later phases.

These are *reference data* shared across all tenants — no tenant FK.
Tenant-specific process definitions live in ``models/process.py`` (Phase 1).
"""

from __future__ import annotations

from typing import ClassVar

from django.db import models
from django.utils.translation import gettext_lazy as _

from simorgh.core.models import TimeStampedModel


# ---------------------------------------------------------------------------
# Choices
# ---------------------------------------------------------------------------

class IndustryChoice(models.TextChoices):
    CROSS_INDUSTRY  = "cross_industry",  _("Cross-Industry")
    AUTOMOTIVE      = "automotive",      _("Automotive")
    HEALTHCARE      = "healthcare",      _("Healthcare")
    EDUCATION       = "education",       _("Education")
    FINANCIAL       = "financial",       _("Financial Services")
    ENERGY          = "energy",          _("Energy & Utilities")
    RETAIL          = "retail",          _("Retail")
    TELECOM         = "telecom",         _("Telecom")
    GOVERNMENT      = "government",      _("Government / Public Sector")
    CONSTRUCTION    = "construction",    _("Construction")
    MANUFACTURING   = "manufacturing",   _("Manufacturing")
    OTHER           = "other",           _("Other")


class PCFLevel(models.IntegerChoices):
    CATEGORY      = 1, _("Category (L1)")
    PROCESS_GROUP = 2, _("Process Group (L2)")
    PROCESS       = 3, _("Process (L3)")
    ACTIVITY      = 4, _("Activity (L4)")


class MetricCategory(models.TextChoices):
    EFFICIENCY    = "efficiency",    _("Process Efficiency")
    EFFECTIVENESS = "effectiveness", _("Process Effectiveness")
    CYCLE_TIME    = "cycle_time",    _("Process Cycle Time")
    COST          = "cost",          _("Process Cost")
    QUALITY       = "quality",       _("Process Quality")
    OTHER         = "other",         _("Other")


# ---------------------------------------------------------------------------
# PCFFramework
# ---------------------------------------------------------------------------

class PCFFramework(TimeStampedModel):
    """A versioned edition of the APQC Process Classification Framework.

    One framework record per (industry × version × language) combination.
    Example: PCF Cross-Industry v7.2.1 (English).
    """

    code = models.CharField(
        _("code"),
        max_length=64,
        unique=True,
        help_text=_('Unique identifier, e.g. "PCF-CI-7.2.1-EN"'),
    )
    name = models.CharField(_("name"), max_length=256)
    industry = models.CharField(
        _("industry"),
        max_length=32,
        choices=IndustryChoice.choices,
        default=IndustryChoice.CROSS_INDUSTRY,
        db_index=True,
    )
    version = models.CharField(_("version"), max_length=32, help_text=_('e.g. "7.2.1"'))
    language = models.CharField(
        _("language"),
        max_length=8,
        default="en",
        help_text=_('ISO 639-1 code, e.g. "en", "fa", "ar"'),
    )
    description = models.TextField(_("description"), blank=True)
    source_url = models.URLField(_("source URL"), blank=True)
    is_active = models.BooleanField(_("active"), default=True, db_index=True)

    class Meta:
        verbose_name = _("PCF framework")
        verbose_name_plural = _("PCF frameworks")
        ordering = ("industry", "version")
        indexes: ClassVar[list[models.Index]] = [
            models.Index(fields=("industry", "is_active")),
        ]

    def __str__(self) -> str:
        return f"{self.name} ({self.version})"


# ---------------------------------------------------------------------------
# PCFElement
# ---------------------------------------------------------------------------

class PCFElement(TimeStampedModel):
    """One node in the APQC PCF hierarchy (Category / Group / Process / Activity).

    Stored flat; parent FK builds the tree.  hierarchy_id uses dot-notation
    matching the official APQC numbering: "1", "1.1", "1.1.1", "1.1.1.1".
    """

    framework = models.ForeignKey(
        PCFFramework,
        on_delete=models.CASCADE,
        related_name="elements",
        verbose_name=_("framework"),
    )
    pcf_id = models.PositiveIntegerField(
        _("PCF ID"),
        help_text=_("Official APQC numeric identifier, e.g. 10002"),
        db_index=True,
    )
    hierarchy_id = models.CharField(
        _("hierarchy ID"),
        max_length=32,
        db_index=True,
        help_text=_('Dot-notation level code, e.g. "1.1.1"'),
    )
    level = models.PositiveSmallIntegerField(
        _("level"),
        choices=PCFLevel.choices,
        db_index=True,
    )
    parent = models.ForeignKey(
        "self",
        on_delete=models.CASCADE,
        null=True,
        blank=True,
        related_name="children",
        verbose_name=_("parent"),
    )
    name_en = models.CharField(_("name (EN)"), max_length=512)
    name_fa = models.CharField(_("name (FA)"), max_length=512, blank=True)
    name_ar = models.CharField(_("name (AR)"), max_length=512, blank=True)
    definition_en = models.TextField(_("definition (EN)"), blank=True)
    definition_fa = models.TextField(_("definition (FA)"), blank=True)
    order = models.PositiveSmallIntegerField(_("order"), default=0, db_index=True)
    is_active = models.BooleanField(_("active"), default=True, db_index=True)

    class Meta:
        verbose_name = _("PCF element")
        verbose_name_plural = _("PCF elements")
        ordering = ("framework", "order", "hierarchy_id")
        indexes: ClassVar[list[models.Index]] = [
            models.Index(fields=("framework", "level")),
            models.Index(fields=("framework", "hierarchy_id")),
        ]
        constraints = [
            models.UniqueConstraint(
                fields=("framework", "pcf_id"),
                name="bpm_pcfelement_unique_pcf_id_per_framework",
            ),
            models.UniqueConstraint(
                fields=("framework", "hierarchy_id"),
                name="bpm_pcfelement_unique_hierarchy_id_per_framework",
            ),
        ]

    def __str__(self) -> str:
        return f"{self.hierarchy_id} — {self.name_en}"

    # ------------------------------------------------------------------
    # Helpers
    # ------------------------------------------------------------------

    @property
    def level_label(self) -> str:
        return PCFLevel(self.level).label

    def get_ancestors(self) -> list[PCFElement]:
        """Return ordered list of ancestor elements (root first)."""
        ancestors: list[PCFElement] = []
        node = self.parent
        while node is not None:
            ancestors.insert(0, node)
            node = node.parent
        return ancestors

    def get_descendants(self) -> models.QuerySet[PCFElement]:
        """Return all descendants (children, grandchildren, …) as a queryset."""
        ids: list[int] = []
        queue = list(self.children.values_list("pk", flat=True))
        while queue:
            ids.extend(queue)
            queue = list(
                PCFElement.objects.filter(parent_id__in=queue).values_list("pk", flat=True)
            )
        return PCFElement.objects.filter(pk__in=ids)


# ---------------------------------------------------------------------------
# PCFMetric
# ---------------------------------------------------------------------------

class PCFMetric(TimeStampedModel):
    """APQC standard benchmark metric linked to a PCFElement.

    Metrics at level 1–4 are shipped with the PCF framework data.
    They serve as reference for KPI mapping in Phase 5.
    """

    pcf_element = models.ForeignKey(
        PCFElement,
        on_delete=models.CASCADE,
        related_name="metrics",
        verbose_name=_("PCF element"),
    )
    metric_id = models.CharField(
        _("metric ID"),
        max_length=32,
        db_index=True,
        help_text=_("APQC metric identifier, e.g. 101337"),
    )
    category = models.CharField(
        _("category"),
        max_length=32,
        choices=MetricCategory.choices,
        default=MetricCategory.OTHER,
        db_index=True,
    )
    name = models.CharField(_("name"), max_length=512)
    formula = models.TextField(_("formula"), blank=True)
    unit = models.CharField(_("unit"), max_length=128, blank=True)
    description = models.TextField(_("description"), blank=True)

    class Meta:
        verbose_name = _("PCF metric")
        verbose_name_plural = _("PCF metrics")
        ordering = ("pcf_element", "metric_id")
        constraints = [
            models.UniqueConstraint(
                fields=("pcf_element", "metric_id"),
                name="bpm_pcfmetric_unique_metric_id_per_element",
            ),
        ]

    def __str__(self) -> str:
        return f"[{self.metric_id}] {self.name}"
