"""Regression coverage for #2472 fork-from-here on messaging sessions."""

from __future__ import annotations

from pathlib import Path
from types import SimpleNamespace

import api.routes as routes

REPO = Path(__file__).resolve().parents[1]
COMMANDS_JS = (REPO / "static" / "commands.js").read_text(encoding="utf-8")
ROUTES_PY = (REPO / "api" / "routes.py").read_text(encoding="utf-8")


def _function_body(src: str, name: str) -> str:
    start = src.index(f"async function {name}")
    brace = src.index("{", start)
    depth = 0
    for i in range(brace, len(src)):
        if src[i] == "{":
            depth += 1
        elif src[i] == "}":
            depth -= 1
            if depth == 0:
                return src[start : i + 1]
    raise AssertionError(f"function {name!r} body not found")


def test_messaging_merge_helper_matches_session_get_coordinate_space():
    session = SimpleNamespace(
        messages=[
            {"role": "user", "content": "sidecar only", "timestamp": 2},
            {"role": "assistant", "content": "shared", "timestamp": 3},
        ]
    )
    cli_messages = [
        {"role": "user", "content": "cli earlier", "timestamp": 1},
        {"role": "assistant", "content": "shared", "timestamp": 3},
        {"role": "assistant", "content": "cli later", "timestamp": 4},
    ]

    merged = routes._merged_session_messages_for_display(session, cli_messages)

    assert [m["content"] for m in merged] == [
        "cli earlier",
        "sidecar only",
        "shared",
        "cli later",
    ]


def test_messaging_merge_helper_dedupes_equivalent_timestamp_formats():
    session = SimpleNamespace(
        messages=[
            {"role": "user", "content": "hi", "timestamp": "10.0"},
            {"role": "assistant", "content": "same answer", "timestamp": "11.000000"},
        ]
    )
    cli_messages = [
        {"role": "user", "content": "hi", "timestamp": 10},
        {"role": "assistant", "content": "same answer", "timestamp": 11},
    ]

    merged = routes._merged_session_messages_for_display(session, cli_messages)

    assert [m["content"] for m in merged] == ["hi", "same answer"]


def test_messaging_merge_preserves_longer_sidecar_order_when_timestamps_collapse():
    """A repaired messaging sidecar can preserve order but lose subsecond timestamps.

    Re-sorting those messages by ``(timestamp, role, content)`` groups assistant
    and tool rows before user rows, making the WebUI look like replies vanished.
    """
    session = SimpleNamespace(
        messages=[
            {"role": "assistant", "content": "prior answer", "timestamp": 100.0},
            {"role": "user", "content": "first prompt", "timestamp": 101.0},
            {"role": "assistant", "content": "first answer", "timestamp": 101.0},
            {"role": "user", "content": "second prompt", "timestamp": 101.0},
            {"role": "assistant", "content": "second answer", "timestamp": 101.0},
        ]
    )
    cli_messages = [
        {"role": "user", "content": "first prompt", "timestamp": 101.1},
        {"role": "assistant", "content": "first answer", "timestamp": 101.2},
        {"role": "user", "content": "second prompt", "timestamp": 101.3},
        {"role": "assistant", "content": "second answer", "timestamp": 101.4},
    ]

    merged = routes._merged_session_messages_for_display(session, cli_messages)

    assert [m["content"] for m in merged] == [
        "prior answer",
        "first prompt",
        "first answer",
        "second prompt",
        "second answer",
    ]


def test_branch_handler_uses_merged_messaging_messages_for_keep_count():
    branch_idx = ROUTES_PY.index('parsed.path == "/api/session/branch":')
    block = ROUTES_PY[branch_idx : branch_idx + 2600]

    assert "_merged_session_messages_for_display(source, cli_messages)" in block
    assert "get_cli_session_messages(source.session_id)" in block
    assert "source_messages = source.messages or []" not in block


def test_branch_handler_best_effort_saves_source_before_fork_slice():
    branch_idx = ROUTES_PY.index('parsed.path == "/api/session/branch":')
    block = ROUTES_PY[branch_idx : branch_idx + 2600]

    assert "source.save()" in block
    assert block.index("source.save()") < block.index("source_messages =")


def test_fork_from_message_snapshots_session_id_across_async_load():
    body = _function_body(COMMANDS_JS, "forkFromMessage")

    assert "const initialSid = S.session.session_id;" in body
    assert "S.session.session_id !== initialSid" in body
    assert "session_id:initialSid" in body
    assert "session_id:S.session.session_id" not in body


def test_fork_loads_full_fork_transcript_after_branch():
    body = _function_body(COMMANDS_JS, "forkFromMessage")

    load_idx = body.index("await loadSession(data.session_id)")
    after_load = body[load_idx:]
    assert "await _ensureAllMessagesLoaded()" in after_load
