"""View-level smoke tests for the Repository UI."""

from __future__ import annotations

import json
from pathlib import Path

import pytest
from django.conf import settings
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.models import Document


@pytest.mark.django_db
def test_browse_page_renders(public_collection):
    client = Client()
    resp = client.get(reverse("repo_documents:browse"))
    assert resp.status_code == 200


@pytest.mark.django_db
def test_qa_queue_requires_role(public_collection, submitter_user):
    client = Client()
    client.login(email="submitter@test.example", password="pw-test-1234")
    resp = client.get(reverse("repo_documents:qa_queue"))
    assert resp.status_code in (302, 403)  # redirect to login or forbidden


@pytest.mark.django_db
def test_manager_can_view_qa_queue(public_collection, manager_user):
    client = Client()
    client.login(email="repo.manager@test.example", password="pw-test-1234")
    resp = client.get(reverse("repo_documents:qa_queue"))
    assert resp.status_code == 200


# ── Wizard staged-upload flow ──────────────────────────────────────────────


def _pdf_bytes() -> bytes:
    return b"%PDF-1.4\n%\xe2\xe3\xcf\xd3\n1 0 obj<</Type/Catalog>>endobj\ntrailer<<>>\n%%EOF\n"


@pytest.mark.django_db
def test_staged_upload_returns_token_and_persists_file(submitter_user):
    client = Client()
    client.login(email="submitter@test.example", password="pw-test-1234")
    upload = SimpleUploadedFile(
        "wizard.pdf", _pdf_bytes(), content_type="application/pdf"
    )
    resp = client.post(reverse("repo_documents:staged_upload"), {"file": upload})
    assert resp.status_code == 200
    payload = resp.json()
    assert payload["token"]
    assert payload["name"] == "wizard.pdf"

    staged_path = (
        Path(settings.MEDIA_ROOT) / "staged_uploads" / payload["token"] / "wizard.pdf"
    )
    assert staged_path.exists()


@pytest.mark.django_db
def test_staged_upload_requires_authentication():
    client = Client()
    upload = SimpleUploadedFile("anon.pdf", _pdf_bytes(), content_type="application/pdf")
    resp = client.post(reverse("repo_documents:staged_upload"), {"file": upload})
    assert resp.status_code in (302, 403)  # login redirect or denied


@pytest.mark.django_db
def test_submit_wizard_consumes_staged_token(public_collection, submitter_user):
    """Wizard path: stage the file separately, then post metadata + token."""
    client = Client()
    client.login(email="submitter@test.example", password="pw-test-1234")

    upload = SimpleUploadedFile(
        "thesis.pdf", _pdf_bytes(), content_type="application/pdf"
    )
    stage_resp = client.post(reverse("repo_documents:staged_upload"), {"file": upload})
    assert stage_resp.status_code == 200
    token = stage_resp.json()["token"]
    staged_path = (
        Path(settings.MEDIA_ROOT) / "staged_uploads" / token / "thesis.pdf"
    )
    assert staged_path.exists()

    submit_resp = client.post(
        reverse("repo_documents:submit"),
        data={
            "title": "A Wizard Submission",
            "abstract": "Body.",
            "document_type": Document.DocumentType.THESIS,
            "license_type": Document.License.CC_BY,
            "license_notes": "",
            "language": "en",
            "year": 2026,
            "doi": "",
            "collection": public_collection.pk,
            "visibility": Document.Visibility.INHERIT,
            "grant_reference": "",
            "authors_text": "Doe, Jane",
            "keywords_text": "",
            "staged_token": token,
        },
    )
    assert submit_resp.status_code == 302
    doc = Document.objects.get(title="A Wizard Submission")
    assert doc.file
    # Staged copy is cleaned up on successful submission.
    assert not staged_path.exists()


@pytest.mark.django_db
def test_submit_form_rejects_when_no_file_or_token(public_collection, submitter_user):
    client = Client()
    client.login(email="submitter@test.example", password="pw-test-1234")
    resp = client.post(
        reverse("repo_documents:submit"),
        data={
            "title": "No file",
            "abstract": "x",
            "document_type": Document.DocumentType.THESIS,
            "license_type": Document.License.CC_BY,
            "language": "en",
            "year": 2026,
            "collection": public_collection.pk,
            "visibility": Document.Visibility.INHERIT,
            "authors_text": "Doe, Jane",
        },
    )
    # Form re-renders with the file error rather than redirecting.
    assert resp.status_code == 200
    assert b"source file is required" in resp.content.lower()


@pytest.mark.django_db
def test_staged_upload_delete_clears_token(submitter_user):
    client = Client()
    client.login(email="submitter@test.example", password="pw-test-1234")
    upload = SimpleUploadedFile("drop.pdf", _pdf_bytes(), content_type="application/pdf")
    stage = client.post(reverse("repo_documents:staged_upload"), {"file": upload}).json()
    token = stage["token"]
    staged_path = (
        Path(settings.MEDIA_ROOT) / "staged_uploads" / token / "drop.pdf"
    )
    assert staged_path.exists()

    resp = client.delete(
        reverse("repo_documents:staged_upload"),
        data=json.dumps({"token": token}),
        content_type="application/json",
    )
    assert resp.status_code == 200
    assert not staged_path.exists()


# ── Collection list: dense-list default + grid toggle (P1-2) ───────────────


@pytest.mark.django_db
def test_collection_list_defaults_to_list_view(public_collection):
    """No ?view= → dense list (collection-row), not card grid."""
    client = Client()
    resp = client.get(reverse("repo_documents:collection_list"))
    assert resp.status_code == 200
    body = resp.content.decode()
    assert "collection-row" in body
    assert "collection-card" not in body


@pytest.mark.django_db
def test_collection_list_grid_view_via_query(public_collection):
    """?view=grid restores the legacy card grid."""
    client = Client()
    resp = client.get(reverse("repo_documents:collection_list") + "?view=grid")
    assert resp.status_code == 200
    body = resp.content.decode()
    assert "collection-card" in body
    # Dense-list rows are not rendered in grid mode.
    assert "collection-row" not in body


# ── Document detail: action-bar mobile overflow (P2-2) ─────────────────────


@pytest.mark.django_db
def test_document_detail_action_bar_renders_overflow_for_authenticated_user(
    public_collection, manager_user
):
    """Authenticated user sees both the desktop overflow row and the mobile
    "More actions" trigger. Each surface includes one of the shared partial's
    role-gated links (e.g. document_share)."""
    doc = Document.objects.create(
        title="Action-bar smoke",
        abstract="x",
        document_type=Document.DocumentType.THESIS,
        license_type=Document.License.CC_BY,
        language="en",
        year=2026,
        collection=public_collection,
        visibility=Document.Visibility.PUBLIC_OPEN,
        status=Document.Status.PUBLISHED,
        submitted_by=manager_user,
        file=SimpleUploadedFile("ab.pdf", _pdf_bytes(), content_type="application/pdf"),
    )

    client = Client()
    client.force_login(manager_user)
    resp = client.get(reverse("repo_documents:document_detail", kwargs={"uid": doc.document_uid}))
    assert resp.status_code == 200
    body = resp.content.decode()
    # Desktop overflow row (icon-only) is hidden on small screens via sm:flex.
    assert "action-bar__overflow hidden sm:flex" in body
    # Mobile trigger exists, with the More-actions sheet container.
    assert "action-bar__more" in body
    assert "action-bar-more-sheet" in body
    assert 'aria-label="More actions"' in body
    # The shared partial is wired on both surfaces, so the Share URL appears.
    assert "document_share" in body or "/share" in body


# ── FRREP-SR009 — anonymous CTA on a gated document ─────────────────────────


def _gated_doc(collection, manager_user):
    # AUTHENTICATED (not RESTRICTED) so a plain signed-in non-owner user can
    # reach the page naturally (can_access=True) while still failing
    # can_download — matches the "download / request-access" branch pair
    # this fix touches, without needing to relax the object-level gate.
    return Document.objects.create(
        title="Gated report",
        abstract="x",
        document_type=Document.DocumentType.TECHNICAL_REPORT,
        license_type=Document.License.CC_BY,
        language="en",
        year=2026,
        collection=collection,
        visibility=Document.Visibility.AUTHENTICATED,
        status=Document.Status.PUBLISHED,
        submitted_by=manager_user,
        file=SimpleUploadedFile("gated.pdf", _pdf_bytes(), content_type="application/pdf"),
    )


@pytest.mark.django_db
def test_anonymous_sees_sign_in_cta_on_gated_document(
    public_collection, manager_user, monkeypatch
):
    """An AUTHENTICATED-visibility document 403s an anonymous visitor at the
    permission gate (unchanged, pre-existing behaviour) — this test exercises
    the action-bar template logic in isolation by relaxing that gate, matching
    the SRS surface the fix actually targets: neither a download button nor
    any way to request access was ever shown to an anonymous visitor here."""
    from apps.repository.documents import views as repo_views

    monkeypatch.setattr(repo_views, "can_access", lambda user, doc: True)
    doc = _gated_doc(public_collection, manager_user)

    resp = Client().get(reverse("repo_documents:document_detail", kwargs={"uid": doc.document_uid}))
    assert resp.status_code == 200
    body = resp.content.decode()
    assert "Sign in to request access" in body
    assert f"{reverse('accounts:login')}?next=" in body
    # No download button, and no bare (non-CTA) "Request access" either.
    assert "document_download" not in body


@pytest.mark.django_db
def test_authenticated_sees_request_access_not_sign_in_cta(
    public_collection, manager_user, submitter_user
):
    doc = _gated_doc(public_collection, manager_user)
    client = Client()
    client.force_login(submitter_user)
    resp = client.get(reverse("repo_documents:document_detail", kwargs={"uid": doc.document_uid}))
    assert resp.status_code == 200
    body = resp.content.decode()
    assert "Sign in to request access" not in body
    assert "Request access" in body
