"""Resume and hydration (docs/specs/2026-08-10-ask-gpt-resume-live-design.md §2)."""

from __future__ import annotations

import pytest

import ask_gpt
import chat
from fake_browser import seat_for

CID = "44444444-4444-4444-8444-444444444444"


def test_a_bare_uuid_parses_to_itself():
    assert chat.parse_resume_id(f" {CID} ") == CID


def test_a_full_url_parses_to_the_bare_id():
    assert chat.parse_resume_id(f"https://chatgpt.com/c/{CID}") == CID


def test_uppercase_normalises_to_lowercase():
    assert chat.parse_resume_id(CID.upper()) == CID


def test_garbage_is_rejected():
    with pytest.raises(chat.ChatError):
        chat.parse_resume_id("not-a-conversation-id")


def test_a_non_chatgpt_url_is_rejected():
    with pytest.raises(chat.ChatError):
        chat.parse_resume_id("https://example.com/whatever")


def test_open_resume_navigates_and_accepts_a_real_conversation(monkeypatch):
    monkeypatch.setattr(chat.time, "sleep", lambda *_: None)
    _, marionette = seat_for([])
    marionette.turns = 2
    seen_at_auth = []
    real_authenticated_account = chat.authenticated_account

    def authenticated_account(browser):
        seen_at_auth.append(list(browser.navigations))
        return real_authenticated_account(browser)

    monkeypatch.setattr(chat, "authenticated_account", authenticated_account)
    chat.open_resume(marionette, CID, "owner@example.com")
    assert seen_at_auth == [["https://chatgpt.com/"]]
    assert marionette.navigations == ["https://chatgpt.com/", f"https://chatgpt.com/c/{CID}"]


def test_open_resume_on_an_unknown_id_is_not_found(monkeypatch):
    """A foreign id lands on a blank new chat (composer present, no turns) rather
    than an error page, so an empty-conversation landing must be reported, not
    silently treated as success."""
    monkeypatch.setattr(chat.time, "sleep", lambda *_: None)
    _, marionette = seat_for([])
    with pytest.raises(chat.ChatError, match=CID):
        chat.open_resume(marionette, CID, "owner@example.com")


def test_open_resume_rejects_account_mismatch_before_target_navigation(monkeypatch):
    _, marionette = seat_for([])
    marionette.account = "other@example.com"
    with pytest.raises(chat.ChatError, match="expects account owner@example.com; current account other@example.com"):
        chat.open_resume(marionette, CID, "owner@example.com")
    assert marionette.navigations == ["https://chatgpt.com/"]


@pytest.mark.parametrize("redirected_url", [
    f"https://example.com/c/{CID}",
    f"https://chatgpt.com/?next=/c/{CID}",
    f"https://chatgpt.com/c/{CID}/",
])
def test_open_resume_rejects_redirect_with_embedded_expected_id(monkeypatch, redirected_url):
    monkeypatch.setattr(chat.time, "sleep", lambda *_: None)
    _, marionette = seat_for([])
    marionette.turns = 2
    marionette.url = lambda: redirected_url

    with pytest.raises(chat.ChatError, match="not found in this account"):
        chat.open_resume(marionette, CID, "owner@example.com")


def test_cli_unknown_id_fails_before_daemon_or_browser(monkeypatch, capsys):
    monkeypatch.setattr(ask_gpt, "daemon_endpoint", lambda: (_ for _ in ()).throw(AssertionError()))
    assert ask_gpt.main(["--resume", CID, "hello"]) == 1
    assert "not in the local registry" in capsys.readouterr().err


def test_hydrate_dom_reads_every_visible_turn(monkeypatch):
    monkeypatch.setattr(chat.time, "sleep", lambda *_: None)
    _, marionette = seat_for([])
    marionette.hydrate_turns = [
        {"prompt": "first", "answer": "reply one", "thinking": ""},
        {"prompt": "second", "answer": "reply two", "thinking": ""},
    ]
    turns = chat.hydrate_dom(marionette)
    assert [t["prompt"] for t in turns] == ["first", "second"]
