"""Tests for the unified value-stream-builder registry."""

from __future__ import annotations

import pytest

from ledgrab.core.processing import value_kinds
from ledgrab.core.processing.value_kinds import (
    NEEDS_CLOCK_RUNTIME,
    STREAM_BUILDERS,
    ValueStreamDeps,
    build_stream,
)
from ledgrab.storage.value_source import _VALUE_SOURCE_MAP


def test_builders_cover_every_storage_kind():
    """STREAM_BUILDERS keys == storage._VALUE_SOURCE_MAP keys."""
    storage_kinds = set(_VALUE_SOURCE_MAP.keys())
    builder_kinds = set(STREAM_BUILDERS.keys())
    assert storage_kinds == builder_kinds, (
        f"missing={storage_kinds - builder_kinds}, " f"extra={builder_kinds - storage_kinds}"
    )


def test_build_stream_raises_on_unknown_kind():
    class _Fake:
        source_type = "totally_unregistered"
        id = "fake"

    deps = ValueStreamDeps(value_stream_manager=None)
    with pytest.raises(ValueError, match="totally_unregistered"):
        build_stream(_Fake(), deps)


def test_coverage_assertion_raises_on_drift(monkeypatch):
    """A kind added to storage without a builder fails the import-time check."""
    monkeypatch.setitem(_VALUE_SOURCE_MAP, "phantom_kind", object)
    with pytest.raises(RuntimeError, match="phantom_kind"):
        value_kinds._assert_value_kind_coverage()


def test_needs_clock_runtime_is_subset_of_registered_kinds():
    assert NEEDS_CLOCK_RUNTIME.issubset(set(STREAM_BUILDERS.keys()))


def test_static_builder_returns_static_value_stream():
    from ledgrab.core.processing.value_stream import StaticValueStream
    from ledgrab.storage.value_source import StaticValueSource
    from datetime import datetime, timezone

    src = StaticValueSource(
        id="vs_t",
        name="t",
        source_type="static",
        created_at=datetime.now(timezone.utc),
        updated_at=datetime.now(timezone.utc),
        value=0.42,
    )
    deps = ValueStreamDeps(value_stream_manager=None)
    stream = build_stream(src, deps)
    assert isinstance(stream, StaticValueStream)
    # Sanity: the value flowed through
    assert stream.get_value() == 0.42
