# recoil/pipeline/tests/test_sidecar.py
"""Sidecar read protocol tests. mtime cache + lazy sha256 + drift surfaced not raised."""

import json
import time
from pathlib import Path

import pytest


def _write_sidecar(file_path: Path, manifest: dict) -> Path:
    meta_dir = file_path.parent / "_meta"
    meta_dir.mkdir(parents=True, exist_ok=True)
    sidecar = meta_dir / f"{file_path.name}.json"
    sidecar.write_text(json.dumps(manifest))
    return sidecar


def test_read_sidecar_returns_none_when_missing(tmp_path):
    from recoil.pipeline._lib.sidecar import read_sidecar
    file_path = tmp_path / "characters" / "sadie" / "hero.jpg"
    file_path.parent.mkdir(parents=True)
    file_path.write_bytes(b"\x89PNG\r\n\x1a\n" + b"0" * 256)
    assert read_sidecar(file_path) is None


def test_read_sidecar_returns_record_with_drifted_false_when_sha_matches(tmp_path):
    from recoil.pipeline._lib.sidecar import read_sidecar, compute_sha256

    file_path = tmp_path / "characters" / "sadie" / "hero.jpg"
    file_path.parent.mkdir(parents=True)
    file_path.write_bytes(b"\x89PNG\r\n\x1a\n" + b"0" * 256)
    actual_sha = compute_sha256(file_path)

    _write_sidecar(file_path, {
        "schema_version": 1,
        "file": {"path": str(file_path), "sha256": actual_sha, "size_bytes": file_path.stat().st_size},
    })

    record = read_sidecar(file_path)
    assert record is not None
    assert record.drifted is False
    assert record.manifest["file"]["sha256"] == actual_sha


def test_read_sidecar_surfaces_drift_when_sha_diverges(tmp_path):
    from recoil.pipeline._lib.sidecar import read_sidecar

    file_path = tmp_path / "characters" / "sadie" / "hero.jpg"
    file_path.parent.mkdir(parents=True)
    file_path.write_bytes(b"\x89PNG\r\n\x1a\n" + b"0" * 256)
    _write_sidecar(file_path, {
        "schema_version": 1,
        "file": {"path": str(file_path), "sha256": "stalehash000000000000000000000000000000000000000000000000000000", "size_bytes": file_path.stat().st_size},
    })

    record = read_sidecar(file_path, force=True)
    assert record is not None
    assert record.drifted is True


def test_read_sidecar_uses_mtime_cache(tmp_path):
    from recoil.pipeline._lib.sidecar import read_sidecar, _CACHE  # private — fine for test

    file_path = tmp_path / "characters" / "sadie" / "hero.jpg"
    file_path.parent.mkdir(parents=True)
    file_path.write_bytes(b"\x89PNG\r\n\x1a\n" + b"0" * 256)
    _write_sidecar(file_path, {
        "schema_version": 1,
        "file": {"path": str(file_path), "sha256": "deadbeef" + "0" * 56, "size_bytes": file_path.stat().st_size},
    })

    _CACHE.clear()
    read_sidecar(file_path, force=True)  # warm
    assert file_path in _CACHE
    cached_at = _CACHE[file_path].cached_at_mtime

    # Reading again WITHOUT force should hit the cache
    read_sidecar(file_path, force=False)
    assert _CACHE[file_path].cached_at_mtime == cached_at
