"""The M1 gate, walked end to end as ONE narrative.

Roadmap §10.1: *create a project from the template, invite a fresh external
client, client signs in on a phone, sees timeline + reference, taps Approve,
and comments on a stage with a screenshot; an @mention lights rian's bell with
a deep link straight to that comment. Two stages run active at once and close
independently; a "Staging site URL" field is created once, then found and
reused by name on a second project.*

Everything above is asserted here except the phone itself — a browser on a
real device is rian's step, and no test can stand in for it. Keeping the gate
as a test rather than a one-time ritual means a later change that quietly
breaks it fails here instead of in front of a client.
"""

import io

from tests.conftest import as_user

PNG = bytes.fromhex("89504e470d0a1a0a") + b"\x00" * 64


def test_the_m1_gate(client, kit, agency):
    # ── the agency composes a project from the seeded roadmap ────────────
    as_user(client, agency)
    r = client.post("/api/projects", json={"display_name": "Gate Project",
                                           "template_key": "website_build_v1",
                                           "client_name_hint": "Dana"})
    assert r.status_code == 201, r.text
    pid = r.json()["id"]
    stages = client.get(f"/api/projects/{pid}").json()["stages"]
    assert len(stages) >= 4, "the template must arrive as a real roadmap"

    # a data point, created once by searching first
    made = client.post("/api/admin/field-definitions",
                       json={"label": "Staging site URL", "type": "url", "confirm": True})
    key = made.json()["key"]
    client.put(f"/api/projects/{pid}/fields/{key}",
               json={"value": "https://staging.example.com", "client_visible": True})

    # something the client should NOT see, sitting right next to it
    client.post(f"/api/projects/{pid}/reference",
                json={"title": "Internal", "body_md": "our own notes"})
    client.post(f"/api/projects/{pid}/reference",
                json={"title": "How to reach us", "body_md": "Reply on any stage.",
                      "client_visible": True})

    # ── a fresh external client joins ────────────────────────────────────
    kit.member("dana", "member")
    kit.grant("dana", pid, "member")

    # ── two stages run at once, and close independently (D13) ────────────
    mockups = next(s for s in stages if s["requires_approval"])
    other = next(s for s in stages if s["id"] != mockups["id"])
    for sid in (mockups["id"], other["id"]):
        assert client.post(f"/api/projects/{pid}/stages/{sid}/status",
                           json={"status": "active"}).status_code == 200
    live = client.get(f"/api/projects/{pid}").json()
    assert len([s for s in live["stages"] if s["status"] == "active"]) == 2

    client.post(f"/api/projects/{pid}/stages/{other['id']}/status", json={"status": "done"})
    after = {s["id"]: s["status"] for s in client.get(f"/api/projects/{pid}").json()["stages"]}
    assert after[other["id"]] == "done"
    assert after[mockups["id"]] == "active", "closing one stage must not touch another"

    # ── the client's view: timeline + reference, nothing internal ────────
    as_user(client, "dana")
    seen = client.get(f"/api/projects/{pid}").json()
    assert seen["is_agency"] is False
    assert [f["label"] for f in seen["fields"]] == ["Staging site URL"]
    assert [r["title"] for r in seen["reference"]] == ["How to reach us"]
    assert any(n["kind"] == "approval" and n["stage_id"] == mockups["id"]
               for n in seen["needed_from_you"]), "the ask has to be on the page"

    # ── taps Approve ─────────────────────────────────────────────────────
    approved = client.post(f"/api/projects/{pid}/stages/{mockups['id']}/approve",
                           json={"note": "Looks great"})
    assert approved.status_code == 200
    stage = next(s for s in approved.json()["project"]["stages"] if s["id"] == mockups["id"])
    assert stage["approval"]["by"] == "dana"

    # ── comments on a stage with a screenshot, and @mentions rian ────────
    up = client.post(f"/api/attachments/{mockups['id']}",
                     files={"file": ("shot.png", io.BytesIO(PNG), "image/png")})
    assert up.status_code == 201
    shot = up.json()["attachment"]
    said = client.post(f"/api/projects/{pid}/stages/{mockups['id']}/comments",
                       json={"body": f"@{agency} the header is off on mobile\n{shot['markdown']}"})
    assert said.status_code == 201
    comment_id = said.json()["id"]

    # ── the bell lights, with a deep link straight to that comment ───────
    as_user(client, agency)
    box = client.get("/api/notifications").json()
    assert box["needs_you"] is True, "a mention is addressed to you, not news"
    hit = next(n for n in box["notifications"] if n["kind"] == "mention")
    assert hit["actor"] == "dana" and hit["app"] == "caddie"
    assert hit["context_label"] == f"Gate Project › {mockups['title']}"
    # absolute (the inbox is cross-app), and it lands ON the comment:
    assert hit["url"].startswith("https://")
    assert f"/projects/{pid}" in hit["url"]
    assert f"stage={mockups['id']}" in hit["url"]
    assert hit["url"].endswith(f"#c-{comment_id}")

    # the screenshot is readable by both sides, and by nobody else
    assert client.get(shot["url"]).status_code == 200
    kit.member("stranger", "member")
    as_user(client, "stranger")
    assert client.get(shot["url"]).status_code == 404

    # ── the data point is FOUND and reused by name on a second project ───
    as_user(client, agency)
    pid2 = client.post("/api/projects", json={"display_name": "Gate Project Two"}).json()["id"]

    found = client.get("/api/admin/field-definitions?q=staging").json()["definitions"]
    reuse = next(d for d in found if d["label"] == "Staging site URL")
    assert reuse["used_in"] == 1, "the count is what makes reuse the obvious move"

    client.put(f"/api/projects/{pid2}/fields/{reuse['key']}",
               json={"value": "https://staging2.example.com"})
    assert [f["label"] for f in client.get(f"/api/projects/{pid2}").json()["fields"]] \
        == ["Staging site URL"]

    # and creating it a second time is interrupted, not silently duplicated
    dupe = client.post("/api/admin/field-definitions", json={"label": "Staging Site Url"})
    assert dupe.json()["needs_confirm"] is True
    assert any(n["label"] == "Staging site URL" for n in dupe.json()["near_matches"])
