#!/usr/bin/env python3
"""Build an external proof packet for the blocked selected-root execution gate."""
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"
SELECTED_ROOT_EXTERNAL_EVIDENCE_REFS = [
    {
        "path": "out/save_selector_real_savedata_evidence_gap.json",
        "fields": ["proofFound", "failedSavedataGateIds", "missingEvidence"],
    },
    {
        "path": "out/save_selector_selected_pointer_usage.json",
        "fields": ["selectedPointerGlobalHex", "currentRootHex", "selectedPointerMatchesCurrentRoot", "promotionStatus"],
    },
    {
        "path": "out/save_selector_dispatch_table_context.json",
        "fields": ["proofFound", "failedDispatchTableGateIds", "missingEvidence"],
    },
    {
        "path": "out/save_selector_global_selected_pointer_paths.json",
        "fields": ["nonCurrentSelectedPointerPathCount", "routeBackedPathCount"],
    },
    {
        "path": "out/save_selector_current_writer_paths.json",
        "fields": ["proofFound", "failedCurrentWriterPathGateIds", "missingEvidence"],
    },
    {
        "path": "out/runtime_selected_pointer_poll.json",
        "fields": ["sampleCount", "reachedRouteSelector", "observedSelectors"],
    },
    {
        "path": "out/runtime_patched_public_selector_2_0_input_path_case_alias_poll.json",
        "fields": ["observedSelectors", "constructedDiagnosticExcludedFromProof"],
    },
]


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


def summarize_subgates(selected: dict) -> list[dict]:
    statuses = selected.get("selectedRootSubgateStatuses") or {}
    rows = []
    for row in selected.get("gateRows") or []:
        gate = row.get("gate")
        rows.append({
            "gate": gate,
            "status": row.get("status") or statuses.get(gate),
            "evidence": row.get("evidence"),
            "impact": row.get("impact"),
        })
    return rows


def summarize_route_pair(route_pair: dict) -> dict:
    return {
        "promotionStatus": route_pair.get("promotionStatus"),
        "selector": route_pair.get("selector"),
        "rootHex": route_pair.get("rootHex"),
        "rootTablePointerHex": route_pair.get("rootTablePointerHex"),
        "frontierReaderHex": route_pair.get("frontierReaderHex"),
        "routePairEntryIndices": route_pair.get("routePairEntryIndices") or [],
        "routePairCorrectedTraceEntryIndices": route_pair.get("routePairCorrectedTraceEntryIndices") or [],
        "negativeReaderEntryIndices": route_pair.get("negativeReaderEntryIndices") or [],
        "routePairCurrentEntryCount": route_pair.get("routePairCurrentEntryCount"),
        "routePairCorrectedTraceReachesReaderCount": route_pair.get(
            "routePairCorrectedTraceReachesReaderCount"
        ),
        "frontierReaderSelectableByNonNegativeIndex": route_pair.get(
            "frontierReaderSelectableByNonNegativeIndex"
        ),
        "frontierReaderReachableByCorrectedNonNegativeIndex": route_pair.get(
            "frontierReaderReachableByCorrectedNonNegativeIndex"
        ),
        "correctedTraceNormalSelectionGapFound": route_pair.get("correctedTraceNormalSelectionGapFound"),
        "correctedTraceNormalSelectionGapStatus": route_pair.get("correctedTraceNormalSelectionGapStatus"),
        "routePairEntryExecutionProven": route_pair.get("routePairEntryExecutionProven"),
        "selectedRootExecutionRefFound": route_pair.get("selectedRootExecutionRefFound"),
        "wrapperExecutionProofFound": route_pair.get("wrapperExecutionProofFound"),
        "rootTableWindowDirectRefCount": route_pair.get("rootTableWindowDirectRefCount"),
        "rootTableWindowDirectTextRefCount": route_pair.get("rootTableWindowDirectTextRefCount"),
        "routePairIndexSourceHigherLevelIndexSourceProven": route_pair.get(
            "routePairIndexSourceHigherLevelIndexSourceProven"
        ),
        "evidenceRows": route_pair.get("evidenceRows") or [],
        "remainingProofs": route_pair.get("remainingProofs") or [],
    }


def summarize_wrapper(wrapper: dict) -> dict:
    return {
        "promotionStatus": wrapper.get("promotionStatus"),
        "wrapperEntryHex": wrapper.get("wrapperEntryHex"),
        "wrapperDescriptorHex": wrapper.get("wrapperDescriptorHex"),
        "wrapperChildPointerHex": wrapper.get("wrapperChildPointerHex"),
        "frontierLeafHex": wrapper.get("frontierLeafHex"),
        "frontierReaderHex": wrapper.get("frontierReaderHex"),
        "currentRootReferencesWrapper": wrapper.get("currentRootReferencesWrapper"),
        "wrapperEntryRefCount": wrapper.get("wrapperEntryRefCount"),
        "wrapperEntryCurrentRootEntryRunRefCount": wrapper.get("wrapperEntryCurrentRootEntryRunRefCount"),
        "wrapperEntryOpcode5aFallthroughRefCount": wrapper.get("wrapperEntryOpcode5aFallthroughRefCount"),
        "wrapperEntryFallthroughNonCodeRefCount": wrapper.get("wrapperEntryFallthroughNonCodeRefCount"),
        "wrapperEntryPromotingRefCount": wrapper.get("wrapperEntryPromotingRefCount"),
        "wrapperChildIsFrontierLeaf": wrapper.get("wrapperChildIsFrontierLeaf"),
        "wrapperExecutionProofFound": wrapper.get("wrapperExecutionProofFound"),
        "currentLeafSelectionProofFound": wrapper.get("currentLeafSelectionProofFound"),
        "currentSelectorLeafExecutionProofFound": wrapper.get("currentSelectorLeafExecutionProofFound"),
        "constructedDiagnosticExcludedFromWrapperProof": wrapper.get(
            "constructedDiagnosticExcludedFromWrapperProof"
        ),
        "constructedDiagnosticLeftStabilityReproducibility": wrapper.get(
            "constructedDiagnosticLeftStabilityReproducibility"
        ),
        "constructedDiagnosticLeftStabilityRouteSelectorHitCount": wrapper.get(
            "constructedDiagnosticLeftStabilityRouteSelectorHitCount"
        ),
        "constructedDiagnosticLeftStabilityRecheckRouteSelectorHitCount": wrapper.get(
            "constructedDiagnosticLeftStabilityRecheckRouteSelectorHitCount"
        ),
        "constructedDiagnosticLeftActiveOrderRecheckRouteSelectorHitCount": wrapper.get(
            "constructedDiagnosticLeftActiveOrderRecheckRouteSelectorHitCount"
        ),
        "constructedDiagnosticLeftActiveOrderRecheckActiveOrderCountValues": wrapper.get(
            "constructedDiagnosticLeftActiveOrderRecheckActiveOrderCountValues"
        ),
        "remainingProofs": wrapper.get("remainingProofs") or [],
        "evidenceRefs": wrapper.get("evidenceRefs") or [],
    }


def summarize_leaf_table(leaf_table: dict) -> dict:
    return {
        "selector": leaf_table.get("selector"),
        "rootHex": leaf_table.get("rootHex"),
        "rootTablePointerHex": leaf_table.get("rootTablePointerHex"),
        "frontierLeafHex": leaf_table.get("frontierLeafHex"),
        "frontierReaderHex": leaf_table.get("frontierReaderHex"),
        "frontierLeafRefIsDirectRootTableEntry": leaf_table.get("frontierLeafRefIsDirectRootTableEntry"),
        "runtimeSelectionProven": leaf_table.get("runtimeSelectionProven"),
        "promotionStatus": leaf_table.get("promotionStatus"),
    }


def build_summary(out_dir: Path = OUT) -> dict:
    selected = load_json(out_dir / "save_selector_selected_root_execution_gap.json", {})
    route_pair = load_json(out_dir / "save_selector_route_pair_entry_execution_gap.json", {})
    wrapper = load_json(out_dir / "save_selector_wrapper_execution_gap.json", {})
    leaf_table = load_json(out_dir / "save_selector_leaf_table_context.json", {})
    subgate_rows = summarize_subgates(selected)
    evidence_refs = selected.get("evidenceRefs") or SELECTED_ROOT_EXTERNAL_EVIDENCE_REFS
    return {
        "source": SOURCE,
        "target": TARGET,
        "promotionStatus": "blocked",
        "proofFound": selected.get("proofFound"),
        "selectedRootExternalProofFound": selected.get("proofFound"),
        "failedSelectedRootExternalGateIds": selected.get("failedSelectedRootGateIds") or [],
        "missingEvidence": selected.get("missingEvidence") or [],
        "currentSelector": selected.get("currentSelector"),
        "currentRootHex": selected.get("currentRootHex"),
        "selectedPointerGlobalHex": selected.get("selectedPointerGlobalHex"),
        "selectedRootExecutionRefFound": selected.get("selectedRootExecutionRefFound"),
        "selectedRootExecutionRejectionClassification": selected.get(
            "selectedRootExecutionRejectionClassification"
        ),
        "selectedRootSubgateCount": selected.get("selectedRootSubgateCount") or len(subgate_rows),
        "selectedRootNonPromotingSubgateCount": selected.get(
            "selectedRootNonPromotingSubgateCount"
        ) or len(subgate_rows),
        "selectedRootAllSubgatesNonPromoting": selected.get("selectedRootAllSubgatesNonPromoting"),
        "subgateRows": subgate_rows,
        "saveLoaderGate": selected.get("saveLoaderGate") or {},
        "staticReferenceGate": selected.get("staticReferenceGate") or {},
        "runtimeProbeGate": selected.get("runtimeProbeGate") or {},
        "diagnosticExclusionGate": selected.get("diagnosticExclusionGate") or {},
        "routePairSelectionEvidence": summarize_route_pair(route_pair),
        "wrapperExecutionEvidence": summarize_wrapper(wrapper),
        "leafTableEvidence": summarize_leaf_table(leaf_table),
        "acceptedEvidenceChecklist": [
            {
                "requirement": "real selector 2:0 savedata selects 0x00540714",
                "currentStatus": "missing",
                "acceptedSignal": "saveLoaderGate.currentSelectorRealSaveCount > 0 and selectedPointerRealSaveCount > 0",
            },
            {
                "requirement": "normal runtime reaches selected pointer 0x00540714",
                "currentStatus": "missing",
                "acceptedSignal": "runtimeProbeGate.anyRuntimePollReachedRouteSelector == true on non-diagnostic input",
            },
            {
                "requirement": "non-current root selects/stores current 2:0 root or range",
                "currentStatus": "missing",
                "acceptedSignal": "opcode 07/08/09 non-current producer count is positive and route-backed",
            },
            {
                "requirement": "entry 6/8 or wrapper -12 is selected in normal execution",
                "currentStatus": "missing",
                "acceptedSignal": "routePairEntryExecutionProven == true or wrapperExecutionProofFound == true",
            },
        ],
        "notAcceptedEvidence": [
            "constructed selector 2:0 savedata or patched public-base diagnostics",
            "corrected trace reachability without normal entry selection",
            "table-only .data references with no text/control-flow ref",
            "selected-pointer hook refs whose prerequisites are not satisfied",
        ],
        "relatedReports": [
            "out/save_selector_selected_root_execution_gap.html",
            "out/save_selector_route_pair_entry_execution_gap.html",
            "out/save_selector_wrapper_execution_gap.html",
            "out/save_selector_leaf_table_context.json",
        ],
        "evidenceRefs": evidence_refs,
        "evidenceRefCount": len(evidence_refs),
        "regenerateAndVerifyCommands": [
            "python3 tools/summarize_selected_root_execution_external_proof_packet.py",
            "python3 tools/verify_web_assets.py",
        ],
        "remainingProofs": selected.get("remainingProofs") or [],
        "conclusion": (
            "Selected-root execution remains blocked: selector 2:0 is present as table data, "
            "but no real save, normal runtime trace, non-current producer, or wrapper/entry "
            "selection proof reaches 0x00540714."
        ),
    }


def markdown(summary: dict) -> str:
    lines = [
        "# Selected Root Execution External Proof Packet",
        "",
        f"- route: `{summary['source']} -> {summary['target']}`",
        f"- promotion status: `{summary['promotionStatus']}`",
        f"- current selector: `{summary.get('currentSelector')}`",
        f"- current root: `{summary.get('currentRootHex')}`",
        f"- selected pointer global: `{summary.get('selectedPointerGlobalHex')}`",
        f"- proof found: {summary.get('proofFound')}",
        f"- selectedRootExternalProofFound: {summary.get('selectedRootExternalProofFound')}",
        f"- failed selected-root external gates: `{', '.join(summary.get('failedSelectedRootExternalGateIds') or [])}`",
        f"- missing evidence count: {len(summary.get('missingEvidence') or [])}",
        f"- evidence refs: {summary.get('evidenceRefCount')}",
        f"- selected-root execution ref found: {summary.get('selectedRootExecutionRefFound')}",
        f"- rejection: `{summary.get('selectedRootExecutionRejectionClassification')}`",
        "",
        "## Subgates",
        "",
        "| gate | status | evidence | impact |",
        "| --- | --- | --- | --- |",
    ]
    for row in summary.get("subgateRows") or []:
        lines.append(
            f"| {row.get('gate')} | `{row.get('status')}` | {row.get('evidence')} | {row.get('impact')} |"
        )
    route_pair = summary.get("routePairSelectionEvidence") or {}
    wrapper = summary.get("wrapperExecutionEvidence") or {}
    diagnostic = summary.get("diagnosticExclusionGate") or {}
    lines.extend([
        "",
        "## Route-Pair Entry Selection",
        "",
        f"- route-pair entry indices: `{route_pair.get('routePairEntryIndices')}`",
        f"- negative reader entry indices: `{route_pair.get('negativeReaderEntryIndices')}`",
        f"- corrected trace reaches reader count: {route_pair.get('routePairCorrectedTraceReachesReaderCount')}",
        f"- non-negative frontier reader selectable: {route_pair.get('frontierReaderSelectableByNonNegativeIndex')}",
        f"- corrected trace normal selection gap: {route_pair.get('correctedTraceNormalSelectionGapFound')}",
        f"- route-pair entry execution proven: {route_pair.get('routePairEntryExecutionProven')}",
        "",
        "## Wrapper Execution",
        "",
        f"- wrapper entry: `{wrapper.get('wrapperEntryHex')}`",
        f"- wrapper descriptor: `{wrapper.get('wrapperDescriptorHex')}`",
        f"- wrapper child: `{wrapper.get('wrapperChildPointerHex')}`",
        f"- wrapper child is frontier leaf: {wrapper.get('wrapperChildIsFrontierLeaf')}",
        f"- current root references wrapper: {wrapper.get('currentRootReferencesWrapper')}",
        f"- wrapper entry promoting refs: {wrapper.get('wrapperEntryPromotingRefCount')}",
        f"- wrapper execution proof found: {wrapper.get('wrapperExecutionProofFound')}",
        "",
        "## Diagnostic Exclusion",
        "",
        f"- diagnostic route observed: {diagnostic.get('branchStateReachedRouteSelector')}",
        f"- excluded from proof: {diagnostic.get('excludedFromSelectedRootExecutionProof')}",
        f"- left stability reproducibility: {diagnostic.get('leftStabilityRouteHitReproducibility')}",
        f"- left recheck route hits: {diagnostic.get('leftStabilityRecheckRouteSelectorHitCount')}",
        f"- left active-order recheck route hits: {diagnostic.get('leftActiveOrderRecheckRouteSelectorHitCount')}",
        "",
        "## 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(["", "## Evidence Refs", ""])
    lines.extend(
        f"- `{ref.get('path')}`: {', '.join(ref.get('fields') or [])}"
        for ref in summary.get("evidenceRefs") 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))

    subgate_rows = "".join(
        "<tr>"
        f"<td>{esc(row.get('gate'))}</td>"
        f"<td><code>{esc(row.get('status'))}</code></td>"
        f"<td>{esc(row.get('evidence'))}</td>"
        f"<td>{esc(row.get('impact'))}</td>"
        "</tr>"
        for row in summary.get("subgateRows") or []
    )
    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 []
    )
    route_pair = summary.get("routePairSelectionEvidence") or {}
    wrapper = summary.get("wrapperExecutionEvidence") or {}
    diagnostic = summary.get("diagnosticExclusionGate") 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 [])
    evidence_refs = "".join(
        f"<li><code>{esc(ref.get('path'))}</code>: {esc(', '.join(ref.get('fields') or []))}</li>"
        for ref in summary.get("evidenceRefs") 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 [])
    return "\n".join([
        "<!doctype html>",
        '<html lang="en">',
        "<head>",
        '  <meta charset="utf-8">',
        '  <meta name="viewport" content="width=device-width, initial-scale=1">',
        "  <title>Selected Root Execution 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>Selected Root Execution External Proof Packet</h1>",
        f"  <p>route <code>{esc(summary['source'])}</code> -&gt; <code>{esc(summary['target'])}</code>; "
        f"current selector <code>{esc(summary.get('currentSelector'))}</code>; current root "
        f"<code>{esc(summary.get('currentRootHex'))}</code>; selected-root execution ref found "
        f"{esc(summary.get('selectedRootExecutionRefFound'))}.</p>",
        f"  <p>proof found {esc(summary.get('proofFound'))}; "
        f"selectedRootExternalProofFound {esc(summary.get('selectedRootExternalProofFound'))}; "
        "failed selected-root external gates "
        f"<code>{esc(', '.join(summary.get('failedSelectedRootExternalGateIds') or []))}</code>; "
        f"missing evidence count <code>{esc(len(summary.get('missingEvidence') or []))}</code>; "
        f"evidence refs <code>{esc(summary.get('evidenceRefCount'))}</code>.</p>",
        f"  <p>rejection <code>{esc(summary.get('selectedRootExecutionRejectionClassification'))}</code>.</p>",
        "  <h2>Subgates</h2>",
        "  <table><thead><tr><th>gate</th><th>status</th><th>evidence</th><th>impact</th></tr></thead>",
        f"  <tbody>{subgate_rows}</tbody></table>",
        "  <h2>Route-Pair Entry Selection</h2>",
        f"  <p>entry indices <code>{esc(route_pair.get('routePairEntryIndices'))}</code>; "
        f"negative reader indices <code>{esc(route_pair.get('negativeReaderEntryIndices'))}</code>; "
        f"corrected trace normal selection gap {esc(route_pair.get('correctedTraceNormalSelectionGapFound'))}; "
        f"route-pair execution proven {esc(route_pair.get('routePairEntryExecutionProven'))}.</p>",
        "  <h2>Wrapper Execution</h2>",
        f"  <p>wrapper entry <code>{esc(wrapper.get('wrapperEntryHex'))}</code>; descriptor "
        f"<code>{esc(wrapper.get('wrapperDescriptorHex'))}</code>; child "
        f"<code>{esc(wrapper.get('wrapperChildPointerHex'))}</code>; proof "
        f"{esc(wrapper.get('wrapperExecutionProofFound'))}.</p>",
        "  <h2>Diagnostic Exclusion</h2>",
        f"  <p>diagnostic route observed {esc(diagnostic.get('branchStateReachedRouteSelector'))}; "
        f"excluded from proof {esc(diagnostic.get('excludedFromSelectedRootExecutionProof'))}; "
        f"left stability reproducibility {esc(diagnostic.get('leftStabilityRouteHitReproducibility'))}; "
        f"left recheck route hits {esc(diagnostic.get('leftStabilityRecheckRouteSelectorHitCount'))}; "
        f"left active-order recheck route hits {esc(diagnostic.get('leftActiveOrderRecheckRouteSelectorHitCount'))}.</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>Evidence Refs</h2>",
        f"  <ul>{evidence_refs}</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, md_out: Path | None = None) -> None:
    out_dir.mkdir(parents=True, exist_ok=True)
    (out_dir / "selected_root_execution_external_proof_packet.json").write_text(
        json.dumps(summary, ensure_ascii=False, indent=2) + "\n",
        encoding="utf-8",
    )
    if md_out is not None:
        md_out.write_text(markdown(summary), encoding="utf-8")
    (out_dir / "selected_root_execution_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)
    parser.add_argument("--md-out", type=Path, help="Optional legacy markdown output path.")
    args = parser.parse_args()
    summary = build_summary(args.out_dir)
    write_outputs(summary, args.out_dir, args.md_out)
    print(
        "wrote selected root execution external proof packet -> "
        f"{args.out_dir / 'selected_root_execution_external_proof_packet.html'}"
    )


if __name__ == "__main__":
    main()
