from __future__ import annotations

import json
from pathlib import Path

import pytest

from k1link.compute.multirate_perception_qualification import (
    MERGED_FRAME_SCHEMA,
    _validate_merged_rows,
)
from k1link.sessions import SessionIntegrityError


def _merged(index: int, semantic: dict[str, object]) -> dict[str, object]:
    return {
        "schema_version": MERGED_FRAME_SCHEMA,
        "frame_index": index,
        "source_frame_index": 1000 + index,
        "session_seconds": 20.0 + index * 0.1,
        "detector_result_age_ms": 80.0,
        "tracks": [],
        "semantic": semantic,
    }


def test_merged_rows_allow_explicit_unavailable_then_fresh(tmp_path: Path) -> None:
    path = tmp_path / "merged-frames.jsonl"
    unavailable = {
        "status": "unavailable",
        "source_frame_index": None,
        "source_age_ms": None,
        "completion_age_ms": None,
        "mask_sha256": None,
    }
    fresh = {
        "status": "fresh",
        "source_frame_index": 1000,
        "source_age_ms": 200.0,
        "completion_age_ms": 210.0,
        "mask_sha256": "a" * 64,
    }
    path.write_text(
        json.dumps(_merged(0, unavailable)) + "\n" + json.dumps(_merged(2, fresh)) + "\n",
        encoding="utf-8",
    )

    _validate_merged_rows(
        path,
        tmp_path,
        expected_indices=(0, 2),
        source_start=1000,
        semantic_indices={0},
    )


def test_merged_rows_reject_future_semantic_binding(tmp_path: Path) -> None:
    path = tmp_path / "merged-frames.jsonl"
    future = {
        "status": "fresh",
        "source_frame_index": 1005,
        "source_age_ms": 0.0,
        "completion_age_ms": 200.0,
        "mask_sha256": "a" * 64,
    }
    path.write_text(json.dumps(_merged(2, future)) + "\n", encoding="utf-8")

    with pytest.raises(SessionIntegrityError, match="binding"):
        _validate_merged_rows(
            path,
            tmp_path,
            expected_indices=(2,),
            source_start=1000,
            semantic_indices={5},
        )
