"""Phase B: drafts never take forms or pages offline — visitors get the live
(published) version while the designer edits a draft — plus version history,
restore and discard."""

import uuid


async def test_form_stays_live_while_a_new_version_is_drafted(client, auth_headers):
    form = (await client.post("/forms", headers=auth_headers, json={"name": "Leave", "field_definitions": [{"name": "days", "type": "number", "label": "Days"}]})).json()
    fid = form["form_id"]
    await client.post(f"/forms/{fid}/publish", headers=auth_headers)
    draft = (await client.post(f"/forms/{fid}/new-version", headers=auth_headers)).json()
    assert draft["version"] == 2 and draft["status"] == "draft"
    await client.patch(f"/forms/{fid}", headers=auth_headers, json={"field_definitions": [{"name": "days", "type": "number", "label": "Days"}, {"name": "reason", "type": "text", "label": "Reason"}]})

    live = (await client.get(f"/forms/{fid}/live", headers=auth_headers)).json()
    assert live["version"] == 1 and live["status"] == "published"
    assert [f["name"] for f in live["field_definitions"]] == ["days"]
    assert (await client.get(f"/forms/{fid}", headers=auth_headers)).json()["version"] == 2  # the designer's draft

    # People keep submitting against v1.
    sub = await client.post("/form-submissions", headers=auth_headers, json={"form_id": fid, "form_version": 1, "field_values": {"days": 2}})
    assert sub.status_code == 201

    await client.post(f"/forms/{fid}/publish", headers=auth_headers)
    assert (await client.get(f"/forms/{fid}/live", headers=auth_headers)).json()["version"] == 2


async def test_form_draft_can_be_discarded_and_old_versions_restored(client, auth_headers, test_tenant):
    form = (await client.post("/forms", headers=auth_headers, json={"name": "F", "field_definitions": [{"name": "a", "type": "text", "label": "A"}]})).json()
    fid = form["form_id"]
    # Never published: nothing to fall back to.
    assert (await client.delete(f"/forms/{fid}/draft", headers=auth_headers)).status_code == 409
    await client.post(f"/forms/{fid}/publish", headers=auth_headers)
    await client.post(f"/forms/{fid}/new-version", headers=auth_headers)
    await client.patch(f"/forms/{fid}", headers=auth_headers, json={"field_definitions": [{"name": "b", "type": "text", "label": "B"}]})

    back = await client.delete(f"/forms/{fid}/draft", headers=auth_headers)
    assert back.status_code == 200, back.text
    assert back.json()["version"] == 1 and back.json()["is_current"]
    assert [v["version"] for v in (await client.get(f"/forms/{fid}/versions", headers=auth_headers)).json()] == [1]

    # Restore v1 while v1 is current and published: a new draft v2 with v1's design.
    await client.post(f"/forms/{fid}/new-version", headers=auth_headers)
    await client.patch(f"/forms/{fid}", headers=auth_headers, json={"field_definitions": [{"name": "c", "type": "text", "label": "C"}]})
    await client.post(f"/forms/{fid}/publish", headers=auth_headers)  # v2 live with field c
    restored = (await client.post(f"/forms/{fid}/versions/1/restore", headers=auth_headers)).json()
    assert restored["version"] == 3 and restored["status"] == "draft"
    assert [f["name"] for f in restored["field_definitions"]] == ["a"]
    assert (await client.get(f"/forms/{fid}/live", headers=auth_headers)).json()["version"] == 2
    # Restoring onto an existing draft replaces its content rather than adding versions.
    again = (await client.post(f"/forms/{fid}/versions/2/restore", headers=auth_headers)).json()
    assert again["version"] == 3 and [f["name"] for f in again["field_definitions"]] == ["c"]


async def test_task_writes_new_submissions_against_the_live_version(client, auth_headers):
    form = (await client.post("/forms", headers=auth_headers, json={"name": "Log", "field_definitions": [{"name": "msg", "type": "text", "label": "Msg"}]})).json()
    fid = form["form_id"]
    await client.post(f"/forms/{fid}/publish", headers=auth_headers)
    await client.post(f"/forms/{fid}/new-version", headers=auth_headers)
    task = (await client.post("/tasks", headers=auth_headers, json={"name": "Write", "nodes": [
        {"key": "start", "type": "start", "label": "Start", "next_nodes": [{"to": "write"}]},
        {"key": "write", "type": "data_update", "label": "Write", "datasource_type": "form", "form_id": fid,
         "input_params": [{"name": "msg", "type": "string", "value": "hello"}]},
    ]})).json()
    result = (await client.post(f"/tasks/{task['id']}/run", headers=auth_headers, json={"context": {}, "allow_draft": True})).json()
    assert result["ok"], result["trace"]
    rows = (await client.get(f"/forms/{fid}/submissions", headers=auth_headers)).json()
    assert [r["form_version"] for r in rows] == [1]


async def test_page_publish_keeps_visitors_on_the_published_version(client, auth_headers):
    page = (await client.post("/pages", headers=auth_headers, json={"name": "Home", "blocks": [{"id": "t1", "type": "text", "text": "Hello"}]})).json()
    pid = page["id"]
    assert page["published_version"] is None and not page["has_unpublished_changes"]
    # Never published: the working copy is what shows.
    assert (await client.get(f"/pages/{pid}/live", headers=auth_headers)).json()["blocks"][0]["text"] == "Hello"

    published = (await client.post(f"/pages/{pid}/publish", headers=auth_headers, json={"note": "first"})).json()
    assert published["published_version"] == 1 and not published["has_unpublished_changes"]

    edited = (await client.patch(f"/pages/{pid}", headers=auth_headers, json={"blocks": [{"id": "t1", "type": "text", "text": "Hello v2"}]})).json()
    assert edited["has_unpublished_changes"]
    live = (await client.get(f"/pages/{pid}/live", headers=auth_headers)).json()
    assert live["blocks"][0]["text"] == "Hello" and live["status"] == "published"

    await client.post(f"/pages/{pid}/publish", headers=auth_headers)
    assert (await client.get(f"/pages/{pid}/live", headers=auth_headers)).json()["blocks"][0]["text"] == "Hello v2"

    versions = (await client.get(f"/pages/{pid}/versions", headers=auth_headers)).json()
    assert [v["version"] for v in versions] == [2, 1]
    assert versions[1]["note"] == "first" and versions[1]["published_by_name"] == "Pytest Admin"


async def test_page_restore_and_discard_only_touch_the_working_copy(client, auth_headers):
    pid = (await client.post("/pages", headers=auth_headers, json={"name": "P", "blocks": [{"id": "a", "type": "text", "text": "one"}]})).json()["id"]
    await client.post(f"/pages/{pid}/publish", headers=auth_headers)
    await client.patch(f"/pages/{pid}", headers=auth_headers, json={"blocks": [{"id": "a", "type": "text", "text": "two"}]})
    await client.post(f"/pages/{pid}/publish", headers=auth_headers)

    restored = (await client.post(f"/pages/{pid}/versions/1/restore", headers=auth_headers)).json()
    assert restored["blocks"][0]["text"] == "one" and restored["has_unpublished_changes"]
    assert (await client.get(f"/pages/{pid}/live", headers=auth_headers)).json()["blocks"][0]["text"] == "two"

    discarded = (await client.post(f"/pages/{pid}/discard", headers=auth_headers)).json()
    assert discarded["blocks"][0]["text"] == "two" and not discarded["has_unpublished_changes"]
    assert (await client.post(f"/pages/{uuid.uuid4()}/discard", headers=auth_headers)).status_code == 404
