"""Regression tests for the CSS response builder dispatch.

These lock in the safety net introduced when the silent "fallback to a fake
PictureCSSResponse" branch was removed:

* every concrete ColorStripSource subclass registered in ``_SOURCE_TYPE_MAP``
  must have a builder in ``_RESPONSE_MAP`` (verified at module import); and
* the previously-missing ``GameEventColorStripSource`` round-trips through
  the response builder into the matching ``GameEventCSSResponse`` schema.
"""

from __future__ import annotations

from datetime import datetime, timezone

import pytest

from ledgrab.api.routes.color_strip_sources import _helpers
from ledgrab.api.schemas.color_strip_sources import GameEventCSSResponse
from ledgrab.storage.color_strip_source import (
    ColorStripSource,
    GameEventColorStripSource,
)


def test_response_map_covers_every_registered_source_type():
    """Every source_type in _SOURCE_TYPE_MAP has a response builder."""
    storage_kinds = set(_helpers._STORAGE_TYPE_MAP.keys())
    builder_kinds = set(_helpers._RESPONSE_MAP.keys())
    missing = storage_kinds - builder_kinds
    assert not missing, f"_RESPONSE_MAP is missing builders for: {sorted(missing)}"


def test_assert_helper_raises_when_a_kind_is_unregistered(monkeypatch):
    """Adding a kind to the storage registry without a builder is caught."""

    class _PhantomColorStripSource(ColorStripSource):
        pass

    monkeypatch.setitem(_helpers._STORAGE_TYPE_MAP, "phantom", _PhantomColorStripSource)
    with pytest.raises(RuntimeError, match="phantom"):
        _helpers._assert_response_map_coverage()


def test_game_event_source_serialises_to_game_event_response():
    """A GameEventColorStripSource is rendered as GameEventCSSResponse (not the
    fake PictureCSSResponse that the silent fallback used to return).
    """
    now = datetime.now(timezone.utc)
    source = GameEventColorStripSource(
        id="css_gev0001",
        name="Counter-Strike feedback",
        source_type="game_event",
        created_at=now,
        updated_at=now,
        game_integration_id="gi_cs2_main",
        event_mappings=[{"event": "hit", "effect": "flash"}],
        led_count=60,
    )

    response = _helpers._css_to_response(source)

    assert isinstance(response, GameEventCSSResponse)
    assert response.source_type == "game_event"
    assert response.game_integration_id == "gi_cs2_main"
    assert response.event_mappings == [{"event": "hit", "effect": "flash"}]
    assert response.led_count == 60


def test_unregistered_source_type_raises_in_css_to_response():
    """Reaching ``_css_to_response`` with an unmapped source_type raises loudly."""

    class _UnregisteredCSS(ColorStripSource):
        pass

    now = datetime.now(timezone.utc)
    source = _UnregisteredCSS(
        id="css_xxx",
        name="rogue",
        source_type="rogue_unregistered",
        created_at=now,
        updated_at=now,
    )
    with pytest.raises(RuntimeError, match="No CSS response builder"):
        _helpers._css_to_response(source)
