"""FRREP-SR005 — advanced search: every field filters, no 500 on junk, empty-state."""

from __future__ import annotations

import itertools

import pytest
from django.urls import reverse

from apps.repository.documents.models import Author, Document
from apps.repository.search.services import advanced_search

_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"ADV-{next(_seq):05d}",
        **kwargs,
    )


@pytest.fixture
def seeded(public_collection):
    a = Author.objects.create(first_name="Grace", last_name="Kato", orcid="0000-0002-1825-0097")
    doc = _published(
        public_collection,
        "Climate adaptation in maize",
        abstract="smallholder resilience under drought",
        doi="10.1234/abcd.2021",
        license_type=Document.License.CC_BY,
        year=2021,
    )
    doc.authors.add(a)
    # A decoy that must never match the specific filters below.
    _published(public_collection, "Unrelated wheat economics", year=2010,
               license_type=Document.License.CC0, doi="10.9999/zzzz")
    return doc


@pytest.mark.django_db
@pytest.mark.parametrize(
    "field,value",
    [
        ("title", "climate adaptation"),
        ("abstract", "smallholder"),
        ("author", "Kato"),
        ("author_orcid", "0000-0002-1825-0097"),
        ("doi", "10.1234/abcd.2021"),
        ("license", "cc_by"),
    ],
)
def test_each_field_filters(seeded, field, value):
    results = list(advanced_search(**{field: value}))
    assert seeded in results
    # The decoy never carries these exact values.
    assert len(results) == 1


@pytest.mark.django_db
def test_year_range_filters(seeded):
    assert seeded in advanced_search(year_from=2020, year_to=2022)
    assert seeded not in advanced_search(year_from=2022)


@pytest.mark.django_db
def test_non_numeric_year_does_not_500(client, seeded):
    resp = client.get(reverse("repo_search:advanced") + "?title=climate&year_from=abc")
    assert resp.status_code == 200
    # The junk year is ignored, the title filter still runs.
    assert seeded in resp.context["results"]


@pytest.mark.django_db
def test_doi_and_license_round_trip_through_view(client, seeded):
    resp = client.get(reverse("repo_search:advanced") + "?doi=10.1234/abcd.2021")
    assert resp.status_code == 200
    assert list(resp.context["results"]) == [seeded]


@pytest.mark.django_db
def test_empty_result_shows_broaden_state(client, seeded):
    resp = client.get(reverse("repo_search:advanced") + "?title=zzzznomatchzzzz")
    assert resp.status_code == 200
    assert resp.context["results"] is not None
    assert resp.context["results"].paginator.count == 0
    assert "No results" in resp.content.decode()


@pytest.mark.django_db
def test_blank_only_submit_runs_no_search(client, public_collection):
    """Submitting the form with only blank fields must not render a results block."""
    resp = client.get(reverse("repo_search:advanced") + "?title=&abstract=&author=")
    assert resp.status_code == 200
    assert resp.context.get("results") is None


# ── FRREP-SR005 — document type / collection / subject-keyword fields ──────


@pytest.fixture
def classified(public_collection, restricted_collection):
    from apps.repository.documents.models import Keyword

    kw = Keyword.objects.create(
        label="Agroforestry", slug="agroforestry", status=Keyword.Status.APPROVED
    )
    doc = _published(
        public_collection,
        "Agroforestry systems in the Sahel",
        document_type=Document.DocumentType.DATASET,
    )
    doc.keywords.add(kw)
    # Decoy: different type, different collection, no keyword.
    _published(
        restricted_collection,
        "Unrelated policy brief",
        document_type=Document.DocumentType.TECHNICAL_REPORT,
    )
    return doc


@pytest.mark.django_db
def test_advanced_search_filters_by_document_type(classified):
    results = list(advanced_search(document_type=Document.DocumentType.DATASET))
    assert classified in results
    assert len(results) == 1


@pytest.mark.django_db
def test_advanced_search_filters_by_collection(classified, public_collection):
    results = list(advanced_search(collection=public_collection.slug))
    assert classified in results
    assert len(results) == 1


@pytest.mark.django_db
def test_advanced_search_filters_by_subject_keyword(classified):
    results = list(advanced_search(subject="agroforestry"))
    assert classified in results
    assert len(results) == 1


@pytest.mark.django_db
def test_advanced_search_view_exposes_classification_fields(client, classified, public_collection):
    resp = client.get(
        reverse("repo_search:advanced") + f"?document_type={Document.DocumentType.DATASET}"
    )
    assert resp.status_code == 200
    assert list(resp.context["results"]) == [classified]
    body = resp.content.decode()
    assert 'name="document_type"' in body
    assert 'name="collection"' in body
    assert 'name="subject"' in body
