from __future__ import annotations

import struct

from k1link.device_plugins.xgrids_k1.protocol.streams import (
    LegacyPoint,
    LegacyPointCloudFrame,
    LioPoint,
    LioPointCloudFrame,
    MqttHeader,
)
from k1link.device_plugins.xgrids_k1.viewer.foxglove_bridge import (
    POINT_STRIDE,
    BridgeMetrics,
    pack_legacy_point_cloud,
    pack_lio_point_cloud,
)


def test_lio_points_are_scaled_and_packed_with_uint8_intensity() -> None:
    frame = LioPointCloudFrame(
        header=MqttHeader(
            seq=1,
            stamp=2,
            scaler=1000,
            device_id="synthetic",
            session_id="synthetic",
            openapi_key=None,
        ),
        compression=0,
        compressed_bytes=10,
        decompressed_bytes=20,
        points=(LioPoint(-1000, 2500, 3000, 0xAABBCC7F),),
    )

    packed = pack_lio_point_cloud(frame)

    assert packed.point_count == 1
    assert len(packed.data) == POINT_STRIDE
    assert struct.unpack("<fffB3x", packed.data) == (-1.0, 2.5, 3.0, 0x7F)


def test_legacy_points_keep_verified_metric_fields() -> None:
    frame = LegacyPointCloudFrame(
        envelope=b"\x00" * 12,
        stride=16,
        points=(LegacyPoint(1.0, -2.0, 3.5, 1, 2, 3, 240),),
    )

    packed = pack_legacy_point_cloud(frame)

    assert struct.unpack("<fffB3x", packed.data) == (1.0, -2.0, 3.5, 240)


def test_metrics_distinguish_preview_drops_and_pipeline_latency() -> None:
    metrics = BridgeMetrics()
    metrics.received(100)
    metrics.preview_dropped()
    metrics.record_latency(12.3456)
    metrics.published_pcl(42, 2_000_000_000, 1.2345)

    snapshot = metrics.snapshot()

    assert snapshot["messages_received"] == 1
    assert snapshot["payload_bytes"] == 100
    assert snapshot["preview_dropped"] == 1
    assert snapshot["last_point_count"] == 42
    assert snapshot["mqtt_to_publish_ms"] == 12.346
    assert snapshot["decode_publish_ms"] == 1.234


def test_metrics_report_live_ai_latency_rate_staleness_and_drops() -> None:
    metrics = BridgeMetrics()
    metrics.perception_dropped()
    metrics.published_perception(
        captured_at_epoch_ns=1_000_000_000,
        published_at_epoch_ns=1_125_000_000,
        published_monotonic_ns=2_000_000_000,
    )

    snapshot = metrics.snapshot()

    assert snapshot["perception_frames"] == 1
    assert snapshot["perception_dropped"] == 1
    assert snapshot["perception_end_to_end_ms"] == 125.0
    assert snapshot["perception_end_to_end_p95_ms"] == 125.0
