"""DMS documents — query layer.

All DB reads for DocumentType, Document, and DocumentVersion go through here.
"""

from __future__ import annotations

import uuid

from django.db.models import QuerySet

from simorgh.apps.dms.common.exceptions import AssetNotFound
from simorgh.apps.dms.documents.models import Document, DocumentType, DocumentVersion


# ---------------------------------------------------------------------------
# DocumentType queries
# ---------------------------------------------------------------------------

def get_document_type(tenant_id: int, public_id: str) -> DocumentType:
    try:
        uid = uuid.UUID(str(public_id))
    except (ValueError, AttributeError) as exc:
        raise AssetNotFound(f"Invalid document type id: {public_id!r}") from exc
    try:
        return DocumentType.objects.get(tenant_id=tenant_id, public_id=uid, is_deleted=False)
    except DocumentType.DoesNotExist as exc:
        raise AssetNotFound(f"DocumentType {public_id!r} not found.") from exc


def list_document_types(
    tenant_id: int,
    *,
    is_active: bool | None = None,
    search: str | None = None,
) -> QuerySet:
    qs = DocumentType.objects.filter(tenant_id=tenant_id, is_deleted=False).order_by("name")
    if is_active is not None:
        qs = qs.filter(is_active=is_active)
    if search:
        qs = qs.filter(name__icontains=search)
    return qs


# ---------------------------------------------------------------------------
# Document queries
# ---------------------------------------------------------------------------

def get_document(tenant_id: int, public_id: str) -> Document:
    try:
        uid = uuid.UUID(str(public_id))
    except (ValueError, AttributeError) as exc:
        raise AssetNotFound(f"Invalid document id: {public_id!r}") from exc
    try:
        return Document.objects.select_related(
            "current_version", "document_type", "repository", "folder"
        ).get(tenant_id=tenant_id, public_id=uid, is_deleted=False)
    except Document.DoesNotExist as exc:
        raise AssetNotFound(f"Document {public_id!r} not found.") from exc


def list_documents(
    tenant_id: int,
    *,
    repository_id: int | None = None,
    folder_id: int | None = None,
    document_type_id: int | None = None,
    status: str | None = None,
    search: str | None = None,
) -> QuerySet:
    qs = (
        Document.objects.filter(tenant_id=tenant_id, is_deleted=False)
        .select_related("current_version", "document_type")
        .order_by("-created_at")
    )
    if repository_id is not None:
        qs = qs.filter(repository_id=repository_id)
    if folder_id is not None:
        qs = qs.filter(folder_id=folder_id)
    if document_type_id is not None:
        qs = qs.filter(document_type_id=document_type_id)
    if status:
        qs = qs.filter(status=status)
    if search:
        qs = qs.filter(title__icontains=search)
    return qs


# ---------------------------------------------------------------------------
# DocumentVersion queries
# ---------------------------------------------------------------------------

def get_version(document: Document, public_id: str) -> DocumentVersion:
    try:
        uid = uuid.UUID(str(public_id))
    except (ValueError, AttributeError) as exc:
        raise AssetNotFound(f"Invalid version id: {public_id!r}") from exc
    try:
        return DocumentVersion.objects.select_related("file_asset").get(
            document=document, public_id=uid, is_deleted=False
        )
    except DocumentVersion.DoesNotExist as exc:
        raise AssetNotFound(f"DocumentVersion {public_id!r} not found.") from exc


def list_versions(document: Document) -> QuerySet:
    return (
        DocumentVersion.objects.filter(document=document, is_deleted=False)
        .select_related("file_asset")
        .order_by("-version_major", "-version_minor")
    )
