#!/usr/bin/env python3
"""Summarize runtime opcode24 flag/source observations across route probes."""
from __future__ import annotations

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


ROOT = Path(__file__).resolve().parents[1]
OUT = ROOT / "out"

INPUTS = [
    {
        "key": "routeWatch",
        "source": "runtime_route_watch_values_poll",
        "path": OUT / "runtime_route_watch_values_poll.json",
        "kind": "menu route-watch poll",
        "constructedDiagnostic": False,
    },
    {
        "key": "sourceAdaptive",
        "source": "runtime_selected_pointer_source_exit_adaptive_coordinate_poll",
        "path": OUT / "runtime_selected_pointer_source_exit_adaptive_coordinate_poll.json",
        "kind": "public source-save camera-start adaptive exit",
        "constructedDiagnostic": False,
    },
    {
        "key": "sourceTrailStart",
        "source": "runtime_selected_pointer_source_exit_adaptive_trail_start_poll",
        "path": OUT / "runtime_selected_pointer_source_exit_adaptive_trail_start_poll.json",
        "kind": "public source-save trail-start adaptive exit",
        "constructedDiagnostic": False,
    },
    {
        "key": "sourceExitLoadConfirmed",
        "source": "runtime_selected_pointer_source_exit_branch_state_load_confirmed_poll",
        "path": OUT / "runtime_selected_pointer_source_exit_branch_state_load_confirmed_poll.json",
        "kind": "public source-save load-confirmed exit paths",
        "constructedDiagnostic": False,
    },
    {
        "key": "predecessorDirectionSweep",
        "source": "runtime_selected_pointer_predecessor_direction_sweep_poll",
        "path": OUT / "runtime_selected_pointer_predecessor_direction_sweep_poll.json",
        "kind": "public predecessor direction sweep",
        "constructedDiagnostic": False,
    },
    {
        "key": "predecessorLeftActivation",
        "source": "runtime_selected_pointer_predecessor_left_overrun_activation_sweep_poll",
        "path": OUT / "runtime_selected_pointer_predecessor_left_overrun_activation_sweep_poll.json",
        "kind": "public predecessor left-overrun activation sweep",
        "constructedDiagnostic": False,
    },
    {
        "key": "patchedSelectorDiagnostic",
        "source": "runtime_selected_pointer_patched_public_selector_2_0_input_path_case_alias_poll",
        "path": OUT / "runtime_selected_pointer_patched_public_selector_2_0_input_path_case_alias_poll.json",
        "kind": "constructed selector 2:0 diagnostic",
        "constructedDiagnostic": True,
    },
]

WATCH_KEYS = [
    "opcode24Mode1Source",
    "opcode24RuntimeFlag",
    "opcode24CurrentObjectIndex",
]

RUNTIME_OPCODE24_FLAG_FAILED_GATE_IDS = [
    "mode1-source-runtime-producer",
    "runtime-flag-route-context",
    "selected-root-execution-proof",
    "source-save-route-promotion-evidence",
    "strict-hotspot-or-equivalent-runtime-trigger",
]
RUNTIME_OPCODE24_FLAG_MISSING_EVIDENCE = [
    "runtime producer setting opcode24 mode1 source 0x0059e348 nonzero on the route path",
    "runtime flag 0x0059e34d == 0x01 observed in a selector 2:0/current-root route context",
    "selected-root execution proof for 0x00540714 before opcode24 route use",
    "source-save load path reaching route/current selector instead of diversion 48:13",
    "strict map1_01a hotspot or equivalent runtime trigger",
]
RUNTIME_OPCODE24_FLAG_EVIDENCE_REFS = [
    {
        "path": "out/runtime_route_watch_values_poll.json",
        "fields": ["observedSelectors", "observedWatchValues", "sampleCount"],
    },
    {
        "path": "out/runtime_selected_pointer_source_exit_branch_state_load_confirmed_poll.json",
        "fields": ["observedSelectors", "observedWatchValues", "sampleCount"],
    },
    {
        "path": "out/runtime_selected_pointer_predecessor_direction_sweep_poll.json",
        "fields": ["observedSelectors", "observedWatchValues", "sampleCount"],
    },
    {
        "path": "out/runtime_selected_pointer_patched_public_selector_2_0_input_path_case_alias_poll.json",
        "fields": [
            "observedSelectors",
            "observedWatchValues",
            "anyReachedRouteSelectorContext",
        ],
    },
    {
        "path": "out/runtime_source_save_load_variant_context.json",
        "fields": [
            "classification",
            "readyPathSummary",
            "diversionSelectorContext",
            "routePromotionEvidenceFound",
        ],
    },
    {
        "path": "out/save_selector_opcode24_mode1_runtime_context.json",
        "fields": [
            "proofFound",
            "failedOpcode24RuntimeProducerGateIds",
            "missingEvidence",
            "evidenceRefs",
        ],
    },
    {
        "path": "out/save_selector_opcode24_runtime_enabled_context.json",
        "fields": [
            "proofFound",
            "failedOpcode24RuntimeEnabledGateIds",
            "missingEvidence",
            "evidenceRefs",
        ],
    },
]


def load_json(path: Path) -> dict[str, Any]:
    if not path.exists():
        return {}
    return json.loads(path.read_text(encoding="utf-8"))


def list_text(values: list[Any] | None) -> str:
    return ",".join(str(value) for value in values or []) or "-"


def value_rows_text(rows: list[dict[str, Any]] | None) -> str:
    return ",".join(f"{row.get('valueHex')}x{row.get('count')}" for row in rows or []) or "-"


def value_rows_nonzero(rows: list[dict[str, Any]] | None) -> bool:
    return any(row.get("valueHex") not in {None, "0x00", "0x0000", "0x00000000"} for row in rows or [])


def count_value(rows: list[dict[str, Any]] | None, value_hex: str) -> int:
    return sum(int(row.get("count") or 0) for row in rows or [] if row.get("valueHex") == value_hex)


def aggregate_watch_values(data: dict[str, Any], key: str) -> list[dict[str, Any]]:
    top = (data.get("observedWatchValues") or {}).get(key)
    if top is not None:
        return top
    counts: dict[str, int] = {}
    for row in data.get("rows") or []:
        for value_row in ((row.get("uniqueWatchValues") or {}).get(key) or []):
            value_hex = value_row.get("valueHex")
            if value_hex is None:
                continue
            counts[value_hex] = counts.get(value_hex, 0) + int(value_row.get("count") or 0)
    return [
        {"valueHex": value_hex, "count": count}
        for value_hex, count in sorted(counts.items(), key=lambda item: (-item[1], item[0]))
    ]


def selector_list(row: dict[str, Any]) -> list[str]:
    selectors = []
    for item in row.get("uniqueSelectorContexts") or []:
        selector = item.get("selector") if isinstance(item, dict) else str(item)
        if selector:
            selectors.append(selector)
    return selectors


def compact_rows(data: dict[str, Any]) -> list[dict[str, Any]]:
    rows = []
    for row in data.get("rows") or []:
        watch_values = row.get("uniqueWatchValues") or {}
        rows.append({
            "name": row.get("name"),
            "sampleCount": row.get("sampleCount"),
            "selectors": selector_list(row),
            "sourceReady": row.get("sourceReady"),
            "routeSelectorHitCount": row.get("routeSelectorHitCount"),
            "currentRootHitCount": row.get("currentRootHitCount"),
            "mode1SourceValues": watch_values.get("opcode24Mode1Source") or [],
            "runtimeFlagValues": watch_values.get("opcode24RuntimeFlag") or [],
            "currentObjectIndexValues": watch_values.get("opcode24CurrentObjectIndex") or [],
        })
    return rows


def summarize_poll(config: dict[str, Any], data: dict[str, Any]) -> dict[str, Any]:
    watches = {key: aggregate_watch_values(data, key) for key in WATCH_KEYS}
    runtime_flag_one_count = count_value(watches["opcode24RuntimeFlag"], "0x01")
    return {
        "key": config["key"],
        "source": config["source"],
        "kind": config["kind"],
        "constructedDiagnostic": config["constructedDiagnostic"],
        "sampleCount": data.get("sampleCount"),
        "sequenceCount": data.get("sequenceCount"),
        "observedSelectors": data.get("observedSelectors") or [],
        "sourceReadyCount": data.get("sourceReadyCount"),
        "anyReachedRouteSelectorContext": bool(data.get("anyReachedRouteSelectorContext")),
        "anyReachedCurrentRoot": bool(data.get("anyReachedCurrentRoot")),
        "mode1SourceValues": watches["opcode24Mode1Source"],
        "runtimeFlagValues": watches["opcode24RuntimeFlag"],
        "currentObjectIndexValues": watches["opcode24CurrentObjectIndex"],
        "mode1SourceNonzeroObserved": value_rows_nonzero(watches["opcode24Mode1Source"]),
        "runtimeFlagNonzeroObserved": value_rows_nonzero(watches["opcode24RuntimeFlag"]),
        "runtimeFlagOneCount": runtime_flag_one_count,
        "currentObjectIndexNonzeroObserved": value_rows_nonzero(watches["opcode24CurrentObjectIndex"]),
        "rows": compact_rows(data),
    }


def build_source_save_load_context(context: dict[str, Any] | None) -> dict[str, Any]:
    context = context or {}
    if not context:
        return {"available": False}
    ready = context.get("readyPathSummary") or {}
    diversion = context.get("diversionSelectorContext") or {}
    return {
        "available": True,
        "sourceArtifact": "runtime_source_save_load_variant_context.json",
        "classification": context.get("classification"),
        "promotionStatus": context.get("promotionStatus"),
        "strictSourceHotspotProofFound": context.get("strictSourceHotspotProofFound"),
        "selectedRootExecutionProofFound": context.get("selectedRootExecutionProofFound"),
        "routePromotionEvidenceFound": context.get("routePromotionEvidenceFound"),
        "readyPathDiversionClassification": ready.get("diversionClassification"),
        "readyPathCount": ready.get("readyPathCount"),
        "readyPathRouteOrCurrentCount": ready.get("routeOrCurrentReadyPathCount"),
        "readyPathCandidateOrOutsideCount": ready.get("candidateOrOutsideReadyPathCount"),
        "readyPathDominantNonRouteSelector": ready.get("dominantNonRouteSelector"),
        "diversionSelector": diversion.get("selector"),
        "diversionFieldMaps": diversion.get("fieldMaps") or [],
        "diversionClassification": diversion.get("classification"),
        "diversionSelectorInRoutePair": diversion.get("selectorInRoutePair"),
        "diversionContainsSourceMap": diversion.get("containsSourceMap"),
        "diversionContainsTargetMap": diversion.get("containsTargetMap"),
        "diversionSceneAdjacencyRowCount": diversion.get("sceneAdjacencyRowCount"),
        "diversionSceneAdjacencySelectorOnlyPairCount": diversion.get(
            "sceneAdjacencySelectorOnlyPairCount"
        ),
        "diversionSceneAdjacencyStrictEventBackedCount": diversion.get(
            "sceneAdjacencyStrictEventBackedCount"
        ),
        "diversionSceneAdjacencyConfirmedReviewBackedCount": diversion.get(
            "sceneAdjacencyConfirmedReviewBackedCount"
        ),
        "diversionSelectedPointerRootHex": (diversion.get("selectedPointerPath") or {}).get(
            "rootHex"
        ),
        "diversionSelectedPointerCurrentProofCount": diversion.get(
            "selectedPointerPathSelectsOrStoresCurrentCount"
        ),
        "diversionSelectedRootExecutionRefFound": diversion.get("selectedRootExecutionRefFound"),
        "diversionRoutePromotionEvidenceFound": diversion.get("routePromotionEvidenceFound"),
    }


def build_summary(
    inputs: list[dict[str, Any]] | None = None,
    source_save_load_variant_context: dict[str, Any] | None = None,
) -> dict[str, Any]:
    configs = inputs or INPUTS
    source_save_load_variant_context = (
        source_save_load_variant_context
        if source_save_load_variant_context is not None
        else load_json(OUT / "runtime_source_save_load_variant_context.json")
    )
    polls = [
        summarize_poll(config, load_json(config["path"]))
        for config in configs
        if config["path"].exists()
    ]
    source_save_context = build_source_save_load_context(source_save_load_variant_context)
    real_polls = [poll for poll in polls if not poll.get("constructedDiagnostic")]
    real_route_hit = any(
        poll.get("anyReachedRouteSelectorContext") or poll.get("anyReachedCurrentRoot")
        for poll in real_polls
    )
    constructed_route_hit = any(
        (poll.get("anyReachedRouteSelectorContext") or poll.get("anyReachedCurrentRoot"))
        and poll.get("constructedDiagnostic")
        for poll in polls
    )
    mode1_nonzero = any(poll.get("mode1SourceNonzeroObserved") for poll in polls)
    flag_nonzero = any(poll.get("runtimeFlagNonzeroObserved") for poll in polls)
    flag_one_count = sum(int(poll.get("runtimeFlagOneCount") or 0) for poll in polls)
    if real_route_hit:
        classification = "real-route-observed"
    elif mode1_nonzero:
        classification = "mode1-source-nonzero-observed"
    elif flag_nonzero:
        classification = "runtime-flag-nonroute-mode1-zero"
    else:
        classification = "opcode24-watch-all-zero"
    proof_found = classification == "real-route-observed"
    conclusion = (
        "Runtime opcode24 watch samples do not provide selected-root execution proof. The runtime flag reaches "
        "0x01 only in the menu route-watch poll, where selectors are 8:0/50:0 and opcode24 mode1 source plus "
        "current object index stay 0x00. Public source/predecessor probes, including the load-confirmed "
        "source-exit paths, and the constructed selector 2:0 diagnostic also keep opcode24 mode1 source at "
        "0x00. The source-save load context also diverts through a non-route selector before exit candidates. "
        "The next useful proof target remains a real runtime producer for 0x0059e348 or a strict map1_01a hotspot."
    )
    return {
        "source": "map1_01a",
        "target": "map2_02d",
        "classification": classification,
        "promotionStatus": "blocked" if classification != "real-route-observed" else "candidate",
        "proofFound": proof_found,
        "runtimeOpcode24FlagProofFound": proof_found,
        "failedRuntimeOpcode24FlagGateIds": (
            [] if proof_found else RUNTIME_OPCODE24_FLAG_FAILED_GATE_IDS
        ),
        "missingEvidence": [] if proof_found else RUNTIME_OPCODE24_FLAG_MISSING_EVIDENCE,
        "evidenceRefs": RUNTIME_OPCODE24_FLAG_EVIDENCE_REFS,
        "evidenceRefCount": len(RUNTIME_OPCODE24_FLAG_EVIDENCE_REFS),
        "pollCount": len(polls),
        "realRouteHitObserved": real_route_hit,
        "constructedRouteHitObserved": constructed_route_hit,
        "mode1SourceNonzeroObserved": mode1_nonzero,
        "runtimeFlagNonzeroObserved": flag_nonzero,
        "runtimeFlagOneCount": flag_one_count,
        "currentObjectIndexNonzeroObserved": any(poll.get("currentObjectIndexNonzeroObserved") for poll in polls),
        "selectedRootExecutionProofFound": real_route_hit,
        "routePromotionEvidenceFound": real_route_hit,
        "sourceSaveLoadContext": source_save_context,
        "sourceSaveLoadClassification": source_save_context.get("classification"),
        "sourceSaveLoadPromotionStatus": source_save_context.get("promotionStatus"),
        "sourceSaveLoadReadyPathDiversionClassification": source_save_context.get(
            "readyPathDiversionClassification"
        ),
        "sourceSaveLoadReadyPathCount": source_save_context.get("readyPathCount"),
        "sourceSaveLoadReadyPathRouteOrCurrentCount": source_save_context.get(
            "readyPathRouteOrCurrentCount"
        ),
        "sourceSaveLoadReadyPathCandidateOrOutsideCount": source_save_context.get(
            "readyPathCandidateOrOutsideCount"
        ),
        "sourceSaveLoadReadyPathDominantNonRouteSelector": source_save_context.get(
            "readyPathDominantNonRouteSelector"
        ),
        "sourceSaveLoadDiversionClassification": source_save_context.get(
            "diversionClassification"
        ),
        "sourceSaveLoadDiversionSelector": source_save_context.get("diversionSelector"),
        "sourceSaveLoadDiversionFieldMaps": source_save_context.get("diversionFieldMaps") or [],
        "sourceSaveLoadDiversionSelectedPointerCurrentProofCount": source_save_context.get(
            "diversionSelectedPointerCurrentProofCount"
        ),
        "sourceSaveLoadDiversionRoutePromotionEvidenceFound": source_save_context.get(
            "diversionRoutePromotionEvidenceFound"
        ),
        "sourceSaveLoadRoutePromotionEvidenceFound": source_save_context.get(
            "routePromotionEvidenceFound"
        ),
        "polls": polls,
        "conclusion": conclusion,
    }


def markdown(summary: dict[str, Any]) -> str:
    lines = [
        "# Runtime Opcode24 Flag Context",
        "",
        f"- route: `{summary.get('source')}` -> `{summary.get('target')}`",
        f"- classification: `{summary.get('classification')}`",
        f"- promotion status: `{summary.get('promotionStatus')}`",
        f"- poll count: {summary.get('pollCount')}",
        f"- runtime flag nonzero observed: {summary.get('runtimeFlagNonzeroObserved')} (`0x01` samples: {summary.get('runtimeFlagOneCount')})",
        f"- mode1 source nonzero observed: {summary.get('mode1SourceNonzeroObserved')}",
        f"- current object index nonzero observed: {summary.get('currentObjectIndexNonzeroObserved')}",
        f"- real route/current observed: {summary.get('realRouteHitObserved')}",
        f"- constructed route/current observed: {summary.get('constructedRouteHitObserved')}",
        f"- source-save load classification: `{summary.get('sourceSaveLoadClassification')}`",
        f"- source-save ready diversion: `{summary.get('sourceSaveLoadReadyPathDiversionClassification')}`",
        f"- source-save diversion: `{summary.get('sourceSaveLoadDiversionSelector')}` "
        f"({list_text(summary.get('sourceSaveLoadDiversionFieldMaps'))})",
        f"- source-save ready paths route/current/candidate counts: "
        f"{summary.get('sourceSaveLoadReadyPathCount')} / "
        f"{summary.get('sourceSaveLoadReadyPathRouteOrCurrentCount')} / "
        f"{summary.get('sourceSaveLoadReadyPathCandidateOrOutsideCount')}",
        f"- source-save diversion current proof count: "
        f"{summary.get('sourceSaveLoadDiversionSelectedPointerCurrentProofCount')}",
        f"- source-save route promotion evidence: "
        f"{summary.get('sourceSaveLoadRoutePromotionEvidenceFound')}",
        f"- proof found: {summary.get('proofFound')}",
        f"- runtime opcode24 flag proof found: {summary.get('runtimeOpcode24FlagProofFound')}",
        f"- failed runtime opcode24 flag gates: `{','.join(summary.get('failedRuntimeOpcode24FlagGateIds') or [])}`",
        f"- missing evidence count: {len(summary.get('missingEvidence') or [])}",
        f"- evidence refs: {summary.get('evidenceRefCount')}",
        "",
        summary.get("conclusion") or "",
        "",
        "## Missing Evidence",
        "",
        *[f"- {item}" for item in summary.get("missingEvidence") or []],
        "",
        "## Evidence Refs",
        "",
        "| path | fields |",
        "| --- | --- |",
        *[
            f"| `{row.get('path')}` | {', '.join(row.get('fields') or []) or '-'} |"
            for row in summary.get("evidenceRefs") or []
        ],
        "",
        "| poll | samples | selectors | route/current | mode1 source | runtime flag | current object | note |",
        "| --- | ---: | --- | --- | --- | --- | --- | --- |",
    ]
    for poll in summary.get("polls") or []:
        note = "constructed diagnostic" if poll.get("constructedDiagnostic") else poll.get("kind")
        lines.append(
            f"| `{poll.get('source')}` | {poll.get('sampleCount')} | `{list_text(poll.get('observedSelectors'))}` | "
            f"{poll.get('anyReachedRouteSelectorContext')}/{poll.get('anyReachedCurrentRoot')} | "
            f"`{value_rows_text(poll.get('mode1SourceValues'))}` | "
            f"`{value_rows_text(poll.get('runtimeFlagValues'))}` | "
            f"`{value_rows_text(poll.get('currentObjectIndexValues'))}` | {note} |"
        )
    lines.extend([
        "",
        "## Rows",
        "",
        "| poll | row | source ready | samples | selectors | route/current | mode1 source | runtime flag | current object |",
        "| --- | --- | --- | ---: | --- | --- | --- | --- | --- |",
    ])
    for poll in summary.get("polls") or []:
        for row in poll.get("rows") or []:
            lines.append(
                f"| `{poll.get('source')}` | `{row.get('name')}` | {row.get('sourceReady')} | "
                f"{row.get('sampleCount')} | `{list_text(row.get('selectors'))}` | "
                f"{row.get('routeSelectorHitCount')}/{row.get('currentRootHitCount')} | "
                f"`{value_rows_text(row.get('mode1SourceValues'))}` | "
                f"`{value_rows_text(row.get('runtimeFlagValues'))}` | "
                f"`{value_rows_text(row.get('currentObjectIndexValues'))}` |"
            )
    return "\n".join(lines) + "\n"


def html_page(summary: dict[str, Any]) -> str:
    return (
        "<!doctype html><meta charset=\"utf-8\"><title>Runtime Opcode24 Flag Context</title>"
        "<style>body{font-family:sans-serif;line-height:1.4}table{border-collapse:collapse}"
        "td,th{border:1px solid #ccc;padding:4px 6px}code{background:#f3f3f3;padding:1px 3px}</style>"
        f"<pre>{html.escape(markdown(summary))}</pre>"
    )


def write_outputs(
    summary: dict[str, Any],
    out_dir: Path = OUT,
    html_out: Path | None = None,
) -> Path:
    json_out = out_dir / "runtime_opcode24_flag_context.json"
    json_out.write_text(
        json.dumps(summary, ensure_ascii=False, indent=2) + "\n",
        encoding="utf-8",
    )
    if html_out is not None:
        html_out.write_text(html_page(summary), encoding="utf-8")
    return json_out


def main() -> None:
    parser = argparse.ArgumentParser(
        description="Summarize runtime opcode24 flag/source observations."
    )
    parser.add_argument("--out-dir", type=Path, default=OUT)
    parser.add_argument(
        "--html-out",
        type=Path,
        default=None,
        help="Optional HTML mirror. Omit to keep the active surface JSON-only.",
    )
    args = parser.parse_args()
    summary = build_summary()
    json_out = write_outputs(summary, args.out_dir, args.html_out)
    print(f"wrote runtime opcode24 flag context -> {json_out}")


if __name__ == "__main__":
    main()
