"""Phase 2.1 — registry-first author entry (FRREP-MCL001/002/003).

The submit wizard replaces the free-text author block with a typeahead over the
Author Registry plus an inline add-new form. The structured selection posts as
``authors_json``; the view resolves it through ``resolve_authors_payload``,
which attaches existing authors by id (no re-dedup) and runs new authors through
``register_author`` (ORCID/email/name dedupe + affiliation capture).
"""
from __future__ import annotations

import json

import pytest
from django.core.files.uploadedfile import SimpleUploadedFile
from django.test import Client
from django.urls import reverse

from apps.repository.documents import services
from apps.repository.documents.forms import DocumentSubmitForm
from apps.repository.documents.models import Author, Document

PDF_BYTES = (
    b"%PDF-1.4\n%\xe2\xe3\xcf\xd3\n1 0 obj<</Type/Catalog>>endobj\ntrailer<<>>\n%%EOF\n"
)


def _base_data(collection_pk):
    return {
        "title": "Maize yields under drought",
        "abstract": "A study of drought-tolerant maize.",
        "document_type": Document.DocumentType.THESIS,
        "license_type": Document.License.CC_BY,
        "language": "en",
        "year": 2026,
        "collection": collection_pk,
    }


# ── Author search endpoint ─────────────────────────────────────────────────


@pytest.mark.django_db
def test_author_search_requires_login(client):
    resp = client.get(reverse("repo_documents:author_search"), {"q": "kato"})
    assert resp.status_code in (302, 403)


@pytest.mark.django_db
def test_author_search_matches_name_orcid_and_returns_metadata(submitter_user):
    services.register_author(
        first_name="Amina", last_name="Kato", orcid="0000-0002-1825-0097",
        affiliation_text="Makerere University",
    )
    services.register_author(first_name="Brian", last_name="Otieno")

    client = Client()
    client.force_login(submitter_user)
    resp = client.get(reverse("repo_documents:author_search"), {"q": "kato"})
    assert resp.status_code == 200
    results = resp.json()["results"]
    assert len(results) == 1
    row = results[0]
    assert row["orcid"] == "0000-0002-1825-0097"
    assert row["affiliation"] == "Makerere University"

    # ORCID is searchable too.
    resp = client.get(reverse("repo_documents:author_search"), {"q": "1825-0097"})
    assert len(resp.json()["results"]) == 1


# ── Payload resolution ─────────────────────────────────────────────────────


@pytest.mark.django_db
def test_resolve_payload_attaches_existing_by_id_without_creating(submitter_user):
    existing = services.register_author(first_name="Amina", last_name="Kato")
    before = Author.objects.count()
    resolved = services.resolve_authors_payload(json.dumps([{"id": existing.pk}]))
    assert [a.pk for a in resolved] == [existing.pk]
    assert Author.objects.count() == before  # no new row


@pytest.mark.django_db
def test_resolve_payload_creates_new_author_with_affiliation():
    resolved = services.resolve_authors_payload(
        json.dumps([
            {"name": "Otieno, Brian", "email": "b@x.org", "affiliation": "ICRAF"}
        ])
    )
    assert len(resolved) == 1
    a = resolved[0]
    assert a.first_name == "Brian" and a.last_name == "Otieno"
    assert a.affiliation_text == "ICRAF"


@pytest.mark.django_db
def test_resolve_payload_dedupes_repeated_entries():
    existing = services.register_author(first_name="Amina", last_name="Kato")
    resolved = services.resolve_authors_payload(
        json.dumps([{"id": existing.pk}, {"id": existing.pk}])
    )
    assert len(resolved) == 1


@pytest.mark.django_db
def test_resolve_payload_ignores_junk():
    assert services.resolve_authors_payload("not json") == []
    assert services.resolve_authors_payload(json.dumps([{"name": "  "}])) == []


# ── Form + view wiring ─────────────────────────────────────────────────────


@pytest.mark.django_db
def test_form_requires_at_least_one_author(public_collection):
    data = _base_data(public_collection.pk)
    data["staged_token"] = "tok"
    data["authors_json"] = "[]"
    data["authors_text"] = ""
    form = DocumentSubmitForm(data=data)
    assert not form.is_valid()
    assert "authors_json" in form.errors


@pytest.mark.django_db
def test_submit_with_registry_payload_attaches_without_duplicate(
    public_collection, submitter_user
):
    existing = services.register_author(first_name="Amina", last_name="Kato")
    authors_before = Author.objects.count()

    client = Client()
    client.force_login(submitter_user)
    data = _base_data(public_collection.pk)
    data["authors_json"] = json.dumps([{"id": existing.pk}])
    data["file"] = SimpleUploadedFile("t.pdf", PDF_BYTES, content_type="application/pdf")

    resp = client.post(reverse("repo_documents:submit"), data=data)
    assert resp.status_code == 302
    doc = Document.objects.get()
    assert list(doc.authors.all()) == [existing]
    assert Author.objects.count() == authors_before  # no duplicate created


@pytest.mark.django_db
def test_submit_with_new_author_payload_creates_one_author(
    public_collection, submitter_user
):
    client = Client()
    client.force_login(submitter_user)
    data = _base_data(public_collection.pk)
    data["authors_json"] = json.dumps(
        [{"name": "Otieno, Brian", "affiliation": "ICRAF"}]
    )
    data["file"] = SimpleUploadedFile("t.pdf", PDF_BYTES, content_type="application/pdf")

    resp = client.post(reverse("repo_documents:submit"), data=data)
    assert resp.status_code == 302
    doc = Document.objects.get()
    assert doc.authors.count() == 1
    author = doc.authors.get()
    assert author.affiliation_text == "ICRAF"
