"""Tests for wiring the repository-document link into the publications editor.

Covers the HTMX search results partial (interactive Link action + empty state),
the ``link_publication_to_repository`` service, and the end-to-end formset save
path that attaches a repository document to a publication and flips
``cited_in_repository`` — plus the unlink path that clears it.
"""
from __future__ import annotations

import pytest
from django.urls import reverse

from apps.alumni.profiles.models import AlumniProfile, Publication
from apps.alumni.profiles.services import link_publication_to_repository


@pytest.fixture
def repo_collection(db):
    from apps.repository.documents.models import Collection

    col, _ = Collection.objects.update_or_create(
        slug="alumni-theses",
        defaults={
            "name": "Alumni theses",
            "visibility": Collection.Visibility.PUBLIC_OPEN,
        },
    )
    return col


@pytest.fixture
def repo_document(db, repo_collection):
    from apps.repository.documents.models import Document

    return Document.objects.create(
        title="Soil carbon sequestration in East Africa",
        doi="10.1234/soilcarbon",
        collection=repo_collection,
        document_type=Document.DocumentType.OTHER,
    )


def _base_edit_post(document_pk: str = "") -> dict:
    """Minimal profile-edit POST with a single new publication row.

    ``document_pk`` empty means 'no repository link'; a pk attaches it.
    """
    return {
        # main ProfileEditForm (mentor_capacity is the one required field)
        "mentor_capacity": "3",
        "headline": "",
        "expertise_tags": "",
        "mentor_topics": "",
        # degrees / employments / certificates: empty formsets
        "degrees-TOTAL_FORMS": "0",
        "degrees-INITIAL_FORMS": "0",
        "degrees-MIN_NUM_FORMS": "0",
        "degrees-MAX_NUM_FORMS": "1000",
        "employments-TOTAL_FORMS": "0",
        "employments-INITIAL_FORMS": "0",
        "employments-MIN_NUM_FORMS": "0",
        "employments-MAX_NUM_FORMS": "1000",
        "certificates-TOTAL_FORMS": "0",
        "certificates-INITIAL_FORMS": "0",
        "certificates-MIN_NUM_FORMS": "0",
        "certificates-MAX_NUM_FORMS": "1000",
        # publications: one new row
        "publications-TOTAL_FORMS": "1",
        "publications-INITIAL_FORMS": "0",
        "publications-MIN_NUM_FORMS": "0",
        "publications-MAX_NUM_FORMS": "1000",
        "publications-0-title": "Regenerative agronomy field trials",
        "publications-0-authors_text": "A. Alumnus",
        "publications-0-publication_type": "journal",
        "publications-0-doi": "",
        "publications-0-url": "",
        "publications-0-year": "2025",
        "publications-0-document": document_pk,
        "publications-0-id": "",
    }


# ── HTMX search results partial ────────────────────────────────────────────


@pytest.mark.django_db
def test_document_search_returns_link_action(client, alumni_user, repo_document):
    client.force_login(alumni_user)
    resp = client.get(
        reverse("alumni_profiles:document_search"),
        {"q": "soil carbon", "prefix": "publications-0"},
    )
    assert resp.status_code == 200
    body = resp.content.decode()
    assert repo_document.title in body
    # The Link action targets this row's hidden document input.
    assert "AlumniLinkDoc" in body
    assert "publications-0" in body
    assert str(repo_document.pk) in body


@pytest.mark.django_db
def test_document_search_empty_state(client, alumni_user, repo_document):
    client.force_login(alumni_user)
    resp = client.get(
        reverse("alumni_profiles:document_search"),
        {"q": "no-such-document-xyz", "prefix": "publications-0"},
    )
    assert resp.status_code == 200
    assert "No matching documents" in resp.content.decode()


@pytest.mark.django_db
def test_document_search_matches_by_doi(client, alumni_user, repo_document):
    client.force_login(alumni_user)
    resp = client.get(
        reverse("alumni_profiles:document_search"),
        {"q": "10.1234/soilcarbon", "prefix": "publications-0"},
    )
    assert resp.status_code == 200
    assert repo_document.title in resp.content.decode()


# ── Service ────────────────────────────────────────────────────────────────


@pytest.mark.django_db
def test_link_service_sets_document_and_flag(alumni_user, repo_document):
    profile = AlumniProfile.objects.create(user=alumni_user)
    pub = Publication.objects.create(profile=profile, title="Untethered work")
    assert pub.cited_in_repository is False

    link_publication_to_repository(pub, repo_document)
    pub.refresh_from_db()
    assert pub.document_id == repo_document.pk
    assert pub.cited_in_repository is True


# ── End-to-end formset save ────────────────────────────────────────────────


@pytest.mark.django_db
def test_profile_edit_save_attaches_document(client, alumni_user, repo_document):
    client.force_login(alumni_user)
    resp = client.post(
        reverse("alumni_profiles:profile_edit_self"),
        _base_edit_post(document_pk=str(repo_document.pk)),
    )
    assert resp.status_code in {301, 302}
    pub = Publication.objects.get(title="Regenerative agronomy field trials")
    assert pub.document_id == repo_document.pk
    # The form save keeps cited_in_repository in lock-step with the link.
    assert pub.cited_in_repository is True


@pytest.mark.django_db
def test_profile_detail_shows_repository_link(client, alumni_user, repo_document):
    profile = AlumniProfile.objects.create(user=alumni_user, visibility_consent=True)
    pub = Publication.objects.create(profile=profile, title="Linked paper")
    link_publication_to_repository(pub, repo_document)

    client.force_login(alumni_user)
    resp = client.get(
        reverse("alumni_profiles:profile_detail", kwargs={"pk": profile.pk})
    )
    assert resp.status_code == 200
    body = resp.content.decode()
    assert "In IILMP repository" in body
    # Badge links to the repository document detail.
    assert str(repo_document.document_uid) in body


@pytest.mark.django_db
def test_profile_edit_save_without_document_leaves_flag_false(client, alumni_user):
    client.force_login(alumni_user)
    resp = client.post(
        reverse("alumni_profiles:profile_edit_self"),
        _base_edit_post(document_pk=""),
    )
    assert resp.status_code in {301, 302}
    pub = Publication.objects.get(title="Regenerative agronomy field trials")
    assert pub.document_id is None
    assert pub.cited_in_repository is False


@pytest.mark.django_db
def test_unlinking_document_clears_flag(client, alumni_user, repo_document):
    """Re-saving a linked publication with a blank document unlinks it."""
    profile = AlumniProfile.objects.create(user=alumni_user)
    pub = Publication.objects.create(profile=profile, title="Toggle paper")
    link_publication_to_repository(pub, repo_document)
    assert pub.cited_in_repository is True

    client.force_login(alumni_user)
    data = _base_edit_post(document_pk="")
    data.update(
        {
            "publications-TOTAL_FORMS": "1",
            "publications-INITIAL_FORMS": "1",
            "publications-0-id": str(pub.pk),
            "publications-0-title": "Toggle paper",
            "publications-0-authors_text": "",
            "publications-0-publication_type": "journal",
            "publications-0-year": "",
            "publications-0-document": "",
        }
    )
    resp = client.post(reverse("alumni_profiles:profile_edit_self"), data)
    assert resp.status_code in {301, 302}
    pub.refresh_from_db()
    assert pub.document_id is None
    assert pub.cited_in_repository is False
