"""Catalog Engine domain models.

Model inventory
---------------
CatalogCategory     — hierarchical category tree for catalog items.
CatalogItem         — unified catalog entity (5 catalog types).
CatalogItemVersion  — append-only version record on publish.

Design decisions
----------------
* Every entity extends TenantScopedModel (tenant + org_node FKs).
* UUIDModel exposes public_id for external identifiers.
* AuditedModel adds created_by/updated_by auto-populated from RequestContext.
* SoftDeleteModel protects against accidental hard-delete.
* VersionedModel provides optimistic concurrency control.
* CatalogItem.catalog_type is a TextChoices discriminator — NOT separate tables.
* Custom attributes: use platform_core.CustomFieldDefinition + CustomFieldValue.
* Attachments, Comments, Tags: reuse platform_core (GenericFK).
* Documentation link: soft reference (UUIDField) to content.ContentItem.
* Related items: JSON array of public_id UUIDs (self-referential soft refs).
"""

from __future__ import annotations

from typing import ClassVar

from django.conf import settings
from django.db import models
from django.utils.translation import gettext_lazy as _

from simorgh.core.models import (
    AuditedModel,
    OrderedModel,
    ScopedSoftDeleteManager,
    SoftDeleteModel,
    TenantScopedModel,
    UUIDModel,
    VersionedModel,
)


class CatalogType(models.TextChoices):
    PRODUCT      = "product",      _("Product")
    SERVICE      = "service",      _("Service")
    IT_SERVICE   = "it_service",   _("IT Service")
    HR_SERVICE   = "hr_service",   _("HR Service")
    PROCUREMENT  = "procurement",  _("Procurement")


class CatalogItemStatus(models.TextChoices):
    DRAFT     = "draft",     _("Draft")
    REVIEW    = "review",    _("In Review")
    PUBLISHED = "published", _("Published")
    RETIRED   = "retired",   _("Retired")


# ---------------------------------------------------------------------------
# CatalogCategory
# ---------------------------------------------------------------------------

class CatalogCategory(UUIDModel, TenantScopedModel, OrderedModel):
    """Hierarchical category tree for catalog items."""

    parent = models.ForeignKey(
        "self",
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="children",
        verbose_name=_("parent category"),
    )
    catalog_type = models.CharField(
        _("catalog type"),
        max_length=30,
        choices=CatalogType.choices,
        db_index=True,
    )
    name = models.CharField(_("name"), max_length=200)
    slug = models.SlugField(_("slug"), max_length=200)
    description = models.TextField(_("description"), blank=True, default="")
    icon = models.CharField(_("icon"), max_length=50, blank=True, default="")
    is_active = models.BooleanField(_("active"), default=True, db_index=True)

    class Meta:
        verbose_name = _("catalog category")
        verbose_name_plural = _("catalog categories")
        unique_together = [("tenant", "slug")]
        indexes: ClassVar[list[models.Index]] = [
            models.Index(fields=("tenant", "catalog_type")),
            models.Index(fields=("tenant", "parent")),
            models.Index(fields=("tenant", "is_active")),
        ]

    def __str__(self) -> str:
        return f"{self.get_catalog_type_display()} / {self.name}"


# ---------------------------------------------------------------------------
# CatalogItem
# ---------------------------------------------------------------------------

class CatalogItem(UUIDModel, TenantScopedModel, AuditedModel, SoftDeleteModel, VersionedModel):
    """Unified catalog item — metadata and discoverability only. No commerce logic."""

    name = models.CharField(_("name"), max_length=500)
    slug = models.SlugField(_("slug"), max_length=500)
    catalog_type = models.CharField(
        _("catalog type"),
        max_length=30,
        choices=CatalogType.choices,
        db_index=True,
    )
    category = models.ForeignKey(
        CatalogCategory,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="items",
        verbose_name=_("category"),
    )
    description = models.TextField(_("description"), blank=True, default="")
    short_description = models.CharField(_("short description"), max_length=500, blank=True, default="")
    status = models.CharField(
        _("status"),
        max_length=20,
        choices=CatalogItemStatus.choices,
        default=CatalogItemStatus.DRAFT,
        db_index=True,
    )
    owner = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.PROTECT,
        related_name="owned_catalog_items",
        verbose_name=_("owner"),
        null=True,
        blank=True,
    )
    published_at = models.DateTimeField(_("published at"), null=True, blank=True, db_index=True)
    retired_at = models.DateTimeField(_("retired at"), null=True, blank=True)

    # Image
    image = models.ForeignKey(
        "storage.FileMetadata",
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="+",
        verbose_name=_("image"),
    )

    # Related items (self-referential soft references — JSON array of UUIDs)
    related_items = models.JSONField(_("related items"), default=list, blank=True)

    # Documentation link (soft ref to content engine)
    documentation_content_id = models.UUIDField(
        _("documentation content ID"),
        null=True,
        blank=True,
        help_text=_("Reference to a ContentItem for detailed documentation"),
    )

    # AI / Semantic metadata
    ai_description = models.TextField(_("AI description"), blank=True, default="")
    ai_semantic_type = models.CharField(_("AI semantic type"), max_length=100, blank=True, default="")

    # Workflow instance link
    workflow_instance = models.ForeignKey(
        "platform_workflow.WorkflowInstance",
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="+",
        verbose_name=_("workflow instance"),
    )

    objects = ScopedSoftDeleteManager()

    class Meta:
        verbose_name = _("catalog item")
        verbose_name_plural = _("catalog items")
        unique_together = [("tenant", "slug")]
        indexes: ClassVar[list[models.Index]] = [
            models.Index(fields=("tenant", "catalog_type")),
            models.Index(fields=("tenant", "status")),
            models.Index(fields=("tenant", "category")),
            models.Index(fields=("tenant", "owner")),
            models.Index(fields=("tenant", "catalog_type", "status")),
        ]
        ordering = ["-published_at", "-created_at"]

    def __str__(self) -> str:
        return f"{self.get_catalog_type_display()}: {self.name} [{self.status}]"


# ---------------------------------------------------------------------------
# CatalogItemVersion
# ---------------------------------------------------------------------------

class CatalogItemVersion(UUIDModel, TenantScopedModel):
    """Append-only version record for catalog items — captured on publish."""

    catalog_item = models.ForeignKey(
        CatalogItem,
        on_delete=models.CASCADE,
        related_name="versions",
        verbose_name=_("catalog item"),
    )
    version = models.PositiveIntegerField(_("version number"))
    name = models.CharField(_("name"), max_length=500)
    description = models.TextField(_("description"))
    status = models.CharField(_("status at snapshot"), max_length=20, choices=CatalogItemStatus.choices)
    changed_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="+",
        verbose_name=_("changed by"),
    )
    change_summary = models.CharField(_("change summary"), max_length=500, blank=True, default="")
    created_at = models.DateTimeField(_("created at"), auto_now_add=True)

    class Meta:
        verbose_name = _("catalog item version")
        verbose_name_plural = _("catalog item versions")
        unique_together = [("catalog_item", "version")]
        ordering = ["-version"]

    def __str__(self) -> str:
        return f"{self.catalog_item_id} v{self.version}"
