"""Private synthetic screen of exact repeated edge-objective states."""
from __future__ import annotations

import argparse
from collections import Counter, OrderedDict
from datetime import datetime, timezone
import hashlib
import json
import os
from pathlib import Path
import subprocess
import sys
import time

ROOT = Path(__file__).resolve().parent


def sha(path: Path) -> str:
    return hashlib.sha256(path.read_bytes()).hexdigest()


def worker(args: argparse.Namespace) -> None:
    source = Path(args.source).resolve()
    sys.path.insert(0, str(source / "src"))
    sys.path.insert(1, str(ROOT / "tests/unit"))
    import numpy as np
    import camera_lidar_scene as scene
    from calibrex.core.camera_lidar_edge import CameraLidarEdgeProvenance
    from calibrex.data.ros2_camera_lidar import CameraLidarFrame
    from calibrex.evaluation import camera_lidar_edge as edge

    start = time.perf_counter()
    truth = scene.true_transform()
    frames = []
    inputs = hashlib.sha256()
    for index in range(12):
        rects = scene.make_scene(index)
        image, points = scene.render_image(rects), scene.cast_points(rects, truth)
        inputs.update(image.tobytes())
        inputs.update(points.tobytes())
        frames.append(CameraLidarFrame(
            time_s=float(index), image_time_s=float(index), image=image, points=points,
            cloud_frame_id="lidar", image_frame_id="camera",
        ))
    candidate = scene.perturbed(truth, (0.8, -1.2, 0.0))
    settings = edge.EdgeAlignmentOptions(min_frames=8, blocks=4)
    initializer, scorer = edge.EdgeObjective.__init__, edge.EdgeObjective.score
    counters = Counter()
    calls, unique, caches = {}, {}, {}

    def initialize(self, prepared, camera, initial):
        initializer(self, prepared, camera, initial)
        self._pilot_group = (
            tuple(id(frame) for frame in prepared), camera,
            initial.dtype.str, initial.shape, initial.tobytes(),
        )
        counters["objective_constructions"] += 1

    def score(self, theta):
        group = self._pilot_group
        key = (theta.dtype.str, theta.shape, theta.tobytes())
        counters["score_calls"] += 1
        calls[group] = calls.get(group, 0) + 1
        unique.setdefault(group, set()).add(key)
        cache = caches.setdefault(group, OrderedDict())
        if args.variant == "memo" and key in cache:
            counters["cache_hits"] += 1
            cache.move_to_end(key)
            return cache[key]
        counters["executed_scores"] += 1
        value = scorer(self, theta)
        if args.variant == "memo":
            cache[key] = value
            if len(cache) > 4096:
                cache.popitem(last=False)
        return value

    edge.EdgeObjective.__init__ = initialize
    edge.EdgeObjective.score = score
    artifact = edge.estimate_from_frames(
        frames, edge.EdgeCamera(scene.FOCAL, scene.FOCAL, scene.CX, scene.CY), candidate,
        options=settings,
        provenance=CameraLidarEdgeProvenance(
            generator="edge_objective_reuse_pilot", generator_version="1",
            git_commit=args.commit, command=["synthetic-complete-edge-estimation"],
            dataset_family="synthetic", sequence_ids=["rectangle-scene-12"],
            image_topic="/generated/image", lidar_topic="/generated/points",
            input_sha256=inputs.hexdigest(), input_digest_scope="all image and point bytes",
            dataset_license="repository Apache-2.0 synthetic fixture",
        ),
    )
    api_seconds = time.perf_counter() - start
    output = Path(args.output)
    output.mkdir()
    raw = artifact.model_dump(mode="json")
    (output / "result.json").write_text(
        json.dumps(raw, indent=2, allow_nan=False) + "\n", encoding="utf-8"
    )
    raw["provenance"].pop("created_at")
    canonical = json.dumps(raw, sort_keys=True, separators=(",", ":"), allow_nan=False)
    manifest = json.loads((source / "manifest.json").read_bytes())
    actual = {
        p.relative_to(source / "src").as_posix(): sha(p)
        for p in (source / "src").rglob("*.py")
    }
    assert manifest == actual
    for name, module in list(sys.modules.items()):
        if (name == "calibrex" or name.startswith("calibrex.")) and getattr(module, "__file__", None):
            path = Path(module.__file__).resolve()
            assert path.is_relative_to(source / "src")
            assert sha(path) == manifest[path.relative_to(source / "src").as_posix()]
    result = {
        "variant": args.variant, "api_seconds": api_seconds, "counts": dict(counters),
        "groups": sorted(
            [{"calls": count, "unique": len(unique[group])} for group, count in calls.items()],
            key=lambda item: -item["calls"],
        ),
        "canonical_result_sha256": hashlib.sha256(canonical.encode()).hexdigest(),
        "provenance": {
            "source_commit": args.commit, "source_manifest_sha256": sha(source / "manifest.json"),
            "launcher_sha256": sha(Path(__file__)), "fixture_sha256": sha(Path(scene.__file__)),
            "input_sha256": inputs.hexdigest(), "numpy": np.__version__,
            "recorded_at": datetime.now(timezone.utc).isoformat(),
        },
    }
    (output / "measurement.json").write_text(
        json.dumps(result, indent=2) + "\n", encoding="utf-8"
    )
    print(json.dumps(result), flush=True)


def main() -> None:
    parser = argparse.ArgumentParser()
    parser.add_argument("--variant", choices=["baseline", "memo"])
    parser.add_argument("--source")
    parser.add_argument("--output")
    parser.add_argument("--commit")
    args = parser.parse_args()
    if args.variant:
        worker(args)
        return
    sys.path.insert(0, str(ROOT))
    from tools.benchmark_bspline_lidar_imu import _freeze
    output = ROOT / "outputs/edge-objective-reuse-pilot-v1"
    output.mkdir()
    commit = subprocess.check_output(["git", "rev-parse", "HEAD"], text=True).strip()
    _freeze(output / "source", commit)
    protocol = {
        "scope": "Exploratory complete synthetic estimation; not a speed or accuracy claim.",
        "order": ["baseline", "memo", "memo", "baseline"], "commit": commit,
        "launcher_sha256": sha(Path(__file__)),
        "cache_capacity_per_frame_group": 4096,
        "quality_gate": "Every result byte after normalizing provenance.created_at only",
        "source_manifest_sha256": sha(output / "source/manifest.json"),
        "provenance": {"recorded_at": datetime.now(timezone.utc).isoformat()},
    }
    (output / "protocol.json").write_text(json.dumps(protocol, indent=2) + "\n", encoding="utf-8")
    measurements = []
    for index, variant in enumerate(protocol["order"]):
        target = output / f"{index:02d}-{variant}"
        command = [
            sys.executable, str(Path(__file__)), "--variant", variant,
            "--source", str(output / "source"), "--output", str(target), "--commit", commit,
        ]
        begin = time.perf_counter()
        with (output / f"{index:02d}-{variant}.stdout.log").open("w", encoding="utf-8") as stdout:
            with (output / f"{index:02d}-{variant}.stderr.log").open("w", encoding="utf-8") as stderr:
                completed = subprocess.run(command, env=os.environ.copy(), stdout=stdout, stderr=stderr)
        whole = time.perf_counter() - begin
        assert completed.returncode == 0, (variant, completed.returncode)
        result = json.loads((target / "measurement.json").read_bytes())
        result["whole_seconds"] = whole
        measurements.append(result)
        print(json.dumps({"index": index, "variant": variant, "whole_seconds": whole,
                          "api_seconds": result["api_seconds"], "counts": result["counts"]}), flush=True)
        (output / "attempts.json").write_text(json.dumps(measurements, indent=2) + "\n", encoding="utf-8")
    assert len({m["canonical_result_sha256"] for m in measurements}) == 1
    print("All complete synthetic artifacts match exactly.", flush=True)


if __name__ == "__main__":
    main()
