"""Tests for FRREP-VL002 — admin-configurable major/minor version numbering.

``_next_version_number`` bumps either the major integer (a substantive
revision, e.g. 1.0 -> 2.0) or the minor decimal (a small correction, e.g.
1.0 -> 1.1). Per FRREP-VL004, ``ingest_document`` now lays down the initial
"1.0" ``DocumentVersion`` at upload time, so the *first* subsequent
``add_version`` produces 2.0 (major) or 1.1 (minor) — there is already a 1.0
to build on.
"""

from __future__ import annotations

import pytest
from django.core.exceptions import ValidationError
from django.core.files.base import ContentFile
from django.core.files.uploadedfile import SimpleUploadedFile
from django.urls import reverse

from apps.repository.documents import services
from apps.repository.documents.models import Document

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


def _make_pdf(name: str) -> ContentFile:
    return ContentFile(PDF_BYTES + name.encode(), name=name)


def _ingest(title, submitter_user, public_collection):
    return services.ingest_document(
        file=_make_pdf(f"{title}.pdf"),
        title=title,
        collection=public_collection,
        document_type=Document.DocumentType.THESIS,
        abstract="Abstract text.",
        submitted_by=submitter_user,
        actor=submitter_user,
    )


@pytest.mark.django_db
def test_ingest_creates_initial_version_one_zero(submitter_user, public_collection):
    # FRREP-VL004 — a freshly ingested document already carries version 1.0.
    doc = _ingest("VL004 initial", submitter_user, public_collection)
    versions = list(doc.versions.all())
    assert len(versions) == 1
    assert versions[0].version_number == "1.0"


@pytest.mark.django_db
def test_next_version_number_with_no_prior_version_starts_at_one_zero(
    submitter_user, public_collection
):
    doc = _ingest("VL002 no prior", submitter_user, public_collection)
    # Exercise the "no prior version" branch directly by clearing the auto-1.0.
    doc.versions.all().delete()
    assert services._next_version_number(doc, version_type="major") == "1.0"
    assert services._next_version_number(doc, version_type="minor") == "1.0"


@pytest.mark.django_db
def test_minor_version_increments_decimal(submitter_user, public_collection):
    doc = _ingest("VL002 minor", submitter_user, public_collection)  # 1.0

    v2 = services.add_version(
        doc,
        file=_make_pdf("v2.pdf"),
        changelog="Fixed a typo in the abstract.",
        uploaded_by=submitter_user,
        version_type="minor",
    )
    assert v2.version_number == "1.1"

    v3 = services.add_version(
        doc,
        file=_make_pdf("v3.pdf"),
        changelog="Fixed formatting.",
        uploaded_by=submitter_user,
        version_type="minor",
    )
    assert v3.version_number == "1.2"


@pytest.mark.django_db
def test_major_version_bumps_integer_and_resets_decimal(submitter_user, public_collection):
    doc = _ingest("VL002 major", submitter_user, public_collection)  # 1.0
    services.add_version(
        doc, file=_make_pdf("v2.pdf"), changelog="", uploaded_by=submitter_user, version_type="minor",
    )
    # version is now 1.1 — a major bump must go to 2.0, not 2.1.
    v3 = services.add_version(
        doc,
        file=_make_pdf("v3.pdf"),
        changelog="Substantive revision — new analysis chapter.",
        uploaded_by=submitter_user,
        version_type="major",
    )
    assert v3.version_number == "2.0"


@pytest.mark.django_db
def test_invalid_version_type_raises(submitter_user, public_collection):
    doc = _ingest("VL002 invalid", submitter_user, public_collection)
    with pytest.raises(ValidationError):
        services.add_version(
            doc,
            file=_make_pdf("bad.pdf"),
            changelog="",
            uploaded_by=submitter_user,
            version_type="bogus",
        )


@pytest.mark.django_db
def test_default_version_type_is_major(submitter_user, public_collection):
    doc = _ingest("VL002 default", submitter_user, public_collection)  # 1.0
    v1 = services.add_version(doc, file=_make_pdf("v2.pdf"), changelog="", uploaded_by=submitter_user)
    assert v1.version_number == "2.0"
    v2 = services.add_version(doc, file=_make_pdf("v3.pdf"), changelog="", uploaded_by=submitter_user)
    assert v2.version_number == "3.0"


@pytest.mark.django_db
def test_view_wires_selected_minor_version_type_through(client, submitter_user, public_collection):
    doc = _ingest("VL002 view minor", submitter_user, public_collection)  # 1.0

    client.force_login(submitter_user)
    resp = client.post(
        reverse("repo_documents:document_version_upload", kwargs={"uid": doc.document_uid}),
        {
            "file": SimpleUploadedFile("v2.pdf", PDF_BYTES, content_type="application/pdf"),
            "version_type": "minor",
            "changelog": "Small fix.",
        },
    )
    assert resp.status_code == 302
    latest = doc.versions.order_by("-uploaded_at").first()
    assert latest.version_number == "1.1"


@pytest.mark.django_db
def test_view_wires_selected_major_version_type_through(client, submitter_user, public_collection):
    doc = _ingest("VL002 view major", submitter_user, public_collection)  # 1.0

    client.force_login(submitter_user)
    resp = client.post(
        reverse("repo_documents:document_version_upload", kwargs={"uid": doc.document_uid}),
        {
            "file": SimpleUploadedFile("v2.pdf", PDF_BYTES, content_type="application/pdf"),
            "version_type": "major",
            "changelog": "New chapter added.",
        },
    )
    assert resp.status_code == 302
    latest = doc.versions.order_by("-uploaded_at").first()
    assert latest.version_number == "2.0"
