"""Drive the sticky-notes board end to end and prove `remove_all` clears only on a confirmed elicitation."""

import anyio
import mcp_types as types
from mcp_types.version import HANDSHAKE_PROTOCOL_VERSIONS

from mcp.client import Client, ClientRequestContext
from stories._harness import Target, run_client


async def main(target: Target, *, mode: str = "auto") -> None:
    # Scripted reply for the server's `remove_all` elicitation; rebound between calls below.
    answer = "cancel"
    list_changed = anyio.Event()

    async def on_elicit(context: ClientRequestContext, params: types.ElicitRequestParams) -> types.ElicitResult:
        if answer == "cancel":
            return types.ElicitResult(action="cancel")
        return types.ElicitResult(action="accept", content={"confirm": answer == "confirm"})

    async def on_message(message: object) -> None:
        if isinstance(message, types.ResourceListChangedNotification):
            list_changed.set()

    async with Client(target, mode=mode, elicitation_callback=on_elicit, message_handler=on_message) as client:
        legacy = client.protocol_version in HANDSHAKE_PROTOCOL_VERSIONS

        # Add two notes.
        first = await client.call_tool("add_note", {"text": "Buy milk"})
        assert first.structured_content is not None
        first_id, first_uri = first.structured_content["id"], first.structured_content["uri"]
        assert first_uri.startswith("note:///")
        second = await client.call_tool("add_note", {"text": "Walk the dog"})
        assert second.structured_content is not None
        second_id, second_uri = second.structured_content["id"], second.structured_content["uri"]
        assert first_id != second_id

        # List + read — both notes appear as resources; first reads back its text.
        listed = await client.list_resources()
        uris = {str(r.uri) for r in listed.resources}
        assert first_uri in uris and second_uri in uris, uris
        read = await client.read_resource(first_uri)
        assert isinstance(read.contents[0], types.TextResourceContents)
        assert read.contents[0].text == "Buy milk"

        # list_changed rides the standalone stream — only deliverable on a legacy-era connection.
        if legacy:
            with anyio.fail_after(5):
                await list_changed.wait()

        # Remove one.
        removed = await client.call_tool("remove_note", {"note_id": first_id})
        assert removed.structured_content == {"result": True}
        after = await client.list_resources()
        assert first_uri not in {str(r.uri) for r in after.resources}

        # remove_all uses push-style elicitation: legacy-era only (modern equivalent lands with the mrtr/ story).
        if not legacy:
            gone = await client.call_tool("remove_note", {"note_id": second_id})
            assert gone.structured_content == {"result": True}
            return

        cancelled = await client.call_tool("remove_all", {})
        assert cancelled.structured_content == {"status": "cancelled", "removed": 0}

        answer = "unchecked"
        declined = await client.call_tool("remove_all", {})
        assert declined.structured_content == {"status": "declined", "removed": 0}

        answer = "confirm"
        cleared = await client.call_tool("remove_all", {})
        assert cleared.structured_content == {"status": "cleared", "removed": 1}
        final = await client.list_resources()
        assert not [r for r in final.resources if str(r.uri).startswith("note:///")]

        empty = await client.call_tool("remove_all", {})
        assert empty.structured_content == {"status": "empty", "removed": 0}


if __name__ == "__main__":
    run_client(main)
