from __future__ import annotations

import copy
import hashlib
import json
import struct
import zlib
from pathlib import Path

import pytest

from scripts import build_telegram_visible_unseen_chain_packet as packet_builder
from scripts import collect_telegram_visible_unseen_chain_state as state_collector
from scripts import verify_telegram_visible_unseen_chain as verifier

SUBJECT_ID = "c0000000-0000-4000-8000-000000000001"
CHALLENGE_NONCE = "a" * 64
TURN_CAPTURE_CALL_IDS = ["call_chrome_turn_1", "call_chrome_turn_2", "call_chrome_turn_3"]
FINAL_CAPTURE_CALL_ID = "call_chrome_final"


def packet_and_path(tmp_path: Path) -> tuple[dict, Path]:
    packet = packet_builder.build_packet(
        handler_receipt_path=packet_builder.DEFAULT_HANDLER_RECEIPT.resolve(),
        git_sha="a" * 40,
    )
    path = tmp_path / "packet.json"
    packet_builder.write_json(path, packet)
    return packet, path


def _finish_state_token(value: dict) -> dict:
    value["state_token_sha256"] = state_collector.derive_state_token(value)
    return value


def preflight(packet: dict, packet_path: Path) -> dict:
    return _finish_state_token(
        {
            "schema": state_collector.SCHEMA,
            "generated_at_utc": "2026-07-14T23:59:00+00:00",
            "phase": "preflight",
            "status": "pass",
            "protocol_sha256": packet["protocol_sha256"],
            "packet_file_sha256": verifier._sha256_file(packet_path),
            "manifest_binding": packet["manifest_binding"],
            "capture_challenge_nonce": CHALLENGE_NONCE,
            "baseline_state_token_sha256": "",
            "subject_ref": "",
            "packet_checks": {"fixture_packet_checks_pass": True},
            "remote_checks": {"fixture_remote_checks_pass": True},
            "baseline_checks": {},
            "remote": {
                "deploy_head": "d" * 40,
                "last_deploy_sha": "d" * 40,
                "fingerprint_after": {"fingerprint_sha256": "f" * 64},
                "service_after": {
                    "MainPID": "123",
                    "NRestarts": "0",
                    "ExecMainStartTimestamp": "Wed 2026-07-15 00:00:00 UTC",
                },
                "subject_readback": None,
            },
        }
    )


def postflight(packet: dict, packet_path: Path, before: dict) -> dict:
    return _finish_state_token(
        {
            "schema": state_collector.SCHEMA,
            "generated_at_utc": "2026-07-15T00:04:00Z",
            "phase": "postflight",
            "status": "pass",
            "protocol_sha256": packet["protocol_sha256"],
            "packet_file_sha256": verifier._sha256_file(packet_path),
            "manifest_binding": packet["manifest_binding"],
            "capture_challenge_nonce": CHALLENGE_NONCE,
            "baseline_state_token_sha256": before["state_token_sha256"],
            "subject_ref": "c0000000",
            "packet_checks": {"fixture_packet_checks_pass": True},
            "remote_checks": {"fixture_remote_checks_pass": True},
            "baseline_checks": {"fixture_baseline_checks_pass": True},
            "remote": {
                "deploy_head": "d" * 40,
                "last_deploy_sha": "d" * 40,
                "fingerprint_after": {"fingerprint_sha256": "f" * 64},
                "service_after": {
                    "MainPID": "123",
                    "NRestarts": "0",
                    "ExecMainStartTimestamp": "Wed 2026-07-15 00:00:00 UTC",
                },
                "subject_readback": {
                    "subject_ref": "c0000000",
                    "matches": [
                        {
                            "table": "public.beliefs",
                            "row": {"id": SUBJECT_ID, "statement": "Coordination is the bottleneck."},
                        }
                    ],
                },
            },
        }
    )


def write_png(path: Path, rgba: tuple[int, int, int, int]) -> None:
    width = verifier.MIN_SCREENSHOT_WIDTH
    height = verifier.MIN_SCREENSHOT_HEIGHT
    scanline = b"\x00" + bytes(rgba) * width
    pixels = scanline * height

    def chunk(kind: bytes, payload: bytes) -> bytes:
        return (
            struct.pack(">I", len(payload))
            + kind
            + payload
            + struct.pack(">I", zlib.crc32(kind + payload) & 0xFFFFFFFF)
        )

    ihdr = struct.pack(">IIBBBBB", width, height, 8, 6, 0, 0, 0)
    path.write_bytes(
        b"\x89PNG\r\n\x1a\n" + chunk(b"IHDR", ihdr) + chunk(b"IDAT", zlib.compress(pixels)) + chunk(b"IEND", b"")
    )


def _artifact_hashes(capture: dict) -> dict:
    source = capture["capture_source"]
    return {
        "final_screenshot": verifier._sha256_file(Path(source["final_screenshot"])),
        "final_accessibility": verifier._sha256_file(Path(source["final_accessibility"])),
        "turn_screenshots": [verifier._sha256_file(Path(item["turn_screenshot"])) for item in capture["messages"]],
        "turn_accessibility": [verifier._sha256_file(Path(item["turn_accessibility"])) for item in capture["messages"]],
    }


def authorization_event(packet: dict, capture: dict) -> dict:
    return {
        "timestamp": capture["operator_authorization_captured_at_utc"],
        "type": "response_item",
        "payload": {
            "type": "message",
            "role": "user",
            "content": [{"type": "input_text", "text": capture["operator_authorization_text"]}],
            "internal_chat_message_metadata_passthrough": {"turn_id": "user-message-20260715-authorization"},
        },
    }


def write_browser_provenance(packet: dict, capture: dict, path: Path) -> str:
    source = capture["capture_source"]
    auth_event = authorization_event(packet, capture)
    auth_event_sha256 = hashlib.sha256(
        json.dumps(auth_event, sort_keys=True, separators=(",", ":")).encode("utf-8")
    ).hexdigest()
    final_call_id = TURN_CAPTURE_CALL_IDS[2] if source["final_capture_reuses_turn_3"] else FINAL_CAPTURE_CALL_ID
    provenance = {
        "schema": verifier.BROWSER_PROVENANCE_SCHEMA,
        "status": "pass",
        "capture_channel": "codex_chrome_extension",
        "capture_challenge_nonce": CHALLENGE_NONCE,
        "protocol_sha256": packet["protocol_sha256"],
        "turn_capture_call_ids": TURN_CAPTURE_CALL_IDS,
        "final_capture_call_id": final_call_id,
        "browser": {
            "browser_type": "extension",
            "browser_id": "chrome-backend-20260715",
            "session_id": "chrome-session-20260715",
            "tab_id": "telegram-tab-20260715",
            "provider_capture_id": "chrome-capture-20260715",
            "page_url": "https://web.telegram.org/k/#-5146042086",
            "page_title": "Leo - Telegram",
            "captured_at_utc": source["captured_at_utc"],
        },
        "authorization": {
            "source": "codex_platform_user_message",
            "thread_id": packet["operator_context"]["codex_thread_id"],
            "user_message_id": "user-message-20260715-authorization",
            "source_receipt_id": auth_event_sha256,
            "text_sha256": hashlib.sha256(capture["operator_authorization_text"].encode("utf-8")).hexdigest(),
            "captured_at_utc": capture["operator_authorization_captured_at_utc"],
        },
        "telegram": {
            "chat_label": "Leo",
            "chat_id": "-5146042086",
            "message_ids": [item["telegram_message_id"] for item in capture["messages"]],
            "reply_ids": [item["reply_message_id"] for item in capture["messages"]],
        },
        "artifacts": _artifact_hashes(capture),
        "checks": {
            "authenticated_chrome_extension_session": True,
            "telegram_web_origin_observed": True,
            "chat_identity_observed_in_browser": True,
            "message_ids_observed_in_browser": True,
            "accessibility_captured_from_browser": True,
            "screenshots_captured_from_browser": True,
            "authorization_read_from_codex_user_message": True,
        },
    }
    path.write_text(json.dumps(provenance, indent=2, sort_keys=True) + "\n", encoding="utf-8")
    return verifier._sha256_file(path)


def write_codex_rollout(packet: dict, capture: dict, tmp_path: Path, provenance_sha256: str) -> Path:
    provenance_path = Path(capture["capture_source"]["browser_provenance"])
    provenance = json.loads(provenance_path.read_text(encoding="utf-8"))
    browser = provenance["browser"]
    artifacts = provenance["artifacts"]
    thread_id = packet["operator_context"]["codex_thread_id"]
    sessions_root = tmp_path.parent / f"{tmp_path.name}-codex-sessions"
    rollout_dir = sessions_root / "2026" / "07" / "15"
    rollout_dir.mkdir(parents=True, exist_ok=True)
    rollout_path = rollout_dir / f"rollout-2026-07-15T00-00-00-{thread_id}.jsonl"
    events = [
        {
            "timestamp": "2026-07-14T23:58:00Z",
            "type": "session_meta",
            "payload": {"id": thread_id},
        },
        authorization_event(packet, capture),
    ]

    def chrome_event(call_id: str, timestamp: str, values: list[str]) -> dict:
        return {
            "timestamp": timestamp,
            "type": "event_msg",
            "payload": {
                "type": "mcp_tool_call_end",
                "call_id": call_id,
                "invocation": {
                    "server": "node_repl",
                    "tool": "js",
                    "arguments": {
                        "code": (
                            "await tab.screenshot({fullPage:false}); "
                            "await tab.playwright.domSnapshot(); await tab.url(); await tab.title();"
                        )
                    },
                },
                "result": {
                    "Ok": {
                        "content": [{"type": "text", "text": json.dumps(values)}],
                        "isError": False,
                        "_meta": {
                            "codex/toolSurface": {
                                "backend": "chrome",
                                "browserId": browser["browser_id"],
                                "kind": "browserUse",
                                "openTabIds": [browser["tab_id"]],
                            }
                        },
                    }
                },
            },
        }

    turn_timestamps = ["2026-07-15T00:01:30Z", "2026-07-15T00:02:30Z", "2026-07-15T00:03:30Z"]
    for index, (call_id, timestamp, message) in enumerate(
        zip(TURN_CAPTURE_CALL_IDS, turn_timestamps, capture["messages"], strict=True)
    ):
        values = [
            artifacts["turn_screenshots"][index],
            artifacts["turn_accessibility"][index],
            message["telegram_message_id"],
            message["reply_message_id"],
            browser["page_url"],
            browser["page_title"],
            packet["target"]["chat_id"],
        ]
        if provenance["final_capture_call_id"] == call_id:
            values.extend(
                [
                    artifacts["final_screenshot"],
                    artifacts["final_accessibility"],
                    provenance_sha256,
                    *[item["telegram_message_id"] for item in capture["messages"]],
                    *[item["reply_message_id"] for item in capture["messages"]],
                ]
            )
            timestamp = capture["capture_source"]["captured_at_utc"]
        events.append(chrome_event(call_id, timestamp, values))
    if provenance["final_capture_call_id"] == FINAL_CAPTURE_CALL_ID:
        events.append(
            chrome_event(
                FINAL_CAPTURE_CALL_ID,
                capture["capture_source"]["captured_at_utc"],
                [
                    artifacts["final_screenshot"],
                    artifacts["final_accessibility"],
                    provenance_sha256,
                    *[item["telegram_message_id"] for item in capture["messages"]],
                    *[item["reply_message_id"] for item in capture["messages"]],
                ],
            )
        )
    rollout_path.write_text(
        "".join(json.dumps(event, sort_keys=True) + "\n" for event in events),
        encoding="utf-8",
    )
    return rollout_path


def refresh_provenance_and_rollout(packet: dict, capture: dict, tmp_path: Path) -> Path:
    provenance_path = Path(capture["capture_source"]["browser_provenance"])
    provenance_sha256 = write_browser_provenance(packet, capture, provenance_path)
    return write_codex_rollout(packet, capture, tmp_path, provenance_sha256)


def good_capture(packet: dict, tmp_path: Path) -> tuple[dict, Path]:
    screenshot = tmp_path / "final.png"
    accessibility = tmp_path / "final.txt"
    write_png(screenshot, (10, 20, 30, 255))
    accessibility.write_text("telegram final accessibility proof", encoding="utf-8")
    replies = [
        (
            "The database public.beliefs object c0000000 is an axiom with confidence 0.85. What supports it in "
            "the DB: nothing supports it; there are zero evidence rows and no external primary source."
        ),
        (
            "Claim c0000000 is still the coordination bottleneck belief. Assumption versus observed support: the "
            "priority leap is assumed and the evidence is absent. Falsifier: a contrary case. Proposal A and "
            "Proposal B are staged only for review; nothing applied and neither is live knowledge."
        ),
        (
            "Revised proposal: separate the mechanism from the business outcome. What would resolve the "
            "disagreement: a randomized study and its primary source dataset. Keep it pending_review for human "
            "review; approved is not apply and applied_at remains null. This is not an apply."
        ),
    ]
    colors = [(40, 50, 60, 255), (70, 80, 90, 255), (100, 110, 120, 255)]
    messages = []
    for item, reply, color in zip(packet["exact_messages"], replies, colors, strict=True):
        sequence = item["sequence"]
        turn_screenshot = tmp_path / f"turn-{sequence}.png"
        turn_accessibility = tmp_path / f"turn-{sequence}.txt"
        write_png(turn_screenshot, color)
        turn_accessibility.write_text(
            f"Telegram message: {item['message']}\nLeo reply: {reply}\n",
            encoding="utf-8",
        )
        messages.append(
            {
                "sequence": sequence,
                "prompt_id": item["prompt_id"],
                "sent_text": item["message"],
                "reply": reply,
                "sent_at_utc": f"2026-07-15T00:0{sequence}:00Z",
                "reply_at_utc": f"2026-07-15T00:0{sequence}:20Z",
                "telegram_message_id": f"sent-{sequence}",
                "reply_message_id": f"reply-{sequence}",
                "turn_screenshot": str(turn_screenshot),
                "turn_accessibility": str(turn_accessibility),
            }
        )
    provenance_path = tmp_path / "browser-provenance.json"
    capture = {
        "schema": verifier.CAPTURE_SCHEMA,
        "protocol_sha256": packet["protocol_sha256"],
        "preflight_state_token_sha256": "",
        "operator_authorization_text": packet["explicit_operator_authorization_text"],
        "operator_authorization_captured_at_utc": "2026-07-15T00:00:00Z",
        "extra_messages_sent": 0,
        "capture_source": {
            "platform": "telegram",
            "transport": "authenticated_chrome_telegram_ui",
            "chat_label": "Leo",
            "chat_id": "-5146042086",
            "captured_at_utc": "2026-07-15T00:03:40Z",
            "captured_by": "codex_chrome_extension",
            "final_screenshot": str(screenshot),
            "final_accessibility": str(accessibility),
            "browser_provenance": str(provenance_path),
            "final_capture_reuses_turn_3": False,
            "final_capture_reuse_reason": "",
        },
        "messages": messages,
    }
    rollout_path = refresh_provenance_and_rollout(packet, capture, tmp_path)
    return capture, rollout_path


def verified_fixture(tmp_path: Path) -> tuple[dict, Path, dict, dict, dict, Path]:
    packet, packet_path = packet_and_path(tmp_path)
    before = preflight(packet, packet_path)
    after = postflight(packet, packet_path, before)
    capture, rollout = good_capture(packet, tmp_path)
    capture["preflight_state_token_sha256"] = before["state_token_sha256"]
    return packet, packet_path, before, after, capture, rollout


def run_verifier(
    packet: dict,
    packet_path: Path,
    before: dict,
    after: dict,
    capture: dict,
    rollout_log: Path | None,
    tmp_path: Path,
) -> dict:
    return verifier.verify_capture(
        packet,
        before,
        capture,
        after,
        packet_path=packet_path,
        evidence_root=tmp_path,
        codex_rollout_log=rollout_log,
        codex_sessions_root=(
            rollout_log.parents[3] if rollout_log is not None else tmp_path.parent / f"{tmp_path.name}-codex-sessions"
        ),
    )


def test_no_capture_returns_awaiting_authorization_template(tmp_path: Path) -> None:
    packet, packet_path = packet_and_path(tmp_path)
    before = preflight(packet, packet_path)

    receipt = verifier.verify_capture(
        packet,
        before,
        None,
        None,
        packet_path=packet_path,
        evidence_root=tmp_path,
    )

    assert receipt["status"] == "awaiting_action_time_authorization"
    assert receipt["preparation_ready"] is True
    assert receipt["receipt_ready"] is False
    assert receipt["current_tier"] == verifier.PREPARATION_TIER
    assert receipt["telegram_visible_messages_sent"] is False
    assert receipt["live_receipt_boundary"]["accepted_by_this_api"] is False
    assert receipt["live_receipt_boundary"]["verified"] is False
    assert receipt["capture_template"]["schema"] == verifier.CAPTURE_SCHEMA
    assert receipt["capture_template"]["messages"][0]["prompt_id"] == "OOS-CHAIN-01"


def test_public_verifier_keeps_fully_well_formed_all_local_forgery_preparation_only(
    tmp_path: Path,
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    _packet, packet_path, before, after, capture, rollout = verified_fixture(tmp_path)
    preflight_path = tmp_path / "preflight.json"
    capture_path = tmp_path / "capture.json"
    postflight_path = tmp_path / "postflight.json"
    out_path = tmp_path / "receipt.json"
    markdown_path = tmp_path / "receipt.md"
    verifier.write_json(preflight_path, before)
    verifier.write_json(capture_path, capture)
    verifier.write_json(postflight_path, after)
    monkeypatch.setattr(verifier, "DEFAULT_CODEX_SESSIONS_ROOT", rollout.parents[3])

    exit_code = verifier.main(
        [
            "--packet",
            str(packet_path),
            "--preflight",
            str(preflight_path),
            "--capture-json",
            str(capture_path),
            "--postflight",
            str(postflight_path),
            "--evidence-root",
            str(tmp_path),
            "--codex-rollout-log",
            str(rollout),
            "--out",
            str(out_path),
            "--markdown-out",
            str(markdown_path),
        ]
    )
    receipt = json.loads(out_path.read_text(encoding="utf-8"))

    assert exit_code == 0
    assert receipt["status"] == verifier.PREPARATION_STATUS
    assert receipt["verification_scope"] == "caller_writable_preparation_structure"
    assert receipt["preparation_ready"] is True
    assert receipt["receipt_ready"] is False
    assert receipt["current_tier"] == verifier.PREPARATION_TIER
    assert receipt["telegram_visible_messages_sent"] is False
    assert receipt["live_receipt_boundary"] == {
        "accepted_by_this_api": False,
        "authority": "independently_authenticated_platform_browser_receipt",
        "local_inputs_are": "caller_writable_preparation_evidence",
        "required": True,
        "verified": False,
    }
    assert all(receipt["checks"].values())
    assert all(receipt["preparation_outcomes"].values())
    assert receipt["selected_subject"]["row_id"] == SUBJECT_ID
    assert "T3_live_readonly" not in receipt["current_tier"]
    assert "caller-writable preparation evidence only" in markdown_path.read_text(encoding="utf-8")


def test_self_declared_browser_provenance_without_codex_rollout_cannot_pass_t3(
    tmp_path: Path,
) -> None:
    packet, packet_path, before, after, capture, _rollout = verified_fixture(tmp_path)

    receipt = run_verifier(packet, packet_path, before, after, capture, None, tmp_path)

    assert receipt["status"] == "fail"
    assert receipt["telegram_visible_messages_sent"] is False
    assert receipt["checks"]["codex_rollout_log_has_expected_local_sessions_shape"] is False
    assert receipt["checks"]["codex_rollout_capture_events_are_chrome_backend"] is False


def test_non_chrome_rollout_capture_events_are_rejected(tmp_path: Path) -> None:
    packet, packet_path, before, after, capture, rollout = verified_fixture(tmp_path)
    events = [json.loads(line) for line in rollout.read_text(encoding="utf-8").splitlines()]
    for event in events:
        payload = event.get("payload") or {}
        if payload.get("type") == "mcp_tool_call_end":
            payload["result"]["Ok"]["_meta"]["codex/toolSurface"]["backend"] = "computerUse"
    rollout.write_text(
        "".join(json.dumps(event, sort_keys=True) + "\n" for event in events),
        encoding="utf-8",
    )

    receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path)

    assert receipt["status"] == "fail"
    assert receipt["checks"]["codex_rollout_capture_events_are_chrome_backend"] is False


def test_bot_api_capture_is_rejected(tmp_path: Path) -> None:
    packet, packet_path, before, after, capture, rollout = verified_fixture(tmp_path)
    capture["capture_source"]["transport"] = "telegram_bot_api"

    receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path)

    assert receipt["status"] == "fail"
    assert receipt["checks"]["authenticated_chrome_transport_declared"] is False
    assert receipt["checks"]["bot_api_not_substituted"] is False


def test_postflight_fingerprint_drift_is_rejected(tmp_path: Path) -> None:
    packet, packet_path, before, after, capture, rollout = verified_fixture(tmp_path)
    after["remote"]["fingerprint_after"]["fingerprint_sha256"] = "0" * 64

    receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path)

    assert receipt["status"] == "fail"
    assert receipt["checks"]["postflight_state_token_derivation_valid"] is False
    assert receipt["checks"]["canonical_fingerprint_unchanged_from_preflight"] is False


def test_message_text_drift_is_rejected(tmp_path: Path) -> None:
    packet, packet_path, before, after, capture, rollout = verified_fixture(tmp_path)
    capture["messages"][1]["sent_text"] += " extra"

    receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path)

    assert receipt["status"] == "fail"
    assert receipt["checks"]["sent_text_exact"] is False


def test_sent_and_reply_message_id_reuse_is_rejected(tmp_path: Path) -> None:
    packet, packet_path, before, after, capture, _rollout = verified_fixture(tmp_path)
    capture["messages"][0]["reply_message_id"] = capture["messages"][0]["telegram_message_id"]
    rollout = refresh_provenance_and_rollout(packet, capture, tmp_path)

    receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path)

    assert receipt["status"] == "fail"
    assert receipt["checks"]["message_and_reply_ids_present_unique"] is False


def test_copied_reply_not_present_in_accessibility_is_rejected(tmp_path: Path) -> None:
    packet, packet_path, before, after, capture, rollout = verified_fixture(tmp_path)
    capture["messages"][0]["reply"] += " copied-only suffix"

    receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path)

    assert receipt["status"] == "fail"
    assert receipt["checks"]["turn_accessibility_binds_exact_messages_and_replies"] is False


def test_all_prompts_sent_before_replies_is_rejected(tmp_path: Path) -> None:
    packet, packet_path, before, after, capture, rollout = verified_fixture(tmp_path)
    capture["messages"][0]["reply_at_utc"] = "2026-07-15T00:02:30Z"

    receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path)

    assert receipt["status"] == "fail"
    assert receipt["checks"]["strict_send_reply_turn_order"] is False


def test_after_the_fact_authorization_is_rejected(tmp_path: Path) -> None:
    packet, packet_path, before, after, capture, _rollout = verified_fixture(tmp_path)
    capture["operator_authorization_captured_at_utc"] = "2026-07-15T00:01:10Z"
    rollout = refresh_provenance_and_rollout(packet, capture, tmp_path)

    receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path)

    assert receipt["status"] == "fail"
    assert receipt["checks"]["captured_authorization_before_first_send"] is False


@pytest.mark.parametrize("timestamp", ["2026-07-15T00:01:00", "not-a-timestamp"])
def test_naive_or_malformed_timestamps_are_rejected(tmp_path: Path, timestamp: str) -> None:
    packet, packet_path, before, after, capture, rollout = verified_fixture(tmp_path)
    capture["messages"][0]["sent_at_utc"] = timestamp

    receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path)

    assert receipt["status"] == "fail"
    assert receipt["checks"]["timestamps_valid_and_timezone_aware"] is False


def test_reused_per_turn_evidence_is_rejected(tmp_path: Path) -> None:
    packet, packet_path, before, after, capture, _rollout = verified_fixture(tmp_path)
    capture["messages"][1]["turn_screenshot"] = capture["messages"][0]["turn_screenshot"]
    capture["messages"][1]["turn_accessibility"] = capture["messages"][0]["turn_accessibility"]
    rollout = refresh_provenance_and_rollout(packet, capture, tmp_path)

    receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path)

    assert receipt["status"] == "fail"
    assert receipt["checks"]["per_turn_screenshot_hashes_distinct_nonempty"] is False
    assert receipt["checks"]["per_turn_accessibility_hashes_distinct_nonempty"] is False


def test_final_capture_may_reuse_turn_three_when_documented(tmp_path: Path) -> None:
    packet, packet_path, before, after, capture, _rollout = verified_fixture(tmp_path)
    capture["capture_source"]["final_screenshot"] = capture["messages"][2]["turn_screenshot"]
    capture["capture_source"]["final_accessibility"] = capture["messages"][2]["turn_accessibility"]
    capture["capture_source"]["final_capture_reuses_turn_3"] = True
    capture["capture_source"]["final_capture_reuse_reason"] = (
        "The final Chrome capture is the retained third-turn response state."
    )
    rollout = refresh_provenance_and_rollout(packet, capture, tmp_path)

    receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path)

    assert receipt["status"] == verifier.PREPARATION_STATUS
    assert receipt["preparation_ready"] is True
    assert receipt["receipt_ready"] is False
    assert receipt["telegram_visible_messages_sent"] is False
    assert receipt["checks"]["final_capture_reuse_policy_satisfied"] is True


def test_undocumented_final_turn_three_reuse_is_rejected(tmp_path: Path) -> None:
    packet, packet_path, before, after, capture, _rollout = verified_fixture(tmp_path)
    capture["capture_source"]["final_screenshot"] = capture["messages"][2]["turn_screenshot"]
    rollout = refresh_provenance_and_rollout(packet, capture, tmp_path)

    receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path)

    assert receipt["status"] == "fail"
    assert receipt["checks"]["final_capture_reuse_policy_satisfied"] is False


def test_evidence_path_escape_is_rejected(tmp_path: Path) -> None:
    packet, packet_path, before, after, capture, rollout = verified_fixture(tmp_path)
    outside = tmp_path.parent / "outside-turn.png"
    write_png(outside, (1, 2, 3, 255))
    capture["messages"][0]["turn_screenshot"] = str(outside)

    receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path)

    assert receipt["status"] == "fail"
    assert receipt["checks"]["all_evidence_paths_contained_in_root"] is False


def test_non_png_screenshot_is_rejected(tmp_path: Path) -> None:
    packet, packet_path, before, after, capture, _rollout = verified_fixture(tmp_path)
    Path(capture["messages"][0]["turn_screenshot"]).write_bytes(b"not a png")
    rollout = refresh_provenance_and_rollout(packet, capture, tmp_path)

    receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path)

    assert receipt["status"] == "fail"
    assert receipt["checks"]["screenshots_are_valid_png_with_metadata"] is False


def test_malformed_local_bundle_without_supported_state_or_rollout_structure_fails(
    tmp_path: Path,
) -> None:
    packet, packet_path = packet_and_path(tmp_path)
    before = {
        "phase": "preflight",
        "status": "pass",
        "generated_at_utc": "2026-07-14T23:59:00Z",
        "protocol_sha256": packet["protocol_sha256"],
        "packet_file_sha256": verifier._sha256_file(packet_path),
        "state_token_sha256": "1" * 64,
        "remote": {"fingerprint_after": {"fingerprint_sha256": "f" * 64}, "service_after": {}},
    }
    after = {
        "phase": "postflight",
        "status": "pass",
        "generated_at_utc": "2026-07-15T00:04:00Z",
        "protocol_sha256": packet["protocol_sha256"],
        "state_token_sha256": "2" * 64,
        "subject_ref": "c0000000",
        "remote": {
            "fingerprint_after": {"fingerprint_sha256": "f" * 64},
            "service_after": {},
            "subject_readback": {"subject_ref": "c0000000", "matches": []},
        },
    }
    fake_png = tmp_path / "fake.png"
    fake_text = tmp_path / "fake.txt"
    fake_png.write_bytes(b"arbitrary non-PNG bytes")
    fake_text.write_text("copied prompts and replies", encoding="utf-8")
    capture = {
        "protocol_sha256": packet["protocol_sha256"],
        "preflight_state_token_sha256": "1" * 64,
        "operator_authorization_text": packet["explicit_operator_authorization_text"],
        "operator_authorization_captured_at_utc": "2026-07-15T00:00:00Z",
        "extra_messages_sent": 0,
        "capture_source": {
            "platform": "telegram",
            "transport": "authenticated_chrome_telegram_ui",
            "chat_label": "Leo",
            "chat_id": "-5146042086",
            "captured_at_utc": "2026-07-15T00:03:40Z",
            "captured_by": "fabricated",
            "final_screenshot": str(fake_png),
            "final_accessibility": str(fake_text),
            "browser_provenance": "",
            "final_capture_reuses_turn_3": False,
            "final_capture_reuse_reason": "",
        },
        "messages": [
            {
                "sequence": item["sequence"],
                "prompt_id": item["prompt_id"],
                "sent_text": item["message"],
                "reply": f"fabricated reply {item['sequence']}",
                "sent_at_utc": f"2026-07-15T00:0{item['sequence']}:00Z",
                "reply_at_utc": f"2026-07-15T00:0{item['sequence']}:20Z",
                "telegram_message_id": f"sent-{item['sequence']}",
                "reply_message_id": f"reply-{item['sequence']}",
                "turn_screenshot": str(fake_png),
                "turn_accessibility": str(fake_text),
            }
            for item in packet["exact_messages"]
        ],
    }

    receipt = run_verifier(packet, packet_path, before, after, capture, None, tmp_path)

    assert receipt["status"] == "fail"
    assert receipt["current_tier"] != "T3_live_readonly"
    assert receipt["telegram_visible_messages_sent"] is False
    assert receipt["checks"]["capture_schema_supported"] is False
    assert receipt["checks"]["preflight_schema_supported"] is False
    assert receipt["checks"]["preflight_state_token_derivation_valid"] is False
    assert receipt["checks"]["codex_rollout_log_has_expected_local_sessions_shape"] is False
    assert receipt["checks"]["codex_rollout_has_exact_single_authorization_event"] is False
    assert receipt["checks"]["screenshots_are_valid_png_with_metadata"] is False
    assert receipt["checks"]["per_turn_screenshot_hashes_distinct_nonempty"] is False


def test_state_token_tampering_is_rejected(tmp_path: Path) -> None:
    packet, packet_path, before, after, capture, rollout = verified_fixture(tmp_path)
    before = copy.deepcopy(before)
    before["generated_at_utc"] = "2026-07-14T23:58:00Z"

    receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path)

    assert receipt["status"] == "fail"
    assert receipt["checks"]["preflight_state_token_derivation_valid"] is False
