"""Knowledge Base domain models.

Model inventory
---------------
KBCategory          — hierarchical taxonomy (tenant-scoped, up to 2 levels)
KBArticle           — core content entity with draft/published/archived lifecycle
KBArticleVersion    — immutable snapshot saved on each publish action
KBArticleFeedback   — "Was this helpful?" per-article, optionally per-user

Design decisions
----------------
* KBCategory and KBArticle use direct tenant FKs (not TenantScopedModel) because
  KB content is tenant-wide, not org-node scoped. Categories are a taxonomy, not
  a business entity that needs hierarchical scoping.
* SoftDeleteModel on KBArticle so articles are recoverable and audit-safe.
* Versions are immutable rows created only on publish; body_html is the source of truth.
* view_count / helpful_count are denormalised counters updated via F() to avoid
  SELECT+UPDATE roundtrips.
* Visibility levels: public (no auth needed), internal (authenticated users),
  private (author only).
"""

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 (
    SoftDeleteManager,
    SoftDeleteModel,
    TimeStampedModel,
    UUIDModel,
)


# ---------------------------------------------------------------------------
# Choices
# ---------------------------------------------------------------------------

class ArticleStatus(models.TextChoices):
    DRAFT = "draft", _("Draft")
    PUBLISHED = "published", _("Published")
    ARCHIVED = "archived", _("Archived")


class ArticleVisibility(models.TextChoices):
    PUBLIC = "public", _("Public")
    INTERNAL = "internal", _("Internal")
    PRIVATE = "private", _("Private")


# ---------------------------------------------------------------------------
# KBCategory
# ---------------------------------------------------------------------------

class KBCategory(UUIDModel, TimeStampedModel):
    """Hierarchical category taxonomy for KB articles."""

    tenant = models.ForeignKey(
        "tenants.Tenant",
        on_delete=models.CASCADE,
        related_name="kb_categories",
        verbose_name=_("tenant"),
    )
    name = models.CharField(_("name"), max_length=200)
    slug = models.SlugField(_("slug"), max_length=200)
    parent = models.ForeignKey(
        "self",
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name="children",
        verbose_name=_("parent"),
    )
    icon = models.CharField(_("icon"), max_length=50, blank=True, default="")
    order = models.PositiveIntegerField(_("order"), default=0)

    class Meta:
        verbose_name = _("KB category")
        verbose_name_plural = _("KB categories")
        ordering = ["order", "name"]
        constraints: ClassVar[list[models.BaseConstraint]] = [
            models.UniqueConstraint(
                fields=["tenant", "slug"],
                name="kb_category_unique_tenant_slug",
            ),
        ]

    def __str__(self) -> str:
        return self.name


# ---------------------------------------------------------------------------
# KBArticle
# ---------------------------------------------------------------------------

class KBArticle(UUIDModel, TimeStampedModel, SoftDeleteModel):
    """Core KB content entity with a draft → published → archived lifecycle."""

    tenant = models.ForeignKey(
        "tenants.Tenant",
        on_delete=models.CASCADE,
        related_name="kb_articles",
        verbose_name=_("tenant"),
    )
    title = models.CharField(_("title"), max_length=500)
    slug = models.SlugField(_("slug"), max_length=500)
    category = models.ForeignKey(
        KBCategory,
        on_delete=models.PROTECT,
        related_name="articles",
        verbose_name=_("category"),
    )
    body_html = models.TextField(_("body (HTML)"), blank=True, default="")
    status = models.CharField(
        _("status"),
        max_length=20,
        choices=ArticleStatus.choices,
        default=ArticleStatus.DRAFT,
        db_index=True,
    )
    visibility = models.CharField(
        _("visibility"),
        max_length=20,
        choices=ArticleVisibility.choices,
        default=ArticleVisibility.INTERNAL,
    )
    view_count = models.PositiveIntegerField(_("view count"), default=0)
    helpful_count = models.PositiveIntegerField(_("helpful count"), default=0)
    not_helpful_count = models.PositiveIntegerField(_("not helpful count"), default=0)
    author = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.PROTECT,
        related_name="kb_articles",
        verbose_name=_("author"),
    )
    published_at = models.DateTimeField(_("published at"), null=True, blank=True)

    objects = SoftDeleteManager()

    class Meta:
        verbose_name = _("KB article")
        verbose_name_plural = _("KB articles")
        constraints: ClassVar[list[models.BaseConstraint]] = [
            models.UniqueConstraint(
                fields=["tenant", "slug"],
                name="kb_article_unique_tenant_slug",
            ),
        ]
        indexes: ClassVar[list[models.Index]] = [
            models.Index(fields=["tenant", "status", "category_id"]),
        ]

    def __str__(self) -> str:
        return self.title


# ---------------------------------------------------------------------------
# KBArticleVersion
# ---------------------------------------------------------------------------

class KBArticleVersion(TimeStampedModel):
    """Immutable snapshot of article body saved on each publish action."""

    article = models.ForeignKey(
        KBArticle,
        on_delete=models.CASCADE,
        related_name="versions",
        verbose_name=_("article"),
    )
    version = models.PositiveIntegerField(_("version"))
    body_html = models.TextField(_("body (HTML)"))
    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=""
    )

    class Meta:
        verbose_name = _("KB article version")
        verbose_name_plural = _("KB article versions")
        unique_together = [("article", "version")]
        ordering = ["-version"]

    def __str__(self) -> str:
        return f"{self.article_id} v{self.version}"


# ---------------------------------------------------------------------------
# KBArticleFeedback
# ---------------------------------------------------------------------------

class KBArticleFeedback(TimeStampedModel):
    """'Was this helpful?' per-article, optionally attributed to a user."""

    article = models.ForeignKey(
        KBArticle,
        on_delete=models.CASCADE,
        related_name="feedbacks",
        verbose_name=_("article"),
    )
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="+",
        verbose_name=_("user"),
    )
    is_helpful = models.BooleanField(_("is helpful"))
    comment = models.TextField(_("comment"), blank=True, default="")

    class Meta:
        verbose_name = _("KB article feedback")
        verbose_name_plural = _("KB article feedbacks")
        ordering = ["-created_at"]

    def __str__(self) -> str:
        symbol = "👍" if self.is_helpful else "👎"
        return f"article={self.article_id} {symbol}"
