"""The library's standing rail, and everything it must not have cost.

The layout changed; the features did not. These tests pin both halves: that
the rail counts what it claims to, and that the browser, uploader, groups and
staff controls all survived the rebuild.
"""
import shutil
import tempfile

from django.contrib.auth import get_user_model
from django.core.files.uploadedfile import SimpleUploadedFile
from django.test import TestCase, override_settings
from django.urls import reverse

from documents.models import Category, Collection, Document

User = get_user_model()
_TMP = tempfile.mkdtemp(prefix="hartling-rail-test-")


def pdf(name="a.pdf"):
    return SimpleUploadedFile(name, b"%PDF-1.4", content_type="application/pdf")


@override_settings(PRIVATE_MEDIA_ROOT=_TMP)
class LibraryRailTests(TestCase):
    @classmethod
    def tearDownClass(cls):
        shutil.rmtree(_TMP, ignore_errors=True)
        super().tearDownClass()

    def setUp(self):
        self.staff = User.objects.create_user("staff", password="pw-staff-12345", is_staff=True)
        self.owner = User.objects.create_user("owner", password="pw-owner-12345")
        self.minutes = Category.objects.create(name="Minutes", slug="minutes")
        self.batch = Collection.objects.create(
            title="2026 AGM", slug="2026-agm", occurred_on="2026-05-01")
        for i in range(3):
            Document.objects.create(
                title="Minute %d" % i, category=self.minutes, collection=self.batch,
                published=True, published_date="2026-05-01", file=pdf("m%d.pdf" % i))

    def body(self, user, **params):
        self.client.force_login(user)
        response = self.client.get(reverse("documents:library"), params, secure=True)
        self.assertEqual(response.status_code, 200)
        return response

    # ---- the rail ----
    def test_the_rail_lists_categories_with_a_document_count(self):
        response = self.body(self.owner)
        rail = [e for e in response.context["rail_categories"]]
        self.assertEqual([(e["category"].name, e["count"]) for e in rail], [("Minutes", 3)])

    def test_the_rail_counts_documents_not_rows(self):
        """Three documents in one collection is three, not one.

        The rail and the section heading describe the same category, so if one
        counts rows and the other documents they contradict each other on screen.
        """
        response = self.body(self.owner)
        rail = {e["category"].name: e["count"] for e in response.context["rail_categories"]}
        section = {s["label"]: s["total"] for s in response.context["sections"]}
        self.assertEqual(rail["Minutes"], 3)
        self.assertEqual(section["Minutes"], 3)

    def test_a_trashed_document_leaves_the_rail_count(self):
        from django.utils import timezone
        doc = Document.objects.first()
        doc.removed_at = timezone.now()
        doc.save(update_fields=["removed_at"])
        rail = {e["category"].name: e["count"] for e in self.body(self.owner).context["rail_categories"]}
        self.assertEqual(rail["Minutes"], 2)

    def test_a_category_with_nothing_visible_is_not_listed(self):
        Category.objects.create(name="Empty", slug="empty")
        names = [e["category"].name for e in self.body(self.owner).context["rail_categories"]]
        self.assertNotIn("Empty", names)

    def test_owners_get_the_rail_too(self):
        body = self.body(self.owner).content.decode()
        self.assertIn('class="rail"', body)
        self.assertIn("rail-item", body)

    def test_the_rail_is_a_drawer_on_a_phone(self):
        body = self.body(self.owner).content.decode()
        for hook in ('id="rail-open"', 'id="rail-scrim"', 'id="rail-close"'):
            self.assertIn(hook, body)

    @override_settings(SHOW_DOCUMENT_DATES=True)
    def test_choosing_a_category_narrows_the_pane(self):
        other = Category.objects.create(name="Financials", slug="financials")
        Document.objects.create(title="Budget", category=other, published=True,
                                published_date="2026-01-01", file=pdf("b.pdf"))
        response = self.body(self.owner, group="date", category="financials")
        titles = [i["document"].title for s in response.context["sections"] for i in s["items"]]
        self.assertEqual(titles, ["Budget"])
        self.assertEqual(response.context["pane_title"], "Financials")

    # ---- nothing was lost in the rebuild ----
    def test_the_uploader_is_still_there_for_staff_only(self):
        self.assertIn("page-dropzone", self.body(self.staff).content.decode())
        self.assertNotIn("page-dropzone", self.body(self.owner).content.decode())

    def test_search_grouping_and_the_browser_all_survived(self):
        body = self.body(self.owner).content.decode()
        for hook in ('id="filter"', 'id="browser"', 'id="no-matches"',
                     'id="result-line"', 'class="segmented"'):
            self.assertIn(hook, body)

    def test_groups_still_expand_and_staff_still_get_their_controls(self):
        body = self.body(self.staff).content.decode()
        self.assertIn('class="folder"', body)          # the expandable group
        self.assertIn('data-kind="collection"', body)  # edit
        self.assertIn("edit-dialog", body)
        self.assertIn("upload-dialog", body)

    def test_the_category_pill_shows_only_in_the_flat_view(self):
        """Anywhere grouped, the pill repeats what the reader already knows —
        the section heading, or the category they picked in the rail."""
        pill = 'class="tag has-colour"'
        grouped = self.body(self.owner).content.decode()
        self.assertNotIn(pill, grouped)
        picked = self.body(self.owner, group="date", category="minutes").content.decode()
        self.assertNotIn(pill, picked)
        flat = self.body(self.owner, group="all").content.decode()
        self.assertIn(pill, flat)

    def test_the_flat_view_is_still_reachable(self):
        response = self.body(self.owner, group="all")
        self.assertEqual([s["label"] for s in response.context["sections"]], ["Everything"])
