"""KB business-logic services.

All write operations flow through this module.
Services are free of HTTP concerns – they accept plain Python values and return
model instances or None.
"""

from __future__ import annotations

from django.db import transaction
from django.db.models import F
from django.utils import timezone

from simorgh.apps.kb.models import (
    ArticleStatus,
    ArticleVisibility,
    KBArticle,
    KBArticleFeedback,
    KBArticleVersion,
    KBCategory,
)


# ---------------------------------------------------------------------------
# Category services
# ---------------------------------------------------------------------------

def create_category(
    *,
    tenant_id: int,
    name: str,
    slug: str,
    parent_id: int | None = None,
    icon: str = "",
    order: int = 0,
) -> KBCategory:
    return KBCategory.objects.create(
        tenant_id=tenant_id,
        name=name,
        slug=slug,
        parent_id=parent_id,
        icon=icon,
        order=order,
    )


def update_category(
    category: KBCategory,
    *,
    name: str | None = None,
    slug: str | None = None,
    parent_id: int | None = None,
    icon: str | None = None,
    order: int | None = None,
) -> KBCategory:
    if name is not None:
        category.name = name
    if slug is not None:
        category.slug = slug
    if parent_id is not None:
        category.parent_id = parent_id
    if icon is not None:
        category.icon = icon
    if order is not None:
        category.order = order
    category.save()
    return category


def delete_category(category: KBCategory) -> None:
    category.delete()


# ---------------------------------------------------------------------------
# Article services
# ---------------------------------------------------------------------------

def create_article(
    *,
    tenant_id: int,
    title: str,
    slug: str,
    category_id: int,
    body_html: str = "",
    author_id: int,
    visibility: str = ArticleVisibility.INTERNAL,
) -> KBArticle:
    return KBArticle.objects.create(
        tenant_id=tenant_id,
        title=title,
        slug=slug,
        category_id=category_id,
        body_html=body_html,
        author_id=author_id,
        visibility=visibility,
        status=ArticleStatus.DRAFT,
    )


def update_article(
    article: KBArticle,
    *,
    title: str | None = None,
    slug: str | None = None,
    body_html: str | None = None,
    category_id: int | None = None,
    visibility: str | None = None,
) -> KBArticle:
    if title is not None:
        article.title = title
    if slug is not None:
        article.slug = slug
    if body_html is not None:
        article.body_html = body_html
    if category_id is not None:
        article.category_id = category_id
    if visibility is not None:
        article.visibility = visibility
    article.save()
    return article


@transaction.atomic
def publish_article(
    article: KBArticle,
    *,
    changed_by_id: int,
    change_summary: str = "",
) -> KBArticle:
    next_version = article.versions.count() + 1
    KBArticleVersion.objects.create(
        article=article,
        version=next_version,
        body_html=article.body_html,
        changed_by_id=changed_by_id,
        change_summary=change_summary,
    )
    article.status = ArticleStatus.PUBLISHED
    article.published_at = timezone.now()
    article.save(update_fields=["status", "published_at", "updated_at"])

    try:
        from simorgh.apps.events.bus import publish_event
        publish_event(
            "kb.article.published",
            {
                "article_id": article.pk,
                "public_id": str(article.public_id),
                "tenant_id": article.tenant_id,
                "changed_by_id": changed_by_id,
                "version": next_version,
            },
        )
    except Exception:  # noqa: BLE001
        pass

    return article


@transaction.atomic
def archive_article(
    article: KBArticle,
    *,
    changed_by_id: int,
) -> KBArticle:
    article.status = ArticleStatus.ARCHIVED
    article.save(update_fields=["status", "updated_at"])

    try:
        from simorgh.apps.events.bus import publish_event
        publish_event(
            "kb.article.archived",
            {
                "article_id": article.pk,
                "public_id": str(article.public_id),
                "tenant_id": article.tenant_id,
                "changed_by_id": changed_by_id,
            },
        )
    except Exception:  # noqa: BLE001
        pass

    return article


def delete_article(article: KBArticle) -> None:
    article.delete()


def record_feedback(
    article: KBArticle,
    *,
    user_id: int | None = None,
    is_helpful: bool,
    comment: str = "",
) -> KBArticleFeedback:
    feedback = KBArticleFeedback.objects.create(
        article=article,
        user_id=user_id,
        is_helpful=is_helpful,
        comment=comment,
    )
    if is_helpful:
        KBArticle.objects.filter(pk=article.pk).update(helpful_count=F("helpful_count") + 1)
        article.helpful_count = (article.helpful_count or 0) + 1
    else:
        KBArticle.objects.filter(pk=article.pk).update(not_helpful_count=F("not_helpful_count") + 1)
        article.not_helpful_count = (article.not_helpful_count or 0) + 1
    return feedback


def increment_view_count(article: KBArticle) -> None:
    KBArticle.objects.filter(pk=article.pk).update(view_count=F("view_count") + 1)
