"""Arrival: the tool walkthrough's state and the contents pane.

The rule under test throughout is rian's: the tour is offered ONCE per person
per board, and never becomes a wall in front of the work.
"""

import pytest

from app.services import projects as svc
from tests.conftest import as_user
from tests.test_domain import MOCKUP, add_screen_option, make_project


def test_the_tour_is_offered_once_per_person_per_board(client, kit):
    iid = make_project(client, kit)
    add_screen_option(client, iid)

    as_user(client, "cleo")
    state = client.get(f"/api/projects/{iid}/contents").json()["tool_tour"]
    assert state["should_offer"] is True
    assert state["seen_version"] == 0

    # Dismissing ("I'll explore on my own") counts. Asking again next visit is
    # precisely the wall the milestone forbids.
    assert client.post(f"/api/projects/{iid}/tour/seen",
                       json={"completed": False}).status_code == 200
    state = client.get(f"/api/projects/{iid}/contents").json()["tool_tour"]
    assert state["should_offer"] is False
    assert state["completed"] is False
    assert state["seen_version"] == state["version"]


def test_finishing_the_tour_is_recorded_as_completed(client, kit):
    iid = make_project(client, kit)
    add_screen_option(client, iid)
    as_user(client, "cleo")
    client.post(f"/api/projects/{iid}/tour/seen", json={"completed": True})
    state = client.get(f"/api/projects/{iid}/contents").json()["tool_tour"]
    assert (state["completed"], state["should_offer"]) == (True, False)


def test_a_dismissal_is_not_downgraded_by_a_later_replay(client, kit):
    """Replaying from the contents pane must not un-complete someone."""
    iid = make_project(client, kit)
    add_screen_option(client, iid)
    as_user(client, "cleo")
    client.post(f"/api/projects/{iid}/tour/seen", json={"completed": True})
    client.post(f"/api/projects/{iid}/tour/seen", json={"completed": False})
    assert client.get(f"/api/projects/{iid}/contents").json()["tool_tour"]["completed"]


def test_bumping_the_version_does_not_re_offer_the_tour(client, kit, monkeypatch):
    """Seen is seen (rian, 2026-09-07): a client who walked the introduction
    does not meet the welcome again because we changed a sentence. The version
    stays on the record; the board offers a replay for anyone who wants it."""
    iid = make_project(client, kit)
    add_screen_option(client, iid)
    as_user(client, "cleo")
    client.post(f"/api/projects/{iid}/tour/seen", json={"completed": True})
    assert not client.get(f"/api/projects/{iid}/contents").json()["tool_tour"]["should_offer"]

    monkeypatch.setattr(svc, "TOOL_TOUR_VERSION", svc.TOOL_TOUR_VERSION + 1)
    state = client.get(f"/api/projects/{iid}/contents").json()["tool_tour"]
    assert state["should_offer"] is False
    assert state["seen_version"] < state["version"]


def test_being_walked_through_one_board_does_not_cover_another(client, kit):
    """'Once per person per board' — a client added to a second project is
    oriented there too rather than assumed fluent."""
    first = make_project(client, kit, name="First")
    add_screen_option(client, first)
    as_user(client, "mara")
    second = client.post("/api/projects", json={"name": "Second"}).json()["id"]
    kit.grant("cleo", second, "member")
    add_screen_option(client, second)

    as_user(client, "cleo")
    client.post(f"/api/projects/{first}/tour/seen", json={"completed": True})
    assert client.get(f"/api/projects/{second}/contents").json()["tool_tour"]["should_offer"]


# ------------------------------------------------------------------ contents

def test_contents_groups_tours_by_screen_under_a_how_to_section(client, kit):
    iid = make_project(client, kit)
    sid, oid = add_screen_option(client, iid, "Homepage")
    client.post(f"/api/options/{oid}/walkthrough", json={
        "title": "Start here", "body_md": "…", "target_selector": ".hero",
        "requires_approval": True})

    as_user(client, "cleo")
    sections = client.get(f"/api/projects/{iid}/contents").json()["sections"]
    assert [s["kind"] for s in sections] == ["tool", "screen"]
    assert sections[0]["title"] == "Tool Introduction"
    assert sections[1]["title"] == "Homepage"
    item = sections[1]["items"][0]
    assert (item["title"], item["steps"], item["required"]) == ("Option 1", 1, 1)
    assert item["href"] == f"/p/{iid}/o/{oid}"
    assert item["done"] is False


def test_progress_is_answered_from_the_askers_chair(client, kit):
    """A client sees what THEY have been through; a manager sees what the CLIENT
    has been through — the question each of them actually has."""
    iid = make_project(client, kit)
    _sid, oid = add_screen_option(client, iid)
    step = client.post(f"/api/options/{oid}/walkthrough", json={
        "title": "Does this land?", "body_md": "…", "target_selector": ".x",
        "requires_approval": True}).json()["id"]

    # The manager approving their own presentation must not read as progress.
    client.post(f"/api/walkthrough/{step}/approve", json={})
    screen_section = client.get(f"/api/projects/{iid}/contents").json()["sections"][1]
    assert screen_section["items"][0]["done"] is False

    as_user(client, "cleo")
    assert not client.get(f"/api/projects/{iid}/contents").json()["sections"][1]["done"]
    client.post(f"/api/walkthrough/{step}/approve", json={})
    section = client.get(f"/api/projects/{iid}/contents").json()["sections"][1]
    assert (section["done"], section["done_count"], section["total"]) == (True, 1, 1)

    as_user(client, "mara")
    assert client.get(f"/api/projects/{iid}/contents").json()["sections"][1]["done"]


def test_an_entry_with_nothing_to_approve_is_not_counted_as_done(client, kit):
    """It is a place to go, not a beat to complete — counting it would make the
    progress read a lie."""
    iid = make_project(client, kit)
    _sid, oid = add_screen_option(client, iid)
    client.post(f"/api/options/{oid}/walkthrough", json={
        "title": "FYI", "body_md": "…", "target_selector": ".x",
        "requires_approval": False})
    as_user(client, "cleo")
    section = client.get(f"/api/projects/{iid}/contents").json()["sections"][1]
    assert section["items"][0]["done"] is False
    assert section["total"] == 0        # nothing completable, so nothing claimed


def test_contents_hides_what_the_client_cannot_see(client, kit):
    iid = make_project(client, kit)
    sid, _oid = add_screen_option(client, iid, "Homepage")
    add_screen_option(client, iid, "About", with_mockup=False)
    draft = client.post(f"/api/screens/{sid}/options",
                        json={"title": "Draft", "concept_tag": "wip"}).json()["id"]

    titles = [s["title"] for s in
              client.get(f"/api/projects/{iid}/contents").json()["sections"]]
    assert titles == ["Tool Introduction", "Homepage", "About"]

    as_user(client, "cleo")
    sections = client.get(f"/api/projects/{iid}/contents").json()["sections"]
    assert [s["title"] for s in sections] == ["Tool Introduction", "Homepage"]
    assert all(i["key"] != f"option-{draft}" for i in sections[1]["items"])


def test_contents_and_tour_404_for_a_non_member(client, kit):
    iid = make_project(client, kit)
    add_screen_option(client, iid)
    as_user(client, "nate")
    assert client.get(f"/api/projects/{iid}/contents").status_code == 404
    assert client.post(f"/api/projects/{iid}/tour/seen", json={}).status_code == 404


@pytest.mark.parametrize("chosen", [False, True])
def test_contents_marks_the_chosen_direction(client, kit, chosen):
    iid = make_project(client, kit)
    sid, oid = add_screen_option(client, iid)
    if chosen:
        client.post(f"/api/screens/{sid}/select", json={"option_id": oid})
    as_user(client, "cleo")
    item = client.get(f"/api/projects/{iid}/contents").json()["sections"][1]["items"][0]
    assert item["chosen"] is chosen
