"""Tests for the output-target response-builder registry.

Locks in the safety net that replaced the previous silent
``LedOutputTargetResponse(defaults)`` fallback in
``output_targets._target_to_response``.
"""

from __future__ import annotations

import pytest

from ledgrab.api.routes import output_targets
from ledgrab.api.routes.output_targets import (
    _assert_target_response_coverage,
    _target_to_response,
    _TARGET_RESPONSE_BUILDERS,
)
from ledgrab.storage.ha_light_output_target import HALightOutputTarget
from ledgrab.storage.wled_output_target import WledOutputTarget
from ledgrab.storage.z2m_light_output_target import Z2MLightOutputTarget

EXPECTED_TARGET_CLASSES = {WledOutputTarget, HALightOutputTarget, Z2MLightOutputTarget}


def test_registry_covers_every_known_target_subclass():
    assert set(_TARGET_RESPONSE_BUILDERS.keys()) == EXPECTED_TARGET_CLASSES


def test_every_registered_builder_is_callable():
    for cls, builder in _TARGET_RESPONSE_BUILDERS.items():
        assert callable(builder), f"builder for {cls.__name__} is not callable"


def test_unregistered_target_class_raises_in_target_to_response():
    """Reaching ``_target_to_response`` with an unmapped class raises loudly
    instead of silently returning a malformed LedOutputTargetResponse.
    """

    class _RogueTarget:
        id = "tgt_rogue"
        name = "rogue"

    with pytest.raises(RuntimeError, match="No response builder"):
        _target_to_response(_RogueTarget())


def test_coverage_assertion_raises_on_drift(monkeypatch):
    """Removing a builder from the registry makes the import-time check fail."""
    pruned = {
        cls: builder
        for cls, builder in _TARGET_RESPONSE_BUILDERS.items()
        if cls is not WledOutputTarget
    }
    monkeypatch.setattr(output_targets, "_TARGET_RESPONSE_BUILDERS", pruned)
    with pytest.raises(RuntimeError, match="WledOutputTarget"):
        _assert_target_response_coverage()


def test_coverage_assertion_raises_on_extra_entry(monkeypatch):
    """An entry keyed by an unknown class is also caught."""

    class _RogueTargetClass:
        pass

    extended = {**_TARGET_RESPONSE_BUILDERS, _RogueTargetClass: lambda t: None}
    monkeypatch.setattr(output_targets, "_TARGET_RESPONSE_BUILDERS", extended)
    with pytest.raises(RuntimeError, match="_RogueTargetClass"):
        _assert_target_response_coverage()
