#!/usr/bin/env python3
"""Build an external proof packet for the opcode 0x24 runtime-producer blocker."""
from __future__ import annotations

import argparse
import html
import json
from pathlib import Path
from typing import Any


ROOT = Path(__file__).resolve().parents[1]
OUT = ROOT / "out"
SOURCE = "map1_01a"
TARGET = "map2_02d"
OPCODE24_RUNTIME_PRODUCER_EXTERNAL_EVIDENCE_REFS = [
    {
        "path": "out/save_selector_opcode24_mode1_runtime_context.json",
        "fields": ["proofFound", "failedOpcode24RuntimeProducerGateIds", "missingEvidence"],
    },
    {
        "path": "out/save_selector_opcode24_mode1_source_writes.json",
        "fields": ["rows", "coveringWriteCount", "staticProducerCandidateCount"],
    },
    {
        "path": "out/save_selector_opcode24_mode1_indirect_context.json",
        "fields": ["basePlusMode1OffsetCandidateCount", "noStaticBaseIndirectCandidate"],
    },
    {
        "path": "out/save_selector_opcode24_mode1_file_read_context.json",
        "fields": ["readFileCallCount", "mode1FileReadCandidateCount"],
    },
    {
        "path": "out/save_selector_opcode24_mode1_block_writes.json",
        "fields": ["rows", "blockWriteCandidateCount", "directCoveringWriteCount"],
    },
    {
        "path": "out/save_selector_opcode24_runtime_enabled_context.json",
        "fields": ["runtimeEnabledFlagHex", "directWriteCount", "evidenceRefs"],
    },
    {
        "path": "out/save_selector_opcode24_runtime_enabled_block_writes.json",
        "fields": ["blockWriteCandidateCount", "directCoveringWriteCount"],
    },
    {
        "path": "out/save_selector_opcode24_mode1_default_effect.json",
        "fields": ["staticDefaultPromotesRoute", "directFrontierOperandCount"],
    },
    {
        "path": "out/save_selector_opcode24_current_root_modes.json",
        "fields": ["gateBoundaryVaHex", "mode1CandidateCount", "frontierOperandCount"],
    },
    {
        "path": "out/runtime_opcode24_flag_context.json",
        "fields": ["classification", "runtimeFlagOneCount", "mode1SourceNonzeroObserved"],
    },
    {
        "path": "out/runtime_trace_feasibility.json",
        "fields": ["canRunRuntimeTraceNow", "tracePoints", "blockers"],
    },
    {
        "path": "out/runtime_trace_execution_probe.json",
        "fields": ["canCaptureTraceNow", "blockers"],
    },
]


def load_json(path: Path, fallback: Any) -> Any:
    if not path.exists():
        return fallback
    return json.loads(path.read_text(encoding="utf-8"))


def build_summary(out_dir: Path = OUT) -> dict:
    runtime = load_json(out_dir / "save_selector_opcode24_mode1_runtime_context.json", {})
    source_writes = load_json(out_dir / "save_selector_opcode24_mode1_source_writes.json", {})
    indirect = load_json(out_dir / "save_selector_opcode24_mode1_indirect_context.json", {})
    file_read = load_json(out_dir / "save_selector_opcode24_mode1_file_read_context.json", {})
    block = load_json(out_dir / "save_selector_opcode24_mode1_block_writes.json", {})
    flag = load_json(out_dir / "save_selector_opcode24_runtime_enabled_context.json", {})
    flag_block = load_json(out_dir / "save_selector_opcode24_runtime_enabled_block_writes.json", {})
    default_effect = load_json(out_dir / "save_selector_opcode24_mode1_default_effect.json", {})
    root_modes = load_json(out_dir / "save_selector_opcode24_current_root_modes.json", {})
    runtime_flag = load_json(out_dir / "runtime_opcode24_flag_context.json", {})
    trace = load_json(out_dir / "runtime_trace_feasibility.json", {})
    trace_exec = load_json(out_dir / "runtime_trace_execution_probe.json", {})

    storage = runtime.get("storage") or {}
    return {
        "source": SOURCE,
        "target": TARGET,
        "promotionStatus": "blocked",
        "proofFound": runtime.get("proofFound"),
        "failedOpcode24RuntimeProducerGateIds": (
            runtime.get("failedOpcode24RuntimeProducerGateIds") or []
        ),
        "missingEvidence": runtime.get("missingEvidence") or [],
        "mode1SourceHex": runtime.get("mode1SourceHex") or "0x0059e348",
        "mode1ReadVaHex": "0x0040c675",
        "opcode24BoundaryVaHex": root_modes.get("gateBoundaryVaHex") or "0x005428e4",
        "frontierReaderHex": "0x00542b0c",
        "storage": {
            "sectionName": storage.get("sectionName"),
            "rawBytePresent": storage.get("mode1SourceHasRawByte"),
            "staticInitialValueHex": storage.get("staticInitialValueHex"),
            "staticInitialValueKind": storage.get("staticInitialValueKind"),
            "saveBacked": runtime.get("saveReadBlockContainsMode1Source"),
        },
        "directProducerEvidence": {
            "sourceWriteRows": len(source_writes.get("rows") or []),
            "coveringWriteCount": source_writes.get("coveringWriteCount"),
            "indexedWriteCandidateCount": source_writes.get("indexedWriteCandidateCount"),
            "addressProducerCandidateCount": source_writes.get("addressProducerCandidateCount"),
            "staticProducerCandidateCount": source_writes.get("staticProducerCandidateCount"),
        },
        "indirectProducerEvidence": {
            "basePlusMode1OffsetCandidateCount": indirect.get("basePlusMode1OffsetCandidateCount"),
            "baseWindowMode1WriteCandidateCount": indirect.get("baseWindowMode1WriteCandidateCount"),
            "nearbyBaseWindowMode1WriteCandidateCount": indirect.get("nearbyBaseWindowMode1WriteCandidateCount"),
            "noStaticBaseIndirectCandidate": indirect.get("noStaticBaseIndirectCandidate"),
        },
        "fileAndBlockProducerEvidence": {
            "readFileCallCount": file_read.get("readFileCallCount"),
            "globalDestinationReadFileCount": file_read.get("globalDestinationReadFileCount"),
            "mode1FileReadCandidateCount": file_read.get("mode1FileReadCandidateCount"),
            "mode1BlockRowCount": len(block.get("rows") or []),
            "mode1BlockWriteCandidateCount": block.get("blockWriteCandidateCount"),
            "mode1BlockDirectCoveringWriteCount": block.get("directCoveringWriteCount"),
        },
        "runtimeEnabledFlagEvidence": {
            "flagHex": flag.get("runtimeEnabledFlagHex") or "0x0059e34d",
            "refCount": len(flag.get("refs") or []),
            "directWriteCount": flag.get("directWriteCount"),
            "modeDispatchRequiresRuntimeFlagOne": flag.get("modeDispatchRequiresRuntimeFlagOne"),
            "staticEvidenceProvesModeDispatch": flag.get("staticEvidenceProvesModeDispatch"),
            "blockWriteCandidateCount": flag_block.get("blockWriteCandidateCount"),
            "blockDirectCoveringWriteCount": flag_block.get("directCoveringWriteCount"),
        },
        "defaultAndRuntimePollEvidence": {
            "staticDefaultPromotesRoute": default_effect.get("staticDefaultPromotesRoute"),
            "directFrontierOperandCount": default_effect.get("directFrontierOperandCount"),
            "branchFrontierOperandCount": default_effect.get("branchFrontierOperandCount"),
            "currentRootMode1CandidateCount": root_modes.get("mode1CandidateCount"),
            "currentRootFrontierOperandCount": root_modes.get("frontierOperandCount"),
            "currentRootRouteCnsOperandCount": root_modes.get("routeCnsOperandCount"),
            "runtimeClassification": runtime_flag.get("classification"),
            "pollCount": runtime_flag.get("pollCount"),
            "runtimeFlagOneCount": runtime_flag.get("runtimeFlagOneCount"),
            "mode1SourceNonzeroObserved": runtime_flag.get("mode1SourceNonzeroObserved"),
            "sourceSaveLoadClassification": runtime_flag.get("sourceSaveLoadClassification"),
            "sourceSaveLoadDiversionSelector": runtime_flag.get("sourceSaveLoadDiversionSelector"),
            "sourceSaveLoadRoutePromotionEvidenceFound": runtime_flag.get(
                "sourceSaveLoadRoutePromotionEvidenceFound"
            ),
        },
        "traceAvailability": {
            "canRunRuntimeTraceNow": trace.get("canRunRuntimeTraceNow"),
            "canCaptureTraceNow": trace_exec.get("canCaptureTraceNow"),
            "tracePoints": trace.get("tracePoints") or [],
            "blockers": (trace.get("blockers") or []) + (trace_exec.get("blockers") or []),
        },
        "acceptedEvidenceChecklist": [
            {
                "requirement": "runtime write producer for 0x0059e348 on the normal route path",
                "currentStatus": "missing",
                "acceptedSignal": "watchpoint captures a write to 0x0059e348 before opcode 0x24 mode1 read",
            },
            {
                "requirement": "opcode 0x24 mode1 read consumes nonzero route-relevant value",
                "currentStatus": "missing",
                "acceptedSignal": "breakpoint at 0x0040c675 observes route-backed mode1 source",
            },
            {
                "requirement": "runtime flag enables route-relevant opcode 0x24 mode dispatch",
                "currentStatus": "missing",
                "acceptedSignal": "0x0059e34d == 1 with selected root/strict hotspot proof on same path",
            },
        ],
        "notAcceptedEvidence": [
            "static zero-filled storage at 0x0059e348",
            "runtime flag 0x0059e34d == 1 while selected pointer remains non-route",
            "constructed selector diagnostics with mode1 source still zero",
            "generic opcode 0x24 mode1 payload patterns with no frontier or route CNS operands",
        ],
        "evidenceRefs": OPCODE24_RUNTIME_PRODUCER_EXTERNAL_EVIDENCE_REFS,
        "evidenceRefCount": len(OPCODE24_RUNTIME_PRODUCER_EXTERNAL_EVIDENCE_REFS),
        "relatedReports": [
            "out/save_selector_opcode24_mode1_runtime_context.json",
            "out/save_selector_opcode24_mode1_source_writes.json",
            "out/save_selector_opcode24_mode1_indirect_context.json",
            "out/save_selector_opcode24_mode1_file_read_context.json",
            "out/save_selector_opcode24_mode1_block_writes.json",
            "out/save_selector_opcode24_runtime_enabled_context.json",
            "out/runtime_opcode24_flag_context.json",
            "out/runtime_trace_feasibility.html",
        ],
        "regenerateAndVerifyCommands": [
            "python3 tools/summarize_opcode24_runtime_producer_external_proof_packet.py",
            "python3 tools/verify_web_assets.py",
        ],
        "remainingProofs": runtime.get("remainingProofs") or [],
        "conclusion": (
            "Opcode 0x24 mode1 remains blocked: static/direct/file/block producers are absent, "
            "runtime polls keep 0x0059e348 at zero, and a stable watchpoint trace is unavailable."
        ),
    }


def markdown(summary: dict) -> str:
    direct = summary.get("directProducerEvidence") or {}
    indirect = summary.get("indirectProducerEvidence") or {}
    file_block = summary.get("fileAndBlockProducerEvidence") or {}
    flag = summary.get("runtimeEnabledFlagEvidence") or {}
    polls = summary.get("defaultAndRuntimePollEvidence") or {}
    trace = summary.get("traceAvailability") or {}
    lines = [
        "# Opcode 0x24 Runtime Producer External Proof Packet",
        "",
        f"- route: `{summary['source']} -> {summary['target']}`",
        f"- promotion status: `{summary['promotionStatus']}`",
        f"- proofFound: {summary.get('proofFound')}",
        f"- failed opcode24 runtime producer gates: `{', '.join(summary.get('failedOpcode24RuntimeProducerGateIds') or []) or '-'}`",
        f"- missing evidence count: {len(summary.get('missingEvidence') or [])}",
        f"- mode1 source: `{summary.get('mode1SourceHex')}`",
        f"- mode1 read: `{summary.get('mode1ReadVaHex')}`",
        f"- opcode24 boundary: `{summary.get('opcode24BoundaryVaHex')}`",
        f"- frontier reader: `{summary.get('frontierReaderHex')}`",
        f"- evidence refs: {summary.get('evidenceRefCount')}",
        "",
        "## Producer Evidence",
        "",
        f"- direct rows/covering/indexed/static: {direct.get('sourceWriteRows')}/{direct.get('coveringWriteCount')}/{direct.get('indexedWriteCandidateCount')}/{direct.get('staticProducerCandidateCount')}",
        f"- indirect base+offset/window/nearby/no-static: {indirect.get('basePlusMode1OffsetCandidateCount')}/{indirect.get('baseWindowMode1WriteCandidateCount')}/{indirect.get('nearbyBaseWindowMode1WriteCandidateCount')}/{indirect.get('noStaticBaseIndirectCandidate')}",
        f"- ReadFile/global/mode1 candidates: {file_block.get('readFileCallCount')}/{file_block.get('globalDestinationReadFileCount')}/{file_block.get('mode1FileReadCandidateCount')}",
        f"- block rows/candidates/direct-covering: {file_block.get('mode1BlockRowCount')}/{file_block.get('mode1BlockWriteCandidateCount')}/{file_block.get('mode1BlockDirectCoveringWriteCount')}",
        "",
        "## Runtime Flag And Polls",
        "",
        f"- runtime flag: `{flag.get('flagHex')}` refs/direct writes/requires/static: {flag.get('refCount')}/{flag.get('directWriteCount')}/{flag.get('modeDispatchRequiresRuntimeFlagOne')}/{flag.get('staticEvidenceProvesModeDispatch')}",
        f"- flag block candidates/direct-covering: {flag.get('blockWriteCandidateCount')}/{flag.get('blockDirectCoveringWriteCount')}",
        f"- runtime classification: `{polls.get('runtimeClassification')}`",
        f"- poll count / flag-one / mode1 nonzero: {polls.get('pollCount')}/{polls.get('runtimeFlagOneCount')}/{polls.get('mode1SourceNonzeroObserved')}",
        f"- source-save diversion: `{polls.get('sourceSaveLoadClassification')}` -> `{polls.get('sourceSaveLoadDiversionSelector')}`",
        "",
        "## Trace Availability",
        "",
        f"- can run runtime trace now: {trace.get('canRunRuntimeTraceNow')}",
        f"- can capture trace now: {trace.get('canCaptureTraceNow')}",
        "",
        "## Accepted Evidence Checklist",
        "",
        "| requirement | current status | accepted signal |",
        "| --- | --- | --- |",
    ]
    for row in summary.get("acceptedEvidenceChecklist") or []:
        lines.append(f"| {row.get('requirement')} | {row.get('currentStatus')} | {row.get('acceptedSignal')} |")
    lines.extend(["", "## Missing Evidence", ""])
    lines.extend(f"- {item}" for item in summary.get("missingEvidence") or [])
    lines.extend(["", "## Not Accepted Evidence", ""])
    lines.extend(f"- {item}" for item in summary.get("notAcceptedEvidence") or [])
    lines.extend(["", "## Related Reports", ""])
    lines.extend(f"- `{item}`" for item in summary.get("relatedReports") or [])
    lines.extend(["", "## Regenerate And Verify", ""])
    lines.extend(f"- `{item}`" for item in summary.get("regenerateAndVerifyCommands") or [])
    lines.extend(["", summary.get("conclusion") or "", ""])
    return "\n".join(lines)


def html_page(summary: dict) -> str:
    def esc(value: Any) -> str:
        return html.escape(str(value))

    checklist_rows = "".join(
        "<tr>"
        f"<td>{esc(row.get('requirement'))}</td>"
        f"<td>{esc(row.get('currentStatus'))}</td>"
        f"<td>{esc(row.get('acceptedSignal'))}</td>"
        "</tr>"
        for row in summary.get("acceptedEvidenceChecklist") or []
    )
    not_accepted = "".join(f"<li>{esc(item)}</li>" for item in summary.get("notAcceptedEvidence") or [])
    missing = "".join(f"<li>{esc(item)}</li>" for item in summary.get("missingEvidence") or [])
    related = "".join(f"<li><code>{esc(item)}</code></li>" for item in summary.get("relatedReports") or [])
    commands = "".join(f"<li><code>{esc(item)}</code></li>" for item in summary.get("regenerateAndVerifyCommands") or [])
    direct = summary.get("directProducerEvidence") or {}
    indirect = summary.get("indirectProducerEvidence") or {}
    file_block = summary.get("fileAndBlockProducerEvidence") or {}
    flag = summary.get("runtimeEnabledFlagEvidence") or {}
    polls = summary.get("defaultAndRuntimePollEvidence") or {}
    trace = summary.get("traceAvailability") or {}
    return "\n".join([
        "<!doctype html>",
        '<html lang="en">',
        "<head>",
        '  <meta charset="utf-8">',
        '  <meta name="viewport" content="width=device-width, initial-scale=1">',
        "  <title>Opcode 0x24 Runtime Producer External Proof Packet</title>",
        "  <style>body{margin:24px;background:#101010;color:#eee;font:14px system-ui,sans-serif}table{border-collapse:collapse;width:100%;margin:16px 0 28px}th,td{border:1px solid #333;padding:6px 8px;vertical-align:top}code{color:#f5d76e}</style>",
        "</head>",
        "<body>",
        "  <h1>Opcode 0x24 Runtime Producer External Proof Packet</h1>",
        f"  <p>route <code>{esc(summary['source'])}</code> -&gt; <code>{esc(summary['target'])}</code>; "
        f"mode1 source <code>{esc(summary.get('mode1SourceHex'))}</code>; read "
        f"<code>{esc(summary.get('mode1ReadVaHex'))}</code>; boundary <code>{esc(summary.get('opcode24BoundaryVaHex'))}</code>; "
        f"frontier reader <code>{esc(summary.get('frontierReaderHex'))}</code>.</p>",
        f"  <p>proofFound: {esc(summary.get('proofFound'))}; failed opcode24 runtime producer gates: "
        f"<code>{esc(', '.join(summary.get('failedOpcode24RuntimeProducerGateIds') or []) or '-')}</code>; "
        f"missing evidence count: {esc(len(summary.get('missingEvidence') or []))}; "
        f"evidence refs <code>{esc(summary.get('evidenceRefCount'))}</code>.</p>",
        "  <h2>Producer Evidence</h2>",
        f"  <p>direct rows/covering/indexed/static: {esc(direct.get('sourceWriteRows'))}/{esc(direct.get('coveringWriteCount'))}/{esc(direct.get('indexedWriteCandidateCount'))}/{esc(direct.get('staticProducerCandidateCount'))}; "
        f"indirect base/window/nearby: {esc(indirect.get('basePlusMode1OffsetCandidateCount'))}/{esc(indirect.get('baseWindowMode1WriteCandidateCount'))}/{esc(indirect.get('nearbyBaseWindowMode1WriteCandidateCount'))}; "
        f"ReadFile/global/mode1: {esc(file_block.get('readFileCallCount'))}/{esc(file_block.get('globalDestinationReadFileCount'))}/{esc(file_block.get('mode1FileReadCandidateCount'))}; "
        f"block candidates: {esc(file_block.get('mode1BlockWriteCandidateCount'))}.</p>",
        "  <h2>Runtime Flag And Polls</h2>",
        f"  <p>flag <code>{esc(flag.get('flagHex'))}</code>; refs/direct writes/requires/static: "
        f"{esc(flag.get('refCount'))}/{esc(flag.get('directWriteCount'))}/{esc(flag.get('modeDispatchRequiresRuntimeFlagOne'))}/{esc(flag.get('staticEvidenceProvesModeDispatch'))}; "
        f"classification <code>{esc(polls.get('runtimeClassification'))}</code>; poll/flag-one/nonzero: "
        f"{esc(polls.get('pollCount'))}/{esc(polls.get('runtimeFlagOneCount'))}/{esc(polls.get('mode1SourceNonzeroObserved'))}; "
        f"source-save path <code>{esc(polls.get('sourceSaveLoadClassification'))}</code> "
        f"diverts to <code>{esc(polls.get('sourceSaveLoadDiversionSelector'))}</code>.</p>",
        "  <h2>Trace Availability</h2>",
        f"  <p>canRunRuntimeTraceNow {esc(trace.get('canRunRuntimeTraceNow'))}; "
        f"canCaptureTraceNow {esc(trace.get('canCaptureTraceNow'))}.</p>",
        "  <h2>Accepted Evidence Checklist</h2>",
        f"  <table><thead><tr><th>requirement</th><th>status</th><th>accepted signal</th></tr></thead><tbody>{checklist_rows}</tbody></table>",
        "  <h2>Missing Evidence</h2>",
        f"  <ul>{missing}</ul>",
        "  <h2>Not Accepted Evidence</h2>",
        f"  <ul>{not_accepted}</ul>",
        "  <h2>Related Reports</h2>",
        f"  <ul>{related}</ul>",
        "  <h2>Regenerate And Verify</h2>",
        f"  <ul>{commands}</ul>",
        f"  <p>{esc(summary.get('conclusion'))}</p>",
        "</body>",
        "</html>",
        "",
    ])


def write_outputs(summary: dict, out_dir: Path = OUT) -> None:
    out_dir.mkdir(parents=True, exist_ok=True)
    (out_dir / "opcode24_runtime_producer_external_proof_packet.json").write_text(
        json.dumps(summary, ensure_ascii=False, separators=(",", ":")) + "\n",
        encoding="utf-8",
    )
    (out_dir / "opcode24_runtime_producer_external_proof_packet.html").write_text(html_page(summary), encoding="utf-8")


def main() -> None:
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("--out-dir", type=Path, default=OUT)
    args = parser.parse_args()
    summary = build_summary(args.out_dir)
    write_outputs(summary, args.out_dir)
    print(
        "wrote opcode24 runtime producer external proof packet -> "
        f"{args.out_dir / 'opcode24_runtime_producer_external_proof_packet.html'}"
    )


if __name__ == "__main__":
    main()
