"""DMS collaboration — query layer.

All DB reads for Comment, Annotation, and Mention go through here.
Views and services must not query these models directly.
"""

from __future__ import annotations

import uuid

from django.db.models import QuerySet

from simorgh.apps.dms.common.exceptions import AssetNotFound
from simorgh.apps.dms.collaboration.models import Annotation, Comment, Mention


# ---------------------------------------------------------------------------
# Comment queries
# ---------------------------------------------------------------------------

def get_comment(tenant_id: int, public_id: str) -> Comment:
    """Return a non-deleted Comment by public_id within a tenant.

    Raises ``AssetNotFound`` if the comment does not exist or is deleted.
    """
    try:
        uid = uuid.UUID(str(public_id))
    except (ValueError, AttributeError) as exc:
        raise AssetNotFound(f"Invalid comment id: {public_id!r}") from exc

    try:
        return (
            Comment.objects.select_related(
                "author", "resolved_by", "parent", "version"
            )
            .get(tenant_id=tenant_id, public_id=uid, is_deleted=False)
        )
    except Comment.DoesNotExist as exc:
        raise AssetNotFound(f"Comment {public_id!r} not found.") from exc


def list_comments_for_document(
    document,
    *,
    version=None,
    include_resolved: bool = True,
    top_level_only: bool = False,
) -> QuerySet:
    """Return comments for a document, newest first.

    Parameters
    ----------
    version:
        When provided, restricts to comments on that specific version.
        When None, returns all document-level + version-specific comments.
    include_resolved:
        When False, only unresolved top-level comments are returned.
    top_level_only:
        When True, only root comments (parent=None) are returned.
    """
    qs = (
        Comment.objects.filter(document=document, is_deleted=False)
        .select_related("author", "resolved_by", "version")
        .prefetch_related("replies", "mentions")
        .order_by("created_at")
    )
    if version is not None:
        qs = qs.filter(version=version)
    if not include_resolved:
        qs = qs.filter(is_resolved=False)
    if top_level_only:
        qs = qs.filter(parent__isnull=True)
    return qs


def list_replies(comment: Comment) -> QuerySet:
    """Return direct replies to a top-level comment, oldest first."""
    return (
        Comment.objects.filter(parent=comment, is_deleted=False)
        .select_related("author")
        .order_by("created_at")
    )


# ---------------------------------------------------------------------------
# Annotation queries
# ---------------------------------------------------------------------------

def get_annotation(tenant_id: int, public_id: str) -> Annotation:
    """Return a non-deleted Annotation by public_id within a tenant.

    Raises ``AssetNotFound`` if not found.
    """
    try:
        uid = uuid.UUID(str(public_id))
    except (ValueError, AttributeError) as exc:
        raise AssetNotFound(f"Invalid annotation id: {public_id!r}") from exc

    try:
        return (
            Annotation.objects.select_related("author", "version", "document", "linked_comment")
            .get(tenant_id=tenant_id, public_id=uid, is_deleted=False)
        )
    except Annotation.DoesNotExist as exc:
        raise AssetNotFound(f"Annotation {public_id!r} not found.") from exc


def list_annotations_for_version(version, *, page_number: int | None = None) -> QuerySet:
    """Return non-deleted annotations for a document version.

    Optionally filter by page number.
    """
    qs = (
        Annotation.objects.filter(version=version, is_deleted=False)
        .select_related("author", "linked_comment")
        .order_by("page_number", "created_at")
    )
    if page_number is not None:
        qs = qs.filter(page_number=page_number)
    return qs


def list_annotations_for_document(document) -> QuerySet:
    """Return all non-deleted annotations across all versions of a document."""
    return (
        Annotation.objects.filter(document=document, is_deleted=False)
        .select_related("author", "version", "linked_comment")
        .order_by("version__version_major", "version__version_minor", "page_number", "created_at")
    )


# ---------------------------------------------------------------------------
# Mention queries
# ---------------------------------------------------------------------------

def list_mentions_for_comment(comment: Comment) -> QuerySet:
    """Return all mentions in a comment."""
    return Mention.objects.filter(comment=comment).select_related("mentioned_user")


def list_pending_mention_notifications(tenant_id: int) -> QuerySet:
    """Return unnotified mentions for the notification pipeline."""
    return (
        Mention.objects.filter(
            comment__tenant_id=tenant_id,
            is_notified=False,
            comment__is_deleted=False,
        )
        .select_related("mentioned_user", "comment__document")
        .order_by("created_at")
    )
