"""Performance regression tests: count annotations + prefetch reuse stay O(1) queries."""

from datetime import date

import pytest
from django.contrib.auth import get_user_model
from django.db import connection
from django.test.utils import CaptureQueriesContext
from rest_framework.test import APIClient

from apps.administrations.models import DocumentRequest, LetterNumber, LetterPrefix, SOP, SOPCategory

User = get_user_model()


@pytest.fixture
def client(db):
    admin = User.objects.create_superuser(email="admin@test.local", password="x")
    c = APIClient()
    c.force_authenticate(admin)
    return c


def _make_letter(prefix, request=None, seq=1):
    return LetterNumber.objects.create(
        prefix=prefix, year=2026, month=6, sequence=seq,
        subject=f"S{seq}", recipient="R", sender="X", date=date(2026, 6, seq),
        document_request=request,
    )


def _rows(resp):
    body = resp.json()
    return body["results"] if isinstance(body, dict) and "results" in body else body


@pytest.mark.django_db
class TestLetterPrefixCounts:
    def test_counts_correct(self, client):
        a = LetterPrefix.objects.create(code="A", label="A dept")
        b = LetterPrefix.objects.create(code="B", label="B dept")
        _make_letter(a, seq=1)
        _make_letter(a, seq=2)

        rows = {r["code"]: r for r in _rows(client.get("/api/letter-prefixes/"))}
        assert rows["A"]["letter_count"] == 2
        assert rows["B"]["letter_count"] == 0

    def test_queries_constant_in_rows(self, client):
        for i in range(2):
            LetterPrefix.objects.create(code=f"P{i}", label=f"P{i}")
        with CaptureQueriesContext(connection) as small:
            client.get("/api/letter-prefixes/")
        for i in range(2, 8):
            p = LetterPrefix.objects.create(code=f"P{i}", label=f"P{i}")
            _make_letter(p, seq=i)
        with CaptureQueriesContext(connection) as big:
            client.get("/api/letter-prefixes/")
        assert len(big.captured_queries) == len(small.captured_queries)


@pytest.mark.django_db
class TestSOPCategoryCounts:
    def test_counts_correct_including_empty(self, client):
        cat = SOPCategory.objects.create(name="Ops")
        SOPCategory.objects.create(name="Empty")
        author = User.objects.create_user(email="a@test.local", password="x")
        for i in range(3):
            SOP.objects.create(code=f"SOP-{i}", title=f"T{i}", category="Ops",
                               content="c", author=author, effective_date=date(2026, 1, 1))

        rows = {r["name"]: r for r in _rows(client.get("/api/sop-categories/"))}
        assert rows["Ops"]["sop_count"] == 3
        assert rows["Empty"]["sop_count"] == 0  # Coalesce path, not a fallback query

    def test_queries_constant_in_rows(self, client):
        author = User.objects.create_user(email="a@test.local", password="x")
        SOPCategory.objects.create(name="C0")
        with CaptureQueriesContext(connection) as small:
            client.get("/api/sop-categories/")
        for i in range(1, 7):
            SOPCategory.objects.create(name=f"C{i}")
            SOP.objects.create(code=f"SOP-{i}", title="T", category=f"C{i}",
                               content="c", author=author, effective_date=date(2026, 1, 1))
        with CaptureQueriesContext(connection) as big:
            client.get("/api/sop-categories/")
        assert len(big.captured_queries) == len(small.captured_queries)


@pytest.mark.django_db
class TestDocumentRequestLatestLetter:
    def test_latest_letter_fields(self, client):
        requester = User.objects.create_user(email="r@test.local", password="x")
        prefix = LetterPrefix.objects.create(code="DOC", label="Docs")
        req = DocumentRequest.objects.create(
            requester=requester, document_type="permit", purpose="p")
        _make_letter(prefix, request=req, seq=1)
        latest = _make_letter(prefix, request=req, seq=2)

        rows = _rows(client.get("/api/document-requests/"))
        row = rows[0]
        # uuid7's str() omits dashes; normalize both sides before comparing.
        assert row["letter_id"].replace("-", "") == str(latest.id).replace("-", "")
        assert row["letter_number"] == latest.full_number

    def test_no_letters_yet(self, client):
        requester = User.objects.create_user(email="r@test.local", password="x")
        DocumentRequest.objects.create(
            requester=requester, document_type="permit", purpose="p")
        row = _rows(client.get("/api/document-requests/"))[0]
        assert row["letter_number"] is None
        assert row["letter_id"] is None

    def test_queries_constant_in_rows(self, client):
        requester = User.objects.create_user(email="r@test.local", password="x")
        prefix = LetterPrefix.objects.create(code="DOC", label="Docs")
        req = DocumentRequest.objects.create(
            requester=requester, document_type="permit", purpose="p")
        _make_letter(prefix, request=req, seq=1)
        with CaptureQueriesContext(connection) as small:
            client.get("/api/document-requests/")
        for i in range(2, 7):
            r = DocumentRequest.objects.create(
                requester=requester, document_type=f"doc{i}", purpose="p")
            _make_letter(prefix, request=r, seq=i)
        with CaptureQueriesContext(connection) as big:
            client.get("/api/document-requests/")
        assert len(big.captured_queries) == len(small.captured_queries)
