from __future__ import annotations

import hashlib
import json
import math
import os
import re
import shutil
from collections.abc import Mapping
from datetime import UTC, datetime
from pathlib import Path
from typing import Any, Final

import numpy as np
import numpy.typing as npt

from k1link.ground_segmentation import (
    DEFAULT_GROUND_BENCHMARK_PROFILE,
    GroundBenchmarkProfile,
    GroundSegmentation,
    GroundSegmenter,
    LocalPercentileGroundSegmenter,
)
from k1link.ground_segmentation import (
    PATCHWORKPP_SOURCE_COMMIT as PATCHWORKPP_SOURCE_COMMIT,
)
from k1link.ground_segmentation import (
    PATCHWORKPP_SOURCE_TAG as PATCHWORKPP_SOURCE_TAG,
)
from k1link.ground_segmentation import (
    PATCHWORKPP_SOURCE_URL as PATCHWORKPP_SOURCE_URL,
)
from k1link.ground_segmentation import (
    GroundSegmentationError as LidarGroundError,
)
from k1link.ground_segmentation import (
    PatchworkPPGroundSegmenter as PatchworkPPGroundSegmenter,
)

from .lidar_contract import LidarContractError, sensor_frame_xyzi
from .lidar_replay import LidarReplayPackV2

LIDAR_GROUND_BENCHMARK_SCHEMA: Final = "missioncore.lidar-ground-benchmark/v1"
LIDAR_GROUND_BENCHMARK_REPORT_SCHEMA: Final = "missioncore.lidar-ground-benchmark-report/v1"
LIDAR_GROUND_ANNOTATION_TEMPLATE_SCHEMA: Final = "missioncore.lidar-ground-annotation-template/v1"
LIDAR_GROUND_FRAME_SCHEMA: Final = "missioncore.lidar-ground-frame/v1"
LIDAR_GROUND_RESULTS_NAME: Final = "ground-results.npz"
LIDAR_GROUND_REPORT_NAME: Final = "ground-report.json"
LIDAR_GROUND_MANIFEST_NAME: Final = "manifest.json"
LIDAR_GROUND_ANNOTATION_LABELS_NAME: Final = "labels-template.npz"
MAX_GROUND_FRAME_POINTS: Final = 200_000

_BENCHMARK_ID = re.compile(r"^ground-benchmark-[a-f0-9]{64}$")
_ANNOTATION_TEMPLATE_ID = re.compile(r"^ground-annotation-template-[a-f0-9]{64}$")
_SHA256 = re.compile(r"^[a-f0-9]{64}$")


class LidarGroundBenchmarkV1:
    """Strict reader for immutable ground A/B diagnostic evidence."""

    def __init__(self, root: Path) -> None:
        candidate = root.expanduser().absolute()
        if candidate.is_symlink():
            raise LidarGroundError("Ground benchmark directory cannot be a symlink")
        self.root = candidate.resolve(strict=True)
        if not self.root.is_dir() or _BENCHMARK_ID.fullmatch(self.root.name) is None:
            raise LidarGroundError("Ground benchmark id is invalid")
        self.manifest = _read_json(self.root / LIDAR_GROUND_MANIFEST_NAME)
        self.identity = _object(self.manifest.get("identity"), "ground identity")
        identity_sha256 = self.manifest.get("identity_sha256")
        if (
            self.manifest.get("schema_version") != LIDAR_GROUND_BENCHMARK_SCHEMA
            or self.identity.get("schema_version") != LIDAR_GROUND_BENCHMARK_SCHEMA
            or not isinstance(identity_sha256, str)
            or hashlib.sha256(_canonical_json(self.identity)).hexdigest() != identity_sha256
            or self.root.name != f"ground-benchmark-{identity_sha256}"
            or self.manifest.get("benchmark_id") != self.root.name
        ):
            raise LidarGroundError("Ground benchmark identity is invalid")
        artifacts = _validate_artifacts(self.root, self.manifest.get("artifacts"))
        self.arrays = np.load(artifacts["ground-results"], allow_pickle=False)
        self.report = _read_json(artifacts["ground-report"])
        try:
            _validate_ground_arrays(self.arrays, self.identity)
            input_domain = _object(
                self.report.get("input_domain"),
                "ground input domain",
            )
            labels = _object(self.report.get("labels"), "ground labels")
            decision = _object(self.report.get("decision"), "ground decision")
            if (
                _ground_logical_sha256(self.arrays) != self.identity.get("logical_results_sha256")
                or self.report.get("schema_version") != LIDAR_GROUND_BENCHMARK_REPORT_SCHEMA
                or self.report.get("benchmark_id") != self.root.name
                or self.report.get("replay_pack_id") != self.identity.get("replay_pack_id")
                or self.report.get("status") != "diagnostic-only"
                or input_domain.get("accepted") is not False
                or labels.get("status") != "missing-independent-review"
                or labels.get("metrics_available") is not False
                or decision.get("status") != "do-not-promote-on-current-vendor-map"
                or decision.get("production_promotion") is not False
            ):
                raise LidarGroundError("Ground benchmark report is incompatible")
        except BaseException:
            self.close()
            raise
        self.benchmark_id = self.root.name

    def close(self) -> None:
        self.arrays.close()


def build_lidar_ground_benchmark(
    replay: LidarReplayPackV2,
    output_root: Path,
    *,
    patchwork: GroundSegmenter,
    profile: GroundBenchmarkProfile = DEFAULT_GROUND_BENCHMARK_PROFILE,
) -> Path:
    """Run a diagnostic A/B without claiming labeled accuracy or safety."""

    if replay.pose_frame_count < 1:
        raise LidarGroundError("Ground A/B requires recorded pose evidence")
    current = LocalPercentileGroundSegmenter(profile)
    point_offsets = np.asarray(replay.arrays["point_offsets"], dtype="<i8")
    current_ground = np.zeros(replay.point_count, dtype=np.uint8)
    current_assigned = np.ones(replay.point_count, dtype=np.uint8)
    candidate_ground = np.zeros(replay.point_count, dtype=np.uint8)
    candidate_assigned = np.zeros(replay.point_count, dtype=np.uint8)
    current_latency: list[float] = []
    candidate_latency: list[float] = []
    pose_delta_ms: list[float] = []
    current_fraction: list[float] = []
    candidate_fraction: list[float] = []
    candidate_assigned_fraction: list[float] = []
    inter_provider_iou: list[float] = []
    disagreement_fraction: list[float] = []

    pose_times = np.asarray(
        replay.arrays["pose_received_monotonic_ns"],
        dtype=np.int64,
    )
    for frame_index in range(replay.point_frame_count):
        point = replay.point_frame(frame_index)
        nearest_pose_index = int(np.argmin(np.abs(pose_times - point.received_monotonic_ns)))
        pose = replay.pose_frame(nearest_pose_index)
        delta_ms = abs(pose.received_monotonic_ns - point.received_monotonic_ns) / 1_000_000
        if delta_ms > profile.pose_binding_threshold_ms:
            raise LidarGroundError("Ground A/B point frame has no admitted pose")
        try:
            candidate_input = sensor_frame_xyzi(
                point.decoded_view(),
                pose.decoded_view(),
            )
        except LidarContractError as exc:
            raise LidarGroundError("Ground A/B sensor conversion failed") from exc
        if profile.patchwork_map_vertical_origin_offset_m:
            candidate_input = candidate_input.copy()
            candidate_input[:, 2] -= profile.patchwork_map_vertical_origin_offset_m
        current_input = np.empty((point.xyz_map.shape[0], 4), dtype=np.float32)
        current_input[:, :3] = point.xyz_map.astype(np.float32)
        current_input[:, 3] = point.intensity.astype(np.float32) / 255.0
        current_result = current.segment(current_input)
        candidate_result = patchwork.segment(candidate_input)
        _segmentation(current_result, point.xyz_map.shape[0], "current")
        _segmentation(candidate_result, point.xyz_map.shape[0], "candidate")
        start = int(point_offsets[frame_index])
        end = int(point_offsets[frame_index + 1])
        current_ground[start:end] = current_result.ground_mask.astype(np.uint8)
        candidate_ground[start:end] = candidate_result.ground_mask.astype(np.uint8)
        candidate_assigned[start:end] = candidate_result.assigned_mask.astype(np.uint8)
        current_latency.append(current_result.latency_ms)
        candidate_latency.append(candidate_result.latency_ms)
        pose_delta_ms.append(delta_ms)
        current_fraction.append(float(np.mean(current_result.ground_mask)))
        candidate_fraction.append(float(np.mean(candidate_result.ground_mask)))
        candidate_assigned_fraction.append(float(np.mean(candidate_result.assigned_mask)))
        intersection = int(
            np.count_nonzero(current_result.ground_mask & candidate_result.ground_mask)
        )
        union = int(np.count_nonzero(current_result.ground_mask | candidate_result.ground_mask))
        inter_provider_iou.append(float(intersection / union) if union else 1.0)
        disagreement_fraction.append(
            float(np.mean(current_result.ground_mask != candidate_result.ground_mask))
        )

    arrays: dict[str, npt.NDArray[Any]] = {
        "point_offsets": point_offsets,
        "point_capture_sequence": np.asarray(
            replay.arrays["point_capture_sequence"],
            dtype="<i8",
        ),
        "current_ground": current_ground,
        "current_assigned": current_assigned,
        "candidate_ground": candidate_ground,
        "candidate_assigned": candidate_assigned,
    }
    logical_results_sha256 = _ground_logical_sha256(arrays)
    identity = {
        "schema_version": LIDAR_GROUND_BENCHMARK_SCHEMA,
        "replay_pack_id": replay.pack_id,
        "replay_logical_content_sha256": replay.identity["logical_content_sha256"],
        "session_id": replay.identity["session_id"],
        "profile": profile.to_dict(),
        "providers": {
            "current": dict(current.identity),
            "candidate": dict(patchwork.identity),
        },
        "point_frames": replay.point_frame_count,
        "points": replay.point_count,
        "logical_results_sha256": logical_results_sha256,
        "producer_sha256": _sha256(Path(__file__).resolve(strict=True)),
        "ground_truth": False,
        "authority": {
            "commands_enabled": False,
            "navigation_or_safety_accepted": False,
        },
    }
    identity_sha256 = hashlib.sha256(_canonical_json(identity)).hexdigest()
    benchmark_id = f"ground-benchmark-{identity_sha256}"
    output_parent = output_root.expanduser().resolve()
    output_parent.mkdir(mode=0o700, parents=True, exist_ok=True)
    output = output_parent / benchmark_id
    if output.exists():
        existing = LidarGroundBenchmarkV1(output)
        existing.close()
        return output

    report = {
        "schema_version": LIDAR_GROUND_BENCHMARK_REPORT_SCHEMA,
        "benchmark_id": benchmark_id,
        "replay_pack_id": replay.pack_id,
        "session_id": replay.identity["session_id"],
        "status": "diagnostic-only",
        "input_domain": {
            "accepted": False,
            "representation": replay.profile.representation.value,
            "physical_sensor_height_known": (
                profile.patchwork_height_evidence == "runtime-calibrated"
            ),
            "sensor_scan_geometry_known": replay.profile.scan_geometry_known,
            "normalization": {
                "sensor_height_m": profile.patchwork_sensor_height_proxy_m,
                "map_vertical_origin_offset_m": (profile.patchwork_map_vertical_origin_offset_m),
                "height_evidence": profile.patchwork_height_evidence,
            },
            "reason": (
                "Patchwork++ expects a sensor-centric scan; K1 lio_pcl is an "
                "externally downsampled LIO/map product. Height correction does "
                "not admit the external feed as a raw MID-360 scan."
            ),
        },
        "labels": {
            "status": "missing-independent-review",
            "metrics_available": False,
            "ground_iou": None,
            "curb_recall": None,
            "low_obstacle_recall": None,
            "reflection_noise_rejection": None,
        },
        "frames": replay.point_frame_count,
        "points": replay.point_count,
        "pose_delta_ms": _distribution(pose_delta_ms),
        "current": {
            "provider": dict(current.identity),
            "ground_fraction": _distribution(current_fraction),
            "assigned_fraction": _distribution([1.0] * replay.point_frame_count),
            "latency_ms": _distribution(current_latency),
        },
        "candidate": {
            "provider": dict(patchwork.identity),
            "ground_fraction": _distribution(candidate_fraction),
            "assigned_fraction": _distribution(candidate_assigned_fraction),
            "latency_ms": _distribution(candidate_latency),
        },
        "comparison": {
            "algorithm_to_algorithm_ground_iou": _distribution(inter_provider_iou),
            "ground_disagreement_fraction": _distribution(disagreement_fraction),
            "is_accuracy_metric": False,
        },
        "decision": {
            "status": "do-not-promote-on-current-vendor-map",
            "production_promotion": False,
            "reasons": [
                "candidate input domain is not accepted",
                "independent ground/curb/low-obstacle labels are missing",
                "algorithm disagreement is not accuracy",
            ],
            "next_gate": (
                "human-reviewed annotation subset or an admitted raw sensor scan "
                "with physical sensor height"
            ),
        },
        "authority": {
            "commands_enabled": False,
            "navigation_or_safety_accepted": False,
        },
    }
    staging = output_parent / f".{benchmark_id}.{os.getpid()}.incomplete"
    staging.mkdir(mode=0o700, exist_ok=False)
    try:
        arrays_path = staging / LIDAR_GROUND_RESULTS_NAME
        np.savez_compressed(arrays_path, **arrays)  # type: ignore[arg-type]
        report_path = staging / LIDAR_GROUND_REPORT_NAME
        _write_json(report_path, report)
        manifest = {
            "schema_version": LIDAR_GROUND_BENCHMARK_SCHEMA,
            "benchmark_id": benchmark_id,
            "identity_sha256": identity_sha256,
            "identity": identity,
            "created_at_utc": _utc_now(),
            "classification": "private-derived-lidar-diagnostic",
            "ground_truth": False,
            "artifacts": [
                _artifact_descriptor(
                    "ground-results",
                    arrays_path,
                    "application/x-npz",
                ),
                _artifact_descriptor(
                    "ground-report",
                    report_path,
                    "application/json",
                ),
            ],
        }
        _write_json(staging / LIDAR_GROUND_MANIFEST_NAME, manifest)
        os.replace(staging, output)
        validation = LidarGroundBenchmarkV1(output)
        validation.close()
    except BaseException:
        shutil.rmtree(staging, ignore_errors=True)
        if output.exists():
            shutil.rmtree(output, ignore_errors=True)
        raise
    return output


def build_lidar_ground_annotation_template(
    replay: LidarReplayPackV2,
    output_root: Path,
    *,
    requested_frames: int = 8,
) -> Path:
    """Create an all-ignore, immutable review template; never fabricate labels."""

    if not 1 <= requested_frames <= 64:
        raise LidarGroundError("Ground annotation frame count is invalid")
    selected = np.unique(
        np.linspace(
            0,
            replay.point_frame_count - 1,
            num=min(requested_frames, replay.point_frame_count),
            dtype=np.int64,
        )
    )
    source_offsets = np.asarray(replay.arrays["point_offsets"], dtype=np.int64)
    selected_counts = np.asarray(
        [int(source_offsets[index + 1] - source_offsets[index]) for index in selected],
        dtype="<i8",
    )
    selected_offsets = np.concatenate(
        (np.asarray([0], dtype="<i8"), np.cumsum(selected_counts, dtype=np.int64))
    )
    labels = np.zeros(int(selected_offsets[-1]), dtype=np.uint8)
    arrays: dict[str, npt.NDArray[Any]] = {
        "source_frame_index": selected.astype("<i8"),
        "point_capture_sequence": np.asarray(
            replay.arrays["point_capture_sequence"][selected],
            dtype="<i8",
        ),
        "point_offsets": selected_offsets.astype("<i8"),
        "labels": labels,
    }
    logical_sha256 = _ground_logical_sha256(arrays)
    identity = {
        "schema_version": LIDAR_GROUND_ANNOTATION_TEMPLATE_SCHEMA,
        "replay_pack_id": replay.pack_id,
        "replay_logical_content_sha256": replay.identity["logical_content_sha256"],
        "session_id": replay.identity["session_id"],
        "selected_frames": int(selected.shape[0]),
        "selected_points": int(labels.shape[0]),
        "classes": {
            "0": "ignore-unreviewed",
            "1": "ground",
            "2": "curb",
            "3": "low-obstacle",
            "4": "reflection-noise",
            "5": "other-non-ground",
        },
        "logical_content_sha256": logical_sha256,
        "producer_sha256": _sha256(Path(__file__).resolve(strict=True)),
        "review_status": "unreviewed",
        "ground_truth": False,
    }
    identity_sha256 = hashlib.sha256(_canonical_json(identity)).hexdigest()
    template_id = f"ground-annotation-template-{identity_sha256}"
    parent = output_root.expanduser().resolve()
    parent.mkdir(mode=0o700, parents=True, exist_ok=True)
    output = parent / template_id
    if output.exists():
        _validate_annotation_template(output)
        return output
    staging = parent / f".{template_id}.{os.getpid()}.incomplete"
    staging.mkdir(mode=0o700, exist_ok=False)
    try:
        labels_path = staging / LIDAR_GROUND_ANNOTATION_LABELS_NAME
        np.savez_compressed(labels_path, **arrays)  # type: ignore[arg-type]
        manifest = {
            "schema_version": LIDAR_GROUND_ANNOTATION_TEMPLATE_SCHEMA,
            "template_id": template_id,
            "identity_sha256": identity_sha256,
            "identity": identity,
            "created_at_utc": _utc_now(),
            "classification": "private-derived-lidar-annotation-template",
            "ground_truth": False,
            "artifacts": [
                _artifact_descriptor(
                    "labels-template",
                    labels_path,
                    "application/x-npz",
                )
            ],
        }
        _write_json(staging / LIDAR_GROUND_MANIFEST_NAME, manifest)
        os.replace(staging, output)
        _validate_annotation_template(output)
    except BaseException:
        shutil.rmtree(staging, ignore_errors=True)
        if output.exists():
            shutil.rmtree(output, ignore_errors=True)
        raise
    return output


def score_ground_labels(
    prediction: GroundSegmentation,
    labels: npt.NDArray[np.uint8],
) -> dict[str, object]:
    """Score reviewed point labels; label zero remains excluded, never negative."""

    values = np.asarray(labels, dtype=np.uint8).reshape((-1,))
    _segmentation(prediction, values.shape[0], "labeled prediction")
    if np.any(values > 5):
        raise LidarGroundError("Ground annotation contains an unknown class")
    reviewed = values != 0
    if not np.any(reviewed):
        return {
            "reviewed_points": 0,
            "ground_iou": None,
            "curb_recall": None,
            "low_obstacle_recall": None,
            "reflection_noise_rejection": None,
        }
    ground_truth = values == 1
    union = reviewed & (ground_truth | prediction.ground_mask)
    intersection = ground_truth & prediction.ground_mask
    return {
        "reviewed_points": int(np.count_nonzero(reviewed)),
        "ground_iou": _ratio(
            int(np.count_nonzero(intersection)),
            int(np.count_nonzero(union)),
        ),
        "curb_recall": _class_non_ground_recall(prediction, values, 2),
        "low_obstacle_recall": _class_non_ground_recall(prediction, values, 3),
        "reflection_noise_rejection": _class_unassigned_recall(
            prediction,
            values,
            4,
        ),
    }


def lidar_ground_benchmark_catalog_item(
    benchmark: LidarGroundBenchmarkV1,
) -> dict[str, object]:
    report = benchmark.report
    return {
        "benchmark_id": benchmark.benchmark_id,
        "replay_pack_id": benchmark.identity["replay_pack_id"],
        "session_id": benchmark.identity["session_id"],
        "status": report["status"],
        "frames": report["frames"],
        "points": report["points"],
        "input_domain": report["input_domain"],
        "labels": report["labels"],
        "current": report["current"],
        "candidate": report["candidate"],
        "comparison": report["comparison"],
        "decision": report["decision"],
        "created_at_utc": benchmark.manifest.get("created_at_utc"),
        "authority": {
            "commands_enabled": False,
            "navigation_or_safety_accepted": False,
        },
    }


def lidar_ground_frame_detail(
    benchmark: LidarGroundBenchmarkV1,
    replay: LidarReplayPackV2,
    frame_index: int,
) -> dict[str, object]:
    """Return one bounded, point-aligned frame for browser diagnostic review."""

    if (
        benchmark.identity.get("replay_pack_id") != replay.pack_id
        or benchmark.identity.get("replay_logical_content_sha256")
        != replay.identity.get("logical_content_sha256")
        or benchmark.identity.get("point_frames") != replay.point_frame_count
        or benchmark.identity.get("points") != replay.point_count
    ):
        raise LidarGroundError("Ground benchmark is not bound to this replay pack")
    if not 0 <= frame_index < replay.point_frame_count:
        raise IndexError(frame_index)

    benchmark_offsets = np.asarray(
        benchmark.arrays["point_offsets"],
        dtype=np.int64,
    )
    replay_offsets = np.asarray(replay.arrays["point_offsets"], dtype=np.int64)
    if not np.array_equal(benchmark_offsets, replay_offsets):
        raise LidarGroundError("Ground benchmark point offsets changed")
    start = int(benchmark_offsets[frame_index])
    end = int(benchmark_offsets[frame_index + 1])
    point_count = end - start
    if not 0 < point_count <= MAX_GROUND_FRAME_POINTS:
        raise LidarGroundError("Ground frame point count exceeds viewer limit")

    frame = replay.point_frame(frame_index)
    capture_sequence = int(benchmark.arrays["point_capture_sequence"][frame_index])
    if capture_sequence != frame.capture_sequence:
        raise LidarGroundError("Ground frame capture sequence changed")
    xyz = np.asarray(frame.xyz_map, dtype=np.float64)
    intensity = np.asarray(frame.intensity, dtype=np.uint8)
    current_ground = np.asarray(
        benchmark.arrays["current_ground"][start:end],
        dtype=np.uint8,
    )
    current_assigned = np.asarray(
        benchmark.arrays["current_assigned"][start:end],
        dtype=np.uint8,
    )
    candidate_ground = np.asarray(
        benchmark.arrays["candidate_ground"][start:end],
        dtype=np.uint8,
    )
    candidate_assigned = np.asarray(
        benchmark.arrays["candidate_assigned"][start:end],
        dtype=np.uint8,
    )
    disagreement = (current_ground != candidate_ground).astype(np.uint8)
    if (
        xyz.shape != (point_count, 3)
        or intensity.shape != (point_count,)
        or not np.isfinite(xyz).all()
    ):
        raise LidarGroundError("Ground frame replay content is incompatible")

    return {
        "schema_version": LIDAR_GROUND_FRAME_SCHEMA,
        "benchmark_id": benchmark.benchmark_id,
        "replay_pack_id": replay.pack_id,
        "session_id": replay.identity["session_id"],
        "frame_index": frame_index,
        "frame_count": replay.point_frame_count,
        "capture_sequence": capture_sequence,
        "point_count": point_count,
        "coordinate_frame": "map",
        "distance_unit": "m",
        "points_xyz_m": xyz.tolist(),
        "intensity_0_255": intensity.astype(np.int64).tolist(),
        "masks": {
            "current_ground": current_ground.astype(np.int64).tolist(),
            "current_assigned": current_assigned.astype(np.int64).tolist(),
            "candidate_ground": candidate_ground.astype(np.int64).tolist(),
            "candidate_assigned": candidate_assigned.astype(np.int64).tolist(),
            "disagreement": disagreement.astype(np.int64).tolist(),
        },
        "counts": {
            "current_ground": int(np.count_nonzero(current_ground)),
            "candidate_ground": int(np.count_nonzero(candidate_ground)),
            "disagreement": int(np.count_nonzero(disagreement)),
        },
        "access": "read-only",
        "ground_truth": False,
        "authority": {
            "commands_enabled": False,
            "navigation_or_safety_accepted": False,
        },
    }


def _validate_annotation_template(root: Path) -> None:
    resolved = root.resolve(strict=True)
    if (
        root.is_symlink()
        or not resolved.is_dir()
        or _ANNOTATION_TEMPLATE_ID.fullmatch(resolved.name) is None
    ):
        raise LidarGroundError("Ground annotation template id is invalid")
    manifest = _read_json(resolved / LIDAR_GROUND_MANIFEST_NAME)
    identity = _object(manifest.get("identity"), "annotation template identity")
    identity_sha256 = manifest.get("identity_sha256")
    if (
        manifest.get("schema_version") != LIDAR_GROUND_ANNOTATION_TEMPLATE_SCHEMA
        or identity.get("schema_version") != LIDAR_GROUND_ANNOTATION_TEMPLATE_SCHEMA
        or not isinstance(identity_sha256, str)
        or hashlib.sha256(_canonical_json(identity)).hexdigest() != identity_sha256
        or resolved.name != f"ground-annotation-template-{identity_sha256}"
        or manifest.get("ground_truth") is not False
        or identity.get("review_status") != "unreviewed"
    ):
        raise LidarGroundError("Ground annotation template identity is invalid")
    artifacts = _validate_artifacts(resolved, manifest.get("artifacts"))
    arrays = np.load(artifacts["labels-template"], allow_pickle=False)
    try:
        required = {
            "source_frame_index",
            "point_capture_sequence",
            "point_offsets",
            "labels",
        }
        if (
            set(arrays.files) != required
            or arrays["labels"].dtype != np.dtype("u1")
            or np.any(arrays["labels"] != 0)
            or _ground_logical_sha256(arrays) != identity.get("logical_content_sha256")
        ):
            raise LidarGroundError("Ground annotation template content is invalid")
    finally:
        arrays.close()


def _validate_ground_arrays(arrays: Any, identity: Mapping[str, object]) -> None:
    required = {
        "point_offsets": np.dtype("<i8"),
        "point_capture_sequence": np.dtype("<i8"),
        "current_ground": np.dtype("u1"),
        "current_assigned": np.dtype("u1"),
        "candidate_ground": np.dtype("u1"),
        "candidate_assigned": np.dtype("u1"),
    }
    if set(arrays.files) != set(required):
        raise LidarGroundError("Ground benchmark array set is incompatible")
    if any(arrays[name].dtype != dtype for name, dtype in required.items()):
        raise LidarGroundError("Ground benchmark array dtype changed")
    frames = _nonnegative_int(identity.get("point_frames"), "point frames")
    points = _nonnegative_int(identity.get("points"), "points")
    if (
        arrays["point_offsets"].shape != (frames + 1,)
        or arrays["point_capture_sequence"].shape != (frames,)
        or any(
            arrays[name].shape != (points,)
            for name in (
                "current_ground",
                "current_assigned",
                "candidate_ground",
                "candidate_assigned",
            )
        )
        or int(arrays["point_offsets"][0]) != 0
        or int(arrays["point_offsets"][-1]) != points
        or np.any(np.diff(arrays["point_offsets"]) <= 0)
        or np.any(np.diff(arrays["point_capture_sequence"]) <= 0)
        or any(
            np.any((arrays[name] != 0) & (arrays[name] != 1))
            for name in (
                "current_ground",
                "current_assigned",
                "candidate_ground",
                "candidate_assigned",
            )
        )
        or np.any(arrays["current_ground"] > arrays["current_assigned"])
        or np.any(arrays["candidate_ground"] > arrays["candidate_assigned"])
    ):
        raise LidarGroundError("Ground benchmark array shapes or values are invalid")


def _xyzi(value: npt.NDArray[np.float32]) -> npt.NDArray[np.float32]:
    points = np.asarray(value, dtype=np.float32)
    if points.ndim != 2 or points.shape[1] != 4 or not np.isfinite(points).all():
        raise LidarGroundError("Ground provider input must be finite XYZI")
    return points


def _indices(value: npt.NDArray[np.int64], count: int, label: str) -> None:
    if value.size and (
        np.any(value < 0) or np.any(value >= count) or np.unique(value).shape[0] != value.shape[0]
    ):
        raise LidarGroundError(f"{label} indices are invalid")


def _segmentation(value: GroundSegmentation, count: int, label: str) -> None:
    if (
        value.ground_mask.dtype != np.dtype(np.bool_)
        or value.assigned_mask.dtype != np.dtype(np.bool_)
        or value.ground_mask.shape != (count,)
        or value.assigned_mask.shape != (count,)
        or np.any(value.ground_mask & ~value.assigned_mask)
        or not math.isfinite(value.latency_ms)
        or value.latency_ms < 0
    ):
        raise LidarGroundError(f"{label} segmentation is invalid")


def _class_non_ground_recall(
    prediction: GroundSegmentation,
    labels: npt.NDArray[np.uint8],
    class_id: int,
) -> float | None:
    class_mask = labels == class_id
    return _ratio(
        int(np.count_nonzero(class_mask & ~prediction.ground_mask)),
        int(np.count_nonzero(class_mask)),
    )


def _class_unassigned_recall(
    prediction: GroundSegmentation,
    labels: npt.NDArray[np.uint8],
    class_id: int,
) -> float | None:
    class_mask = labels == class_id
    return _ratio(
        int(np.count_nonzero(class_mask & ~prediction.assigned_mask)),
        int(np.count_nonzero(class_mask)),
    )


def _ratio(numerator: int, denominator: int) -> float | None:
    return float(numerator / denominator) if denominator else None


def _nonnegative_int(value: object, label: str) -> int:
    if not isinstance(value, int) or isinstance(value, bool) or value < 0:
        raise LidarGroundError(f"{label} must be a non-negative integer")
    return value


def _distribution(values: list[float]) -> dict[str, float | int | None]:
    array = np.asarray(values, dtype=np.float64)
    if not array.size:
        return {
            "sample_count": 0,
            "minimum": None,
            "mean": None,
            "p50": None,
            "p95": None,
            "maximum": None,
        }
    if not np.isfinite(array).all():
        raise LidarGroundError("Ground benchmark distribution is non-finite")
    return {
        "sample_count": int(array.size),
        "minimum": float(np.min(array)),
        "mean": float(np.mean(array)),
        "p50": float(np.quantile(array, 0.5)),
        "p95": float(np.quantile(array, 0.95)),
        "maximum": float(np.max(array)),
    }


def _ground_logical_sha256(arrays: Mapping[str, Any]) -> str:
    digest = hashlib.sha256()
    for name in sorted(arrays):
        value = np.asarray(arrays[name])
        digest.update(name.encode())
        digest.update(value.dtype.str.encode())
        digest.update(_canonical_json(list(value.shape)))
        digest.update(np.ascontiguousarray(value).tobytes())
    return digest.hexdigest()


def _artifact_descriptor(
    role: str,
    path: Path,
    media_type: str,
) -> dict[str, object]:
    return {
        "role": role,
        "name": path.name,
        "media_type": media_type,
        "byte_length": path.stat().st_size,
        "sha256": _sha256(path),
    }


def _validate_artifacts(
    root: Path,
    value: object,
) -> dict[str, Path]:
    if not isinstance(value, list) or not value:
        raise LidarGroundError("Ground artifact list is invalid")
    artifacts: dict[str, Path] = {}
    for item in value:
        descriptor = _object(item, "ground artifact")
        role = descriptor.get("role")
        name = descriptor.get("name")
        if (
            not isinstance(role, str)
            or not isinstance(name, str)
            or Path(name).name != name
            or role in artifacts
        ):
            raise LidarGroundError("Ground artifact descriptor is invalid")
        path = root / name
        try:
            metadata = path.lstat()
            resolved = path.resolve(strict=True)
        except OSError as exc:
            raise LidarGroundError("Ground artifact is unavailable") from exc
        if (
            path.is_symlink()
            or not path.is_file()
            or resolved.parent != root
            or descriptor.get("byte_length") != metadata.st_size
            or descriptor.get("sha256") != _sha256(path)
        ):
            raise LidarGroundError("Ground artifact integrity check failed")
        artifacts[role] = path
    return artifacts


def _object(value: object, label: str) -> dict[str, Any]:
    if not isinstance(value, dict) or not all(isinstance(key, str) for key in value):
        raise LidarGroundError(f"{label} must be an object")
    return value


def _read_json(path: Path) -> dict[str, Any]:
    try:
        value = json.loads(path.read_text(encoding="utf-8"))
    except (OSError, UnicodeDecodeError, json.JSONDecodeError) as exc:
        raise LidarGroundError("Ground JSON artifact is unavailable") from exc
    return _object(value, "ground JSON")


def _write_json(path: Path, value: object) -> None:
    path.write_bytes(_canonical_json(value) + b"\n")


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


def _sha256(path: Path) -> str:
    digest = hashlib.sha256()
    with path.open("rb") as stream:
        while chunk := stream.read(1024 * 1024):
            digest.update(chunk)
    return digest.hexdigest()


def _utc_now() -> str:
    return datetime.now(UTC).isoformat(timespec="milliseconds").replace("+00:00", "Z")
