"""The review process document, read at runtime rather than restated (Stream K10.2).

`docs/REVIEW-PROCESS.md` is the authority for what a rule may do without asking a person, and its
version line is a rules version: changing it is a deploy and, when the boundary moves, a rederive.
The first tab of `/review` shows it to a person who is not going to read the repository, so the
server reads the file and hands over its sections. A second copy of a rule in the page would go
stale the first time the doc changed, which is the failure the boundary exists to stop.

What it cost before this was tested: the document's grouping defaults are a table, and the
markdown renderer had no table support, so section 2 -- the block a person opens the tab to read --
rendered as one unreadable run-on paragraph.

Pure logic: no network, no database for the reader itself.
"""
from __future__ import annotations

import pathlib

import pytest

from app.services import process_doc
from app.services.markdown import render_markdown

DOC = pathlib.Path(__file__).resolve().parents[1] / "docs" / "REVIEW-PROCESS.md"


class TestTheDocumentIsFound:
    def test_the_checkout_copy_is_found_and_is_the_real_file(self):
        assert process_doc.path() == DOC

    def test_the_image_path_is_tried_first_so_the_container_reads_its_own_copy(self):
        """The runtime stage copies this one doc (`Dockerfile`); nothing else from `docs/` ships."""
        assert process_doc._CANDIDATES[0] == pathlib.Path("/srv/app/docs/REVIEW-PROCESS.md")
        dockerfile = (pathlib.Path(__file__).resolve().parents[1] / "Dockerfile").read_text()
        assert "COPY docs/REVIEW-PROCESS.md ./docs/REVIEW-PROCESS.md" in dockerfile

    def test_a_missing_document_says_so_rather_than_inventing_content(self, monkeypatch):
        monkeypatch.setitem(process_doc._DOCS["REVIEW-PROCESS"], "candidates", (pathlib.Path("/nowhere/REVIEW-PROCESS.md"),))
        out = process_doc.read()
        assert out["missing"] is True and out["sections"] == [] and out["version"] is None


class TestTheFeaturedDocument:
    """`docs/FEATURED.md` (Stream AW2, D8) is read by the same reader under its own name: the
    public page `/how-we-choose` and `GET /api/featured/method` hand over its sections. What a
    second reader would cost: two parsers of one file shape, drifting on the first edit."""

    FEATURED = pathlib.Path(__file__).resolve().parents[1] / "docs" / "FEATURED.md"

    def test_the_checkout_copy_is_found_and_the_image_path_is_tried_first(self):
        assert process_doc.path("FEATURED") == self.FEATURED
        assert process_doc._DOCS["FEATURED"]["candidates"][0] == pathlib.Path("/srv/app/docs/FEATURED.md")
        dockerfile = (pathlib.Path(__file__).resolve().parents[1] / "Dockerfile").read_text()
        assert "COPY docs/FEATURED.md ./docs/FEATURED.md" in dockerfile

    def test_the_review_process_reader_is_untouched(self):
        assert process_doc._CANDIDATES[0] == pathlib.Path("/srv/app/docs/REVIEW-PROCESS.md")
        assert process_doc.read() == process_doc.read_doc("REVIEW-PROCESS")

    def test_an_unknown_name_is_a_key_error(self):
        with pytest.raises(KeyError):
            process_doc.read_doc("NO-SUCH-DOC")
        with pytest.raises(KeyError):
            process_doc.path("NO-SUCH-DOC")

    def test_the_lede_leads_as_in_short_without_the_version_line(self):
        out = process_doc.read_doc("FEATURED")
        assert out["title"] == "How we choose what is featured" and out["path"] == "docs/FEATURED.md"
        assert out["version"] and out["dated"] and f"**Version {out['version']}, {out['dated']}**" in self.FEATURED.read_text()
        lead = out["sections"][0]
        assert (lead["title"], lead["anchor"], lead["number"]) == ("In short", "in-short", None)
        assert "Version" not in lead["html"] and "<p>Every list on this site" in lead["html"]
        # the review process keeps its version line inside the standing rules, as before
        assert "Version" in process_doc.read()["sections"][0]["html"]

    def test_a_missing_document_and_an_unversioned_one_are_no_authority(self, monkeypatch, tmp_path):
        monkeypatch.setitem(process_doc._DOCS["FEATURED"], "candidates", (pathlib.Path("/nowhere/FEATURED.md"),))
        assert process_doc.read_doc("FEATURED")["missing"] is True
        assert process_doc.featured_method() is None
        unversioned = tmp_path / "FEATURED.md"
        unversioned.write_text("# How we choose what is featured\n\nA lede.\n\n## One\n\nBody.\n")
        monkeypatch.setitem(process_doc._DOCS["FEATURED"], "candidates", (unversioned,))
        out = process_doc.read_doc("FEATURED")
        assert out["missing"] is False and out["version"] is None and len(out["sections"]) == 2
        assert process_doc.featured_method() is None


class TestWhatTheTabShows:
    def test_the_version_line_is_the_document_s_own(self):
        out = process_doc.read()
        assert out["version"] and out["dated"] and out["version_line"].startswith("**Version ")
        assert f"**Version {out['version']}, {out['dated']}**" in DOC.read_text()

    def test_every_section_of_the_document_arrives_with_its_number_and_title(self):
        out = process_doc.read()
        numbered = [s for s in out["sections"] if s["number"]]
        assert [s["number"] for s in numbered] == [str(n) for n in range(1, len(numbered) + 1)]
        titles = {s["number"]: s["title"] for s in numbered}
        assert "certain boundary" in titles["1"]
        assert titles["2"].startswith("Grouping defaults")
        assert "spot-check" in titles["4"]
        assert out["sections"][0]["number"] is None, "the standing rules lead, before section 1"

    def test_the_standing_rules_carry_the_two_a_machine_never_breaks(self):
        standing = process_doc.read()["sections"][0]["html"]
        assert "machine never applies a proposal" in standing and "machine never undoes a decision" in standing

    def test_the_boundary_and_the_thresholds_arrive_as_the_document_wrote_them(self):
        by_number = {s["number"]: s["html"] for s in process_doc.read()["sections"]}
        assert "The brand, matched to its row" in by_number["1"]
        assert "lowest" in by_number["4"] and "0.7" in by_number["4"]

    def test_the_grouping_defaults_are_a_table_and_render_as_one(self):
        """Section 2 is the block rian opens this tab for; as a paragraph it is unreadable."""
        html = next(s["html"] for s in process_doc.read()["sections"] if s["number"] == "2")
        assert "<table>" in html and html.count("<tr>") > 8
        assert "<th>Vertical and case</th>" in html
        assert "|---|" not in html


class TestTheTableRenderer:
    def test_a_pipe_table_becomes_a_table(self):
        html = render_markdown("| A | B |\n|---|---|\n| one | two |")
        assert html == ("<table><thead><tr><th>A</th><th>B</th></tr></thead>"
                        "<tbody><tr><td>one</td><td>two</td></tr></tbody></table>")

    def test_a_short_row_is_padded_and_a_long_one_trimmed_rather_than_shifting_the_columns(self):
        html = render_markdown("| A | B |\n|---|---|\n| one |\n| x | y | z |")
        assert "<tr><td>one</td><td></td></tr>" in html and "<tr><td>x</td><td>y</td></tr>" in html

    def test_a_line_with_a_pipe_that_is_not_a_table_is_still_a_paragraph(self):
        assert render_markdown("a | b and nothing else").startswith("<p>")
        assert "<table>" not in render_markdown("| A | B |\nplain text")

    def test_inline_markup_inside_a_cell_is_rendered_and_html_is_escaped(self):
        html = render_markdown("| A | B |\n|---|---|\n| **bold** | `<script>` |")
        assert "<strong>bold</strong>" in html and "&lt;script&gt;" in html and "<script>" not in html


class TestTheReviewGuide:
    """The guide answers two questions and carries no history (rian, 18 Sep): what is cleaning the
    data right now, and what a pass is looking for. It used to render the process document section
    by section, which made the tab a development diary."""

    def test_the_collection_rules_come_from_the_code_that_performs_them(self):
        from app.services import collection_rules, product_lines

        read = collection_rules.read()
        assert len(read["acting"]) >= 6
        concentration = next(r for r in read["acting"] if r["key"] == "concentration")
        # read from ATTRIBUTE_LABELS, so a vocabulary change reaches the page without an edit here
        assert product_lines.ATTRIBUTE_LABELS["edp"] in concentration["example"]
        assert all(r["name"] and r["what"] and r["applies_to"] for r in read["acting"])

    def test_a_list_that_only_suggests_is_not_listed_as_cleaning(self):
        from app.services import collection_rules

        read = collection_rules.read()
        assert read["suggesting"], "the word lists are shown, as lists that do not act"
        assert not ({r["key"] for r in read["acting"]} & {r["key"] for r in read["suggesting"]})

    def test_every_guideline_is_a_headline_with_a_body(self):
        from app.services import guidelines

        read = guidelines.read()
        assert not read["missing"] and len(read["guidelines"]) >= 10
        assert all(g["headline"] and g["html"] for g in read["guidelines"])

    def test_the_guidelines_carry_no_development_history(self):
        """The whole point of the file: a reviewer reads what to do, not what was done."""
        from app.services import guidelines

        source = guidelines.path().read_text(encoding="utf-8")
        body = "\n".join(l for l in source.splitlines() if not l.strip().startswith("<!--") and "-->" not in l)
        for banned in ("Stream K", "rian said", "**Version", "walk-through W", "2026-09"):
            assert banned not in body, f"{banned!r} is history, and history lives in REVIEW-PROCESS.md"
