"""A conversation about a SCREEN as a whole.

Pins stay the primary act — "about this bit", many of them. This is the other
kind: "about this page", one of it. The feedback that has no spot on the design
("I prefer the second one, but the tone feels formal") had nowhere to go before,
so the client either invented a location for it or kept it to themselves.
"""

from tests.conftest import as_user
from tests.test_domain import add_screen_option, make_project


def test_a_screen_starts_with_no_conversation(client, kit):
    """The thread is made on the first comment, so a screen nobody has spoken
    about carries no empty thread."""
    iid = make_project(client, kit)
    sid, _oid = add_screen_option(client, iid)
    as_user(client, "cleo")
    body = client.get(f"/api/screens/{sid}/thread").json()
    assert body == {"thread_id": None, "resolved": False, "comments": []}


def test_the_client_can_talk_about_the_page_itself(client, kit):
    iid = make_project(client, kit)
    sid, _oid = add_screen_option(client, iid)
    as_user(client, "cleo")
    r = client.post(f"/api/screens/{sid}/comments",
                    json={"body_md": "I prefer the second one, but the tone feels formal."})
    assert r.status_code == 200, r.text

    body = client.get(f"/api/screens/{sid}/thread").json()
    assert body["thread_id"] is not None
    assert body["comments"][0]["author_side"] == "client"
    assert "tone feels formal" in body["comments"][0]["body_md"]


def test_a_screen_has_at_most_one_thread(client, kit):
    """UNIQUE(subject_type, subject_id) in the standard: a running conversation,
    not a pile of notes. The pile is what pins are for."""
    iid = make_project(client, kit)
    sid, _oid = add_screen_option(client, iid)
    as_user(client, "cleo")
    first = client.post(f"/api/screens/{sid}/comments", json={"body_md": "One."}).json()["id"]
    second = client.post(f"/api/screens/{sid}/comments", json={"body_md": "Two."}).json()["id"]
    assert first == second
    assert len(client.get(f"/api/screens/{sid}/thread").json()["comments"]) == 2


def test_a_screen_conversation_turns_the_board(client, kit):
    """The rule that matters. Feedback which does not move the status is
    feedback the client left into silence."""
    iid = make_project(client, kit)
    sid, _oid = add_screen_option(client, iid)
    client.post(f"/api/projects/{iid}/send")
    assert client.get(f"/api/projects/{iid}/status").json()["state"] == "waiting_client"

    as_user(client, "cleo")
    client.post(f"/api/screens/{sid}/comments", json={"body_md": "A thought."})
    status = client.get(f"/api/projects/{iid}/status").json()
    assert status["state"] == "waiting_agency"
    assert status["counts"]["client_open"] == 1

    # ...and the index says it is ours.
    as_user(client, "mara")
    rows = client.get("/api/projects").json()["projects"]
    mine = next(r for r in rows if r["id"] == iid)
    assert (mine["needs_you"], mine["open_feedback"]) == (True, 1)


def test_resolving_a_screen_conversation_returns_the_turn(client, kit):
    """It shares the pin resolve path — one comment surface, several subjects."""
    iid = make_project(client, kit)
    sid, _oid = add_screen_option(client, iid)
    client.post(f"/api/projects/{iid}/send")
    as_user(client, "cleo")
    tid = client.post(f"/api/screens/{sid}/comments",
                      json={"body_md": "A thought."}).json()["id"]

    as_user(client, "mara")
    assert client.post(f"/api/threads/{tid}/comments",
                       json={"body_md": "Good point — changing it."}).status_code == 200
    assert client.post(f"/api/threads/{tid}/resolve").status_code == 200
    assert client.get(f"/api/projects/{iid}/status").json()["state"] == "waiting_client"


def test_the_screen_payload_reports_its_conversation(client, kit):
    iid = make_project(client, kit)
    sid, _oid = add_screen_option(client, iid)
    as_user(client, "cleo")
    tid = client.post(f"/api/screens/{sid}/comments", json={"body_md": "One."}).json()["id"]
    client.post(f"/api/screens/{sid}/comments", json={"body_md": "Two."})

    screen = client.get(f"/api/projects/{iid}").json()["screens"][0]
    assert (screen["open_comments"], screen["comment_count"]) == (1, 2)

    as_user(client, "mara")
    client.post(f"/api/threads/{tid}/resolve")
    screen = client.get(f"/api/projects/{iid}").json()["screens"][0]
    assert (screen["open_comments"], screen["comment_count"]) == (0, 2)


def test_pins_are_untouched_by_any_of_this(client, kit):
    """Pins remain the primary act; the two signals stay separate."""
    iid = make_project(client, kit)
    sid, oid = add_screen_option(client, iid)
    client.post(f"/api/projects/{iid}/send")
    as_user(client, "cleo")
    pin = client.post(f"/api/options/{oid}/pins", json={
        "x_percent": 40.0, "y_percent": 12.0,
        "body_md": "This bit."}).json()["pin"]
    client.post(f"/api/screens/{sid}/comments", json={"body_md": "The page overall."})

    # Two open pieces of client feedback, of two different kinds.
    assert client.get(f"/api/projects/{iid}/status").json()["counts"]["client_open"] == 2
    assert client.get(f"/api/options/{oid}/pins").json()["pins"][0]["pin_id"] == pin["pin_id"]
    screen = client.get(f"/api/projects/{iid}").json()["screens"][0]
    assert screen["options"][0]["open_pin_count"] == 1
    assert screen["open_comments"] == 1


def test_an_outsider_cannot_read_or_start_one(client, kit):
    iid = make_project(client, kit)
    sid, _oid = add_screen_option(client, iid)
    as_user(client, "nate")
    assert client.get(f"/api/screens/{sid}/thread").status_code == 404
    assert client.post(f"/api/screens/{sid}/comments",
                       json={"body_md": "hi"}).status_code == 404


# ------------------------------------------------------- deleting a comment

def test_a_manager_can_remove_any_comment_on_a_screen(client, kit):
    """Useful while testing, and the API already allowed it — nothing in the UI
    ever called it."""
    iid = make_project(client, kit)
    sid, _oid = add_screen_option(client, iid)
    as_user(client, "cleo")
    client.post(f"/api/screens/{sid}/comments", json={"body_md": "Client note."})
    cid = client.get(f"/api/screens/{sid}/thread").json()["comments"][0]["id"]

    as_user(client, "mara")
    assert client.delete(f"/api/comments/{cid}").status_code == 200
    comment = client.get(f"/api/screens/{sid}/thread").json()["comments"][0]
    # SOFT deleted: the row survives, the reading does not. A conversation is a
    # record and the standard says never hard-delete one.
    assert comment["deleted"] is True
    assert comment["body_md"] == ""


def test_a_thread_with_nothing_left_to_read_stops_counting(client, kit):
    """The bug deleting would otherwise expose: comments are soft-deleted, so a
    thread whose every comment was removed still had resolved=False and went on
    turning the board forever. What is open is the reading, not the row."""
    iid = make_project(client, kit)
    sid, _oid = add_screen_option(client, iid)
    client.post(f"/api/projects/{iid}/send")

    as_user(client, "cleo")
    client.post(f"/api/screens/{sid}/comments", json={"body_md": "A thought."})
    cid = client.get(f"/api/screens/{sid}/thread").json()["comments"][0]["id"]
    assert client.get(f"/api/projects/{iid}/status").json()["state"] == "waiting_agency"

    as_user(client, "mara")
    client.delete(f"/api/comments/{cid}")

    assert client.get(f"/api/projects/{iid}/status").json()["state"] == "waiting_client"
    screen = client.get(f"/api/projects/{iid}").json()["screens"][0]
    assert (screen["open_comments"], screen["comment_count"]) == (0, 0)
    assert client.get(f"/api/projects/{iid}/summary").json()["outstanding"] == []
    rows = client.get("/api/projects").json()["projects"]
    assert next(r for r in rows if r["id"] == iid)["open_feedback"] == 0


def test_a_client_can_remove_their_own_but_not_ours(client, kit):
    iid = make_project(client, kit)
    sid, _oid = add_screen_option(client, iid)
    as_user(client, "mara")
    client.post(f"/api/screens/{sid}/comments", json={"body_md": "Ours."})
    ours = client.get(f"/api/screens/{sid}/thread").json()["comments"][0]["id"]

    as_user(client, "cleo")
    client.post(f"/api/screens/{sid}/comments", json={"body_md": "Theirs."})
    theirs = [c for c in client.get(f"/api/screens/{sid}/thread").json()["comments"]
              if c["author_username"] == "cleo"][0]["id"]

    assert client.delete(f"/api/comments/{theirs}").status_code == 200
    assert client.delete(f"/api/comments/{ours}").status_code == 403
