"""FRREP-SR003 — search sort criteria (recent/oldest/title A-Z/Z-A/author/downloads)."""

from __future__ import annotations

import itertools

import pytest

from apps.repository.analytics.models import DownloadEvent
from apps.repository.documents.models import Author, Document
from apps.repository.search.services import search_documents

_seq = itertools.count(1)


def _published(collection, title, **kwargs):
    return Document.objects.create(
        title=title,
        collection=collection,
        status=Document.Status.PUBLISHED,
        visibility=Document.Visibility.PUBLIC_OPEN,
        public_document_id=f"SRT-{next(_seq):05d}",
        **kwargs,
    )


@pytest.mark.django_db
def test_sort_title_desc_orders_z_to_a(public_collection):
    d_a = _published(public_collection, "Apple systems")
    d_z = _published(public_collection, "Zebra systems")

    results = list(search_documents(sort="title_desc"))
    assert results.index(d_z) < results.index(d_a)


@pytest.mark.django_db
def test_sort_downloads_orders_by_real_download_count(public_collection):
    # Fewer downloads but created most recently — a "-created_at" fallback
    # sort (the old stub) would rank this first; the real download-count sort
    # must not.
    d_few = _published(public_collection, "Rarely downloaded")
    d_many = _published(public_collection, "Popular paper")

    DownloadEvent.objects.create(document=d_few)
    for _ in range(3):
        DownloadEvent.objects.create(document=d_many)

    results = list(search_documents(sort="downloads"))
    assert results.index(d_many) < results.index(d_few)


@pytest.mark.django_db
def test_sort_downloads_with_no_events_does_not_crash(public_collection):
    _published(public_collection, "No downloads yet")
    results = list(search_documents(sort="downloads"))
    assert len(results) == 1


@pytest.mark.django_db
def test_sort_author_orders_by_primary_author_last_name(public_collection):
    kato = Author.objects.create(first_name="Grace", last_name="Kato")
    mwangi = Author.objects.create(first_name="John", last_name="Mwangi")
    d_mwangi = _published(public_collection, "Wheat study")
    d_mwangi.authors.add(mwangi)
    d_kato = _published(public_collection, "Maize study")
    d_kato.authors.add(kato)

    results = list(search_documents(sort="author"))
    assert results.index(d_kato) < results.index(d_mwangi)


@pytest.mark.django_db
def test_sort_author_uses_primary_not_co_author(public_collection):
    from apps.repository.documents.models import DocumentAuthor

    primary = Author.objects.create(first_name="Ann", last_name="Aardvark")
    co_author = Author.objects.create(first_name="Zed", last_name="Zulu")
    doc = _published(public_collection, "Joint paper")
    DocumentAuthor.objects.create(document=doc, author=co_author, order=1)
    DocumentAuthor.objects.create(document=doc, author=primary, order=0)

    other = Author.objects.create(first_name="Mid", last_name="Mmiddle")
    other_doc = _published(public_collection, "Solo paper")
    other_doc.authors.add(other)

    results = list(search_documents(sort="author"))
    # "Aardvark" (the primary/order=0 author on `doc`) must sort before
    # "Mmiddle" — proving the subquery picked the primary author, not the
    # alphabetically-earliest DocumentAuthor row overall.
    assert results.index(doc) < results.index(other_doc)


@pytest.mark.django_db
def test_sort_author_handles_documents_without_authors(public_collection):
    _published(public_collection, "No authors on this one")
    results = list(search_documents(sort="author"))
    assert len(results) == 1
