"""BPM Benchmarking models — Phase 13.

Provides APQC Open Standards Benchmarking data and organisational comparison.

Model inventory
---------------
BenchmarkIndustry       — TextChoices for industry segments.
APQCBenchmark           — A standard APQC benchmark record for a PCFMetric.
OrgBenchmarkComparison  — Comparison of an org KPI value against a benchmark.

Design decisions
----------------
* ``percentile_position`` on OrgBenchmarkComparison is stored as a Decimal
  (0–100) computed by ``compute_percentile_position()``.  It is stored
  (not a property) so it can be queried/sorted.
* ``gap_to_median`` is the delta (org_value − P50).  Negative = below median.
* ``APQCBenchmark.industry`` uses free-text TextChoices for extensibility.
"""

from __future__ import annotations

import decimal

from django.conf import settings
from django.db import models
from django.utils import timezone
from django.utils.translation import gettext_lazy as _

from simorgh.core.models import TimeStampedModel, UUIDModel
from simorgh.apps.bpm.models.pcf import PCFMetric
from simorgh.apps.bpm.models.process import ProcessDefinition
from simorgh.apps.bpm.models.kpi import ProcessKPI


# ---------------------------------------------------------------------------
# Choices
# ---------------------------------------------------------------------------

class BenchmarkIndustry(models.TextChoices):
    CROSS_INDUSTRY  = "cross_industry",  _("Cross Industry / کلیه صنایع")
    MANUFACTURING   = "manufacturing",   _("Manufacturing / تولید")
    AUTOMOTIVE      = "automotive",      _("Automotive / خودروسازی")
    FINANCIAL       = "financial",       _("Financial Services / خدمات مالی")
    HEALTHCARE      = "healthcare",      _("Healthcare / بهداشت و درمان")
    TECHNOLOGY      = "technology",      _("Technology / فناوری")
    RETAIL          = "retail",          _("Retail / خرده‌فروشی")
    ENERGY          = "energy",          _("Energy / انرژی")
    GOVERNMENT      = "government",      _("Government / دولتی")
    OTHER           = "other",           _("Other / سایر")


# ---------------------------------------------------------------------------
# APQCBenchmark
# ---------------------------------------------------------------------------

class APQCBenchmark(TimeStampedModel):
    """A single APQC Open Standards Benchmarking record.

    Stores the four percentile thresholds (P25 / P50 / P75 / P90) for a
    specific PCFMetric in a given industry and year.
    """

    pcf_metric = models.ForeignKey(
        PCFMetric,
        on_delete=models.CASCADE,
        related_name="benchmarks",
        verbose_name=_("PCF metric"),
    )
    industry = models.CharField(
        _("industry"),
        max_length=32,
        choices=BenchmarkIndustry.choices,
        default=BenchmarkIndustry.CROSS_INDUSTRY,
        db_index=True,
    )
    year = models.PositiveSmallIntegerField(_("benchmark year"), db_index=True)
    source = models.CharField(
        _("source"),
        max_length=256,
        default="APQC Open Standards Benchmarking",
        blank=True,
    )
    unit = models.CharField(_("unit"), max_length=64, blank=True)
    percentile_25 = models.DecimalField(
        _("25th percentile"), max_digits=18, decimal_places=4
    )
    percentile_50 = models.DecimalField(
        _("50th percentile (median)"), max_digits=18, decimal_places=4
    )
    percentile_75 = models.DecimalField(
        _("75th percentile"), max_digits=18, decimal_places=4
    )
    percentile_90 = models.DecimalField(
        _("90th percentile"), max_digits=18, decimal_places=4
    )

    class Meta:
        verbose_name = _("APQC benchmark")
        verbose_name_plural = _("APQC benchmarks")
        ordering = ("pcf_metric", "-year", "industry")
        constraints = [
            models.UniqueConstraint(
                fields=("pcf_metric", "industry", "year"),
                name="bpm_benchmark_unique_metric_industry_year",
            )
        ]

    def __str__(self) -> str:
        return f"{self.pcf_metric} | {self.industry} | {self.year}"

    # ------------------------------------------------------------------
    # Helpers
    # ------------------------------------------------------------------

    def compute_percentile_position(self, org_value: decimal.Decimal) -> decimal.Decimal:
        """Estimate percentile position (0–100) for org_value.

        Uses linear interpolation between the four benchmark percentile bands.
        """
        v = decimal.Decimal(str(org_value))
        p25, p50, p75, p90 = (
            self.percentile_25, self.percentile_50,
            self.percentile_75, self.percentile_90,
        )

        if v <= p25:
            if p25 > 0:
                return (v / p25 * decimal.Decimal("25")).quantize(decimal.Decimal("0.01"))
            return decimal.Decimal("0")
        elif v <= p50:
            rng = p50 - p25
            if rng > 0:
                return (decimal.Decimal("25") + (v - p25) / rng * decimal.Decimal("25")).quantize(decimal.Decimal("0.01"))
        elif v <= p75:
            rng = p75 - p50
            if rng > 0:
                return (decimal.Decimal("50") + (v - p50) / rng * decimal.Decimal("25")).quantize(decimal.Decimal("0.01"))
        elif v <= p90:
            rng = p90 - p75
            if rng > 0:
                return (decimal.Decimal("75") + (v - p75) / rng * decimal.Decimal("15")).quantize(decimal.Decimal("0.01"))
        else:
            return decimal.Decimal("100")

        return decimal.Decimal("0")


# ---------------------------------------------------------------------------
# OrgBenchmarkComparison
# ---------------------------------------------------------------------------

class OrgBenchmarkComparison(TimeStampedModel, UUIDModel):
    """Comparison of an organisation KPI measurement against an APQC benchmark.

    ``percentile_position`` and ``gap_to_median`` are computed and stored on
    save for fast querying and dashboard rendering.
    """

    process = models.ForeignKey(
        ProcessDefinition,
        on_delete=models.CASCADE,
        related_name="benchmark_comparisons",
        verbose_name=_("process"),
    )
    kpi = models.ForeignKey(
        ProcessKPI,
        on_delete=models.CASCADE,
        related_name="benchmark_comparisons",
        verbose_name=_("KPI"),
    )
    benchmark = models.ForeignKey(
        APQCBenchmark,
        on_delete=models.CASCADE,
        related_name="comparisons",
        verbose_name=_("APQC benchmark"),
    )
    org_value = models.DecimalField(
        _("org value"), max_digits=18, decimal_places=4,
    )
    percentile_position = models.DecimalField(
        _("percentile position"), max_digits=6, decimal_places=2,
        null=True, blank=True,
        help_text=_("Estimated percentile (0–100) of org_value in benchmark distribution."),
    )
    gap_to_median = models.DecimalField(
        _("gap to median"), max_digits=18, decimal_places=4,
        null=True, blank=True,
        help_text=_("org_value − P50. Negative = below median."),
    )
    assessment_date = models.DateField(_("assessment date"), default=timezone.now)
    assessed_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True, blank=True,
        related_name="bpm_benchmark_assessments",
        verbose_name=_("assessed by"),
    )
    notes = models.TextField(_("notes"), blank=True)

    class Meta:
        verbose_name = _("benchmark comparison")
        verbose_name_plural = _("benchmark comparisons")
        ordering = ("-assessment_date",)

    def __str__(self) -> str:
        return f"{self.kpi} vs {self.benchmark} @ {self.assessment_date}"

    def save(self, *args, **kwargs) -> None:
        self.percentile_position = self.benchmark.compute_percentile_position(self.org_value)
        self.gap_to_median = self.org_value - self.benchmark.percentile_50
        super().save(*args, **kwargs)
