#!/usr/bin/env python3
"""Fail-closed evaluation of one long warm-worker real-time envelope run."""

from __future__ import annotations

import argparse
import hashlib
import json
import math
import os
import statistics
import uuid
from collections.abc import Iterable
from datetime import UTC, datetime
from pathlib import Path
from typing import Any

PROFILE_SCHEMA = "missioncore.e21-realtime-envelope-profile/v1"
REPORT_SCHEMA = "missioncore.e21-realtime-envelope-report/v1"
RESULT_SCHEMA = "missioncore.e21-realtime-envelope-result/v1"
SOURCE_SCHEMA = "missioncore.e21-replay-source-report/v1"
WORKER_REPORT_SCHEMA = "missioncore.e15-shadow-inference-report/v1"
WORKER_RESULT_SCHEMA = "missioncore.e15-shadow-inference-result/v1"


def _canonical(value: object) -> bytes:
    return json.dumps(
        value,
        sort_keys=True,
        separators=(",", ":"),
        allow_nan=False,
    ).encode()


def _sha256(path: Path) -> str:
    digest = hashlib.sha256()
    with path.open("rb") as stream:
        for block in iter(lambda: stream.read(1024 * 1024), b""):
            digest.update(block)
    return digest.hexdigest()


def _read_object(path: Path) -> dict[str, Any]:
    value = json.loads(path.read_text(encoding="utf-8-sig"))
    if not isinstance(value, dict):
        raise RuntimeError(f"JSON root is not an object: {path}")
    return value


def _percentiles(values: Iterable[float]) -> dict[str, float | int]:
    normalized = [float(value) for value in values if math.isfinite(float(value))]
    if not normalized:
        return {
            "count": 0,
            "mean": 0.0,
            "p50": 0.0,
            "p95": 0.0,
            "p99": 0.0,
            "max": 0.0,
        }
    ordered = sorted(normalized)

    def percentile(fraction: float) -> float:
        index = min(len(ordered) - 1, max(0, round((len(ordered) - 1) * fraction)))
        return round(ordered[index], 6)

    return {
        "count": len(ordered),
        "mean": round(statistics.fmean(ordered), 6),
        "p50": percentile(0.50),
        "p95": percentile(0.95),
        "p99": percentile(0.99),
        "max": round(max(ordered), 6),
    }


def _trend(samples: list[tuple[float, float]]) -> dict[str, Any]:
    if len(samples) < 4:
        return {
            "sample_count": len(samples),
            "slope_per_second": 0.0,
            "early": _percentiles(value for _, value in samples),
            "late": _percentiles(value for _, value in samples),
            "late_vs_early_p95": 0.0,
        }
    ordered = sorted(samples)
    count = len(ordered)
    quarter = max(1, count // 4)
    early = _percentiles(value for _, value in ordered[:quarter])
    late = _percentiles(value for _, value in ordered[-quarter:])
    x_mean = statistics.fmean(value[0] for value in ordered)
    y_mean = statistics.fmean(value[1] for value in ordered)
    denominator = sum((x - x_mean) ** 2 for x, _ in ordered)
    slope = (
        sum((x - x_mean) * (y - y_mean) for x, y in ordered) / denominator
        if denominator > 0
        else 0.0
    )
    return {
        "sample_count": count,
        "slope_per_second": round(slope, 6),
        "early": early,
        "late": late,
        "late_vs_early_p95": round(float(late["p95"]) - float(early["p95"]), 6),
    }


def _read_jsonl(path: Path, *, maximum_line_bytes: int = 4 * 1024 * 1024) -> list[Any]:
    values: list[Any] = []
    with path.open("rb") as stream:
        for line in stream:
            if len(line) > maximum_line_bytes:
                raise RuntimeError(f"JSONL line exceeds its bound: {path}")
            value = json.loads(line)
            values.append(value)
    return values


def _validate_profile(path: Path) -> tuple[dict[str, Any], str]:
    profile = _read_object(path.resolve(strict=True))
    source = profile.get("source")
    worker = profile.get("worker")
    authority = profile.get("authority")
    if (
        profile.get("schema_version") != PROFILE_SCHEMA
        or profile.get("mode") != "steady-state-baseline"
        or not isinstance(source, dict)
        or not isinstance(worker, dict)
        or authority
        != {
            "commands_enabled": False,
            "navigation_or_safety_accepted": False,
        }
        or float(source.get("speed", 0)) != 1.0
        or float(source.get("minimum_span_seconds", 0)) < 10
        or float(source.get("maximum_wall_over_ideal", 0)) < 1
        or float(worker.get("maximum_p95_world_state_age_ms", 0)) <= 0
        or float(worker.get("maximum_p99_world_state_age_ms", 0)) <= 0
        or int(worker.get("minimum_runtime_telemetry_samples", 0)) < 2
        or int(worker.get("minimum_gpu_telemetry_samples", 0)) < 2
    ):
        raise RuntimeError("LAB E21 profile contract is invalid")
    return profile, _sha256(path)


def _artifact_map(root: Path, result: dict[str, Any]) -> dict[str, Path]:
    artifacts = result.get("artifacts")
    if not isinstance(artifacts, list):
        raise RuntimeError("worker result artifacts are missing")
    validated: dict[str, Path] = {}
    for artifact in artifacts:
        if not isinstance(artifact, dict):
            raise RuntimeError("worker result artifact is invalid")
        kind = artifact.get("kind")
        relative = artifact.get("path")
        if not isinstance(kind, str) or not isinstance(relative, str) or kind in validated:
            raise RuntimeError("worker result artifact identity is invalid")
        path = (root / relative).resolve(strict=True)
        if (
            path.parent != root
            or path.is_symlink()
            or artifact.get("byte_length") != path.stat().st_size
            or artifact.get("sha256") != _sha256(path)
        ):
            raise RuntimeError("worker result artifact integrity failed")
        validated[kind] = path
    return validated


def _all_queues_bounded(source: dict[str, Any], worker: dict[str, Any]) -> bool:
    ingress = source.get("ingress", {})
    source_queues = ingress.get("queues", {}) if isinstance(ingress, dict) else {}
    if not isinstance(source_queues, dict) or not source_queues:
        return False
    for value in source_queues.values():
        if (
            not isinstance(value, dict)
            or int(value.get("maximum_depth", -1)) > int(value.get("capacity", -2))
            or int(value.get("depth", -1)) != 0
        ):
            return False
    metrics = worker.get("metrics", {})
    detector = metrics.get("detector", {}) if isinstance(metrics, dict) else {}
    semantic = metrics.get("semantic", {}) if isinstance(metrics, dict) else {}
    for value in (detector.get("queue"), semantic.get("queue")):
        if (
            not isinstance(value, dict)
            or int(value.get("maximum_depth", -1)) > int(value.get("capacity", -2))
            or int(value.get("final_depth", -1)) != 0
        ):
            return False
    return True


def evaluate(
    *,
    source_report_path: Path,
    worker_result_root: Path,
    profile_path: Path,
) -> dict[str, Any]:
    source_path = source_report_path.resolve(strict=True)
    worker_root = worker_result_root.resolve(strict=True)
    profile, profile_sha256 = _validate_profile(profile_path)
    source = _read_object(source_path)
    result = _read_object(worker_root / "result.json")
    worker = _read_object(worker_root / "run-report.json")
    if (
        source.get("schema_version") != SOURCE_SCHEMA
        or source.get("state") != "completed"
        or result.get("schema_version") != WORKER_RESULT_SCHEMA
        or worker.get("schema_version") != WORKER_REPORT_SCHEMA
        or result.get("result_id") != worker.get("result_id")
    ):
        raise RuntimeError("LAB E21 source/worker contract is incompatible")
    artifacts = _artifact_map(worker_root, result)
    world_path = artifacts.get("e15-world-state")
    runtime_path = artifacts.get("worker-runtime-telemetry")
    if world_path is None or runtime_path is None:
        raise RuntimeError("LAB E21 telemetry artifacts are incomplete")
    world_rows = _read_jsonl(world_path)
    runtime_rows = _read_jsonl(runtime_path, maximum_line_bytes=512 * 1024)
    age_samples: list[tuple[float, float]] = []
    for row in world_rows:
        if not isinstance(row, dict) or not isinstance(row.get("delivery"), dict):
            raise RuntimeError("LAB E21 world-state row is invalid")
        session_seconds = row.get("session_seconds")
        result_age_ms = row["delivery"].get("result_age_ms")
        if not isinstance(session_seconds, int | float) or not isinstance(
            result_age_ms, int | float
        ):
            raise RuntimeError("LAB E21 world-state timing is invalid")
        age_samples.append((float(session_seconds), float(result_age_ms)))
    rss_samples: list[tuple[float, float]] = []
    for row in runtime_rows:
        if (
            not isinstance(row, dict)
            or row.get("schema_version") != "missioncore.worker-runtime-telemetry/v1"
            or not isinstance(row.get("elapsed_seconds"), int | float)
            or not isinstance(row.get("process_rss_mib"), int | float)
        ):
            raise RuntimeError("LAB E21 runtime telemetry row is invalid")
        rss_samples.append(
            (float(row["elapsed_seconds"]), float(row["process_rss_mib"]))
        )
    age_trend = _trend(age_samples)
    rss_trend = _trend(rss_samples)
    source_policy = profile["source"]
    worker_policy = profile["worker"]
    source_descriptor = source["source"]
    source_pacing = source["pacing"]
    source_queues = source["ingress"]["queues"]
    metrics = worker["metrics"]
    detector = metrics["detector"]
    semantic = metrics["semantic"]
    fusion = metrics["fusion"]
    transport = metrics["transport"]
    latency = metrics["latency_ms"]["world_state_age_ms"]
    gpu = metrics["gpu_telemetry"]
    source_drop_total = sum(
        int(queue["dropped_overflow"]) + int(queue["rejected_oversize"])
        for queue in source_queues.values()
    )
    detector_published = int(detector["queue"]["published"])
    semantic_published = int(semantic["queue"]["published"])
    result_attempted = int(transport["results_published"]) + int(
        transport["results_dropped"]
    )
    diagnostic_results = source.get("diagnostic_results")
    if not isinstance(diagnostic_results, dict) or not isinstance(
        diagnostic_results.get("queue"), dict
    ):
        raise RuntimeError("LAB E21 diagnostic result sink is missing")
    result_sink_queue = diagnostic_results["queue"]
    worker_acceptance_checks = worker["acceptance"]["checks"]
    superseded_worker_checks = {"detector_maximum_drop_fraction"}
    checks = {
        "source_identity": source_descriptor["session"] == source_policy["session"],
        "source_speed_is_1x": float(source_descriptor["speed"])
        == float(source_policy["speed"]),
        "source_span": float(source_pacing["source_span_seconds"])
        >= float(source_policy["minimum_span_seconds"]),
        "source_wall_over_ideal": float(source_pacing["wall_over_ideal"])
        <= float(source_policy["maximum_wall_over_ideal"]),
        "source_release_lag": float(source_pacing["release_lag_ms"]["p95"])
        <= float(source_policy["maximum_p95_release_lag_ms"]),
        "source_streams_without_look_ahead": (
            source_descriptor["look_ahead"] is False
            and source_descriptor["payload_loading"] == "streaming-one-event-per-modality"
        ),
        "source_zero_drops": source_drop_total == 0,
        "diagnostic_result_sink_bounded": (
            int(result_sink_queue["maximum_depth"]) <= int(result_sink_queue["capacity"])
            and int(diagnostic_results["received"]) == int(transport["results_published"])
        ),
        "queues_remained_bounded": _all_queues_bounded(source, worker),
        "worker_non_detector_acceptance": all(
            bool(passed)
            for name, passed in worker_acceptance_checks.items()
            if name not in superseded_worker_checks
        ),
        "detector_fps": float(detector["effective_fps"])
        >= float(worker_policy["minimum_detector_fps"]),
        "detector_drop_fraction": int(detector["queue"]["dropped_overflow"])
        / max(1, detector_published)
        <= float(worker_policy["maximum_detector_drop_fraction"]),
        "semantic_fps": float(semantic["effective_fps"])
        >= float(worker_policy["minimum_semantic_fps"]),
        "semantic_drop_fraction": int(semantic["queue"]["dropped_overflow"])
        / max(1, semantic_published)
        <= float(worker_policy["maximum_semantic_drop_fraction"]),
        "fusion_fraction": float(fusion["fused_fraction"])
        >= float(worker_policy["minimum_fused_fraction"]),
        "result_drop_fraction": int(transport["results_dropped"])
        / max(1, result_attempted)
        <= float(worker_policy["maximum_result_drop_fraction"]),
        "world_state_age_p95": float(latency["p95"])
        <= float(worker_policy["maximum_p95_world_state_age_ms"]),
        "world_state_age_p99": float(latency["p99"])
        <= float(worker_policy["maximum_p99_world_state_age_ms"]),
        "world_state_age_does_not_accumulate": (
            float(age_trend["slope_per_second"])
            <= float(worker_policy["maximum_age_slope_ms_per_second"])
            and float(age_trend["late_vs_early_p95"])
            <= float(worker_policy["maximum_late_vs_early_p95_age_growth_ms"])
        ),
        "rss_does_not_accumulate": float(rss_trend["late_vs_early_p95"])
        <= float(worker_policy["maximum_rss_growth_mib"]),
        "runtime_telemetry_coverage": len(runtime_rows)
        >= int(worker_policy["minimum_runtime_telemetry_samples"]),
        "gpu_telemetry_coverage": int(gpu["sample_count"])
        >= int(worker_policy["minimum_gpu_telemetry_samples"]),
        "transport_complete": (
            int(transport["ingress_sequence_gaps"]) == 0
            and int(transport["camera_sequence_gaps"]) == 0
            and transport["session_end_seen"] is True
            and transport["timed_out"] is False
        ),
        "authority_remains_diagnostic": worker["acceptance"]["commands_enabled"] is False
        and worker["acceptance"]["navigation_or_safety_accepted"] is False,
    }
    identity = {
        "schema_version": "missioncore.e21-realtime-envelope-identity/v1",
        "profile_sha256": profile_sha256,
        "source_report_sha256": _sha256(source_path),
        "worker_result_sha256": _sha256(worker_root / "result.json"),
        "source_session_id": source["session_id"],
        "worker_result_id": result["result_id"],
    }
    identity_sha256 = hashlib.sha256(_canonical(identity)).hexdigest()
    return {
        "schema_version": REPORT_SCHEMA,
        "result_id": f"e21-realtime-envelope-{identity_sha256}",
        "created_at_utc": datetime.now(UTC)
        .isoformat(timespec="milliseconds")
        .replace("+00:00", "Z"),
        "state": "accepted" if all(checks.values()) else "rejected",
        "identity": identity,
        "checks": checks,
        "metrics": {
            "source": {
                "pacing": source_pacing,
                "events_selected": source["events_selected"],
                "events_admitted": source["events_admitted"],
                "drop_total": source_drop_total,
                "process": source["process"],
                "diagnostic_results": diagnostic_results,
            },
            "worker": {
                "detector": detector,
                "semantic": semantic,
                "fusion": fusion,
                "transport": transport,
                "world_state_age_ms": latency,
                "world_state_age_trend": age_trend,
                "runtime_telemetry": metrics["runtime_telemetry"],
                "rss_trend": rss_trend,
                "gpu_telemetry": gpu,
                "process_cpu_seconds": metrics["process_cpu_seconds"],
                "process_peak_rss_mib": metrics["process_peak_rss_mib"],
                "cuda_peak_memory_allocated_mib": metrics[
                    "cuda_peak_memory_allocated_mib"
                ],
                "cuda_peak_memory_reserved_mib": metrics[
                    "cuda_peak_memory_reserved_mib"
                ],
                "disk": metrics["disk"],
            },
        },
        "authority": profile["authority"],
        "interpretation": {
            "accepted_scope": "recorded-1x-warm-worker-steady-state-only",
            "physical_k1_live_accepted": False,
            "navigation_or_safety_accepted": False,
        },
    }


def publish(report: dict[str, Any], output_root: Path) -> Path:
    root = output_root.resolve()
    root.mkdir(mode=0o700, parents=True, exist_ok=True)
    destination = root / str(report["result_id"])
    if destination.exists():
        existing = _read_object(destination / "report.json")
        if existing.get("identity") != report.get("identity"):
            raise RuntimeError("existing LAB E21 result identity differs")
        return destination
    staging = root / f".{report['result_id']}.{uuid.uuid4().hex}.tmp"
    staging.mkdir(mode=0o700)
    try:
        report_path = staging / "report.json"
        with report_path.open("x", encoding="utf-8", newline="\n") as stream:
            json.dump(report, stream, indent=2, sort_keys=True)
            stream.write("\n")
            stream.flush()
            os.fsync(stream.fileno())
        result = {
            "schema_version": RESULT_SCHEMA,
            "result_id": report["result_id"],
            "state": report["state"],
            "report": {
                "path": "report.json",
                "byte_length": report_path.stat().st_size,
                "sha256": _sha256(report_path),
                "schema_version": REPORT_SCHEMA,
            },
        }
        with (staging / "result.json").open("x", encoding="utf-8", newline="\n") as stream:
            json.dump(result, stream, indent=2, sort_keys=True)
            stream.write("\n")
            stream.flush()
            os.fsync(stream.fileno())
        staging.replace(destination)
    finally:
        if staging.exists():
            for path in staging.iterdir():
                path.unlink()
            staging.rmdir()
    return destination


def main() -> int:
    root = Path(__file__).resolve().parents[2]
    parser = argparse.ArgumentParser()
    parser.add_argument("--source-report", type=Path, required=True)
    parser.add_argument("--worker-result-root", type=Path, required=True)
    parser.add_argument(
        "--profile",
        type=Path,
        default=Path(__file__).with_name("e21_realtime_envelope_profile.json"),
    )
    parser.add_argument(
        "--output-root",
        type=Path,
        default=root / ".runtime" / "compute-experiments" / "e21" / "results",
    )
    args = parser.parse_args()
    report = evaluate(
        source_report_path=args.source_report,
        worker_result_root=args.worker_result_root,
        profile_path=args.profile,
    )
    destination = publish(report, args.output_root)
    print(
        json.dumps(
            {
                "result_root": str(destination),
                "result_id": report["result_id"],
                "state": report["state"],
                "failed_checks": [
                    name for name, passed in report["checks"].items() if not passed
                ],
            },
            sort_keys=True,
        )
    )
    return 0 if report["state"] == "accepted" else 2


if __name__ == "__main__":
    raise SystemExit(main())
