from __future__ import annotations

import hashlib
import json
import struct
import subprocess
import sys
from pathlib import Path

from k1link.device_plugins.xgrids_k1.mqtt.capture import FRAME_HEADER, RAW_MAGIC
from k1link.device_plugins.xgrids_k1.recorded_point_colors import (
    RecordedPointColorOverlayStore,
)
from k1link.sessions import ReplayArtifact, ReplayCommand


def _point_payload(x: float, intensity: int) -> bytes:
    return struct.pack("<III", 16, 0, 0) + struct.pack(
        "<fffBBBB",
        x,
        -2.0,
        3.0,
        10,
        20,
        30,
        intensity,
    )


def _command(tmp_path: Path) -> ReplayCommand:
    source = tmp_path / "mqtt.raw.k1mqtt"
    metadata_path = tmp_path / "mqtt.metadata.jsonl"
    raw = bytearray(RAW_MAGIC)
    metadata: list[dict[str, object]] = []
    epoch_origin_ns = 1_784_124_315_000_000_000
    monotonic_origin_ns = 9_000_000_000
    topic = "RealtimePointcloud"
    for sequence in range(1, 7):
        payload = _point_payload(float(sequence), sequence * 20)
        topic_bytes = topic.encode("utf-8")
        frame_offset = len(raw)
        raw.extend(FRAME_HEADER.pack(len(topic_bytes), len(payload)))
        raw.extend(topic_bytes)
        payload_offset = len(raw)
        raw.extend(payload)
        metadata.append(
            {
                "record_type": "message",
                "sequence": sequence,
                "received_at_epoch_ns": epoch_origin_ns + sequence * 100_000_000,
                "received_monotonic_ns": monotonic_origin_ns + sequence * 100_000_000,
                "topic": topic,
                "payload_bytes": len(payload),
                "payload_sha256": hashlib.sha256(payload).hexdigest(),
                "raw_frame_offset": frame_offset,
                "raw_payload_offset": payload_offset,
                "raw_frame_bytes": len(raw) - frame_offset,
            }
        )
    source.write_bytes(raw)
    metadata_path.write_text(
        "".join(json.dumps(item, separators=(",", ":")) + "\n" for item in metadata),
        encoding="utf-8",
    )
    artifacts = (
        ReplayArtifact(
            artifact_id="raw-transport-primary",
            path=source,
            media_type="application/x-nodedc-k1mqtt",
            file_byte_length=source.stat().st_size,
            replay_byte_length=source.stat().st_size,
            expected_sha256=hashlib.sha256(source.read_bytes()).hexdigest(),
        ),
        ReplayArtifact(
            artifact_id="raw-transport-index",
            path=metadata_path,
            media_type="application/x-ndjson",
            file_byte_length=metadata_path.stat().st_size,
            replay_byte_length=metadata_path.stat().st_size,
            expected_sha256=hashlib.sha256(metadata_path.read_bytes()).hexdigest(),
        ),
    )
    return ReplayCommand(
        session_id="recorded-color-test",
        plugin_id="nodedc.device.xgrids-lixelkity-k1",
        allowed_root=tmp_path,
        session_root=tmp_path,
        primary_artifact_id="raw-transport-primary",
        artifacts=artifacts,
        timeline_origin_epoch_ns=epoch_origin_ns,
        timeline_origin_monotonic_ns=monotonic_origin_ns,
        speed=1.0,
        loop=False,
    )


def test_recorded_color_overlay_logs_only_colors_at_operator_frame_cadence(
    tmp_path: Path,
) -> None:
    store = RecordedPointColorOverlayStore()
    payload = store.render(
        _command(tmp_path),
        application_id="nodedc_mission_core_recorded",
        recording_id="recording-001",
        color_mode="height",
        palette="viridis",
        custom_color="#35d7c1",
    )
    output = tmp_path / "colors.rrd"
    output.write_bytes(payload)
    printed = subprocess.run(
        [
            sys.executable,
            "-m",
            "rerun_cli",
            "rrd",
            "print",
            "-vvv",
            "--entity",
            "/world/points",
            str(output),
        ],
        check=True,
        capture_output=True,
        text=True,
    ).stdout

    assert payload.startswith(b"RRF2")
    assert printed.count("Points3D:colors") == 2
    assert "Points3D:positions" not in printed
    assert "session_time" in printed


def test_recorded_color_overlay_reuses_index_and_identical_payload(
    tmp_path: Path,
) -> None:
    store = RecordedPointColorOverlayStore()
    command = _command(tmp_path)
    first = store.render(
        command,
        application_id="nodedc_mission_core_recorded",
        recording_id="recording-001",
        color_mode="distance",
        palette="plasma",
        custom_color="#35d7c1",
    )
    second = store.render(
        command,
        application_id="nodedc_mission_core_recorded",
        recording_id="recording-001",
        color_mode="distance",
        palette="plasma",
        custom_color="#35d7c1",
    )

    assert second is first
