"""Tests for TransitionRegistry."""

import pytest

from apps.core.choices.base import RichChoice
from apps.core.choices.registry import registry
from apps.core.state_machine.registry import (
    TransitionInfo,
    TransitionRegistry,
    registry_instance,
)


@pytest.fixture
def sample_choices():
    """Create sample choices for testing."""
    choices = [
        RichChoice(
            value="pending",
            label="Pending",
            metadata={
                "can_transition_to": ["approved", "rejected"],
                "requires_moderator": True,
            },
        ),
        RichChoice(
            value="approved",
            label="Approved",
            metadata={"is_final": True, "can_transition_to": []},
        ),
        RichChoice(
            value="rejected",
            label="Rejected",
            metadata={"is_final": True, "can_transition_to": []},
        ),
    ]
    registry.register("test_states", choices, domain="test")
    yield choices
    registry.clear_domain("test")
    registry_instance.clear_registry()


def test_transition_info_creation():
    """Test TransitionInfo dataclass creation."""
    info = TransitionInfo(
        source="pending",
        target="approved",
        method_name="approve",
        requires_moderator=True,
    )
    assert info.source == "pending"
    assert info.target == "approved"
    assert info.method_name == "approve"
    assert info.requires_moderator is True


def test_transition_info_hashable():
    """Test TransitionInfo is hashable."""
    info1 = TransitionInfo(source="pending", target="approved", method_name="approve")
    info2 = TransitionInfo(source="pending", target="approved", method_name="approve")
    assert hash(info1) == hash(info2)


def test_registry_singleton():
    """Test TransitionRegistry is a singleton."""
    reg1 = TransitionRegistry()
    reg2 = TransitionRegistry()
    assert reg1 is reg2


def test_register_transition():
    """Test transition registration."""
    registry_instance.register_transition(
        choice_group="test_states",
        domain="test",
        source="pending",
        target="approved",
        method_name="approve",
        metadata={"requires_moderator": True},
    )

    transition = registry_instance.get_transition("test_states", "test", "pending", "approved")
    assert transition is not None
    assert transition.method_name == "approve"
    assert transition.requires_moderator is True


def test_get_transition_not_found():
    """Test getting non-existent transition."""
    transition = registry_instance.get_transition("nonexistent", "test", "pending", "approved")
    assert transition is None


def test_get_available_transitions(sample_choices):
    """Test getting available transitions from a state."""
    registry_instance.build_registry_from_choices("test_states", "test")

    available = registry_instance.get_available_transitions("test_states", "test", "pending")
    assert len(available) == 2
    targets = [t.target for t in available]
    assert "approved" in targets
    assert "rejected" in targets


def test_get_transition_method_name():
    """Test getting transition method name."""
    registry_instance.register_transition(
        choice_group="test_states",
        domain="test",
        source="pending",
        target="approved",
        method_name="approve",
    )

    method_name = registry_instance.get_transition_method_name("test_states", "test", "pending", "approved")
    assert method_name == "approve"


def test_validate_transition():
    """Test transition validation."""
    registry_instance.register_transition(
        choice_group="test_states",
        domain="test",
        source="pending",
        target="approved",
        method_name="approve",
    )

    assert registry_instance.validate_transition("test_states", "test", "pending", "approved")
    assert not registry_instance.validate_transition("test_states", "test", "pending", "nonexistent")


def test_build_registry_from_choices(sample_choices):
    """Test automatic registry building from RichChoice metadata."""
    registry_instance.build_registry_from_choices("test_states", "test")

    # Check transitions were registered
    transition = registry_instance.get_transition("test_states", "test", "pending", "approved")
    assert transition is not None


def test_clear_registry_specific():
    """Test clearing specific choice group."""
    registry_instance.register_transition(
        choice_group="test_states",
        domain="test",
        source="pending",
        target="approved",
        method_name="approve",
    )

    registry_instance.clear_registry(choice_group="test_states", domain="test")

    transition = registry_instance.get_transition("test_states", "test", "pending", "approved")
    assert transition is None


def test_clear_registry_all():
    """Test clearing entire registry."""
    registry_instance.register_transition(
        choice_group="test_states",
        domain="test",
        source="pending",
        target="approved",
        method_name="approve",
    )

    registry_instance.clear_registry()

    transition = registry_instance.get_transition("test_states", "test", "pending", "approved")
    assert transition is None


def test_export_transition_graph_dict(sample_choices):
    """Test exporting transition graph as dict."""
    registry_instance.build_registry_from_choices("test_states", "test")

    graph = registry_instance.export_transition_graph("test_states", "test", format="dict")
    assert isinstance(graph, dict)
    assert "pending" in graph
    assert set(graph["pending"]) == {"approved", "rejected"}


def test_export_transition_graph_mermaid(sample_choices):
    """Test exporting transition graph as mermaid."""
    registry_instance.build_registry_from_choices("test_states", "test")

    graph = registry_instance.export_transition_graph("test_states", "test", format="mermaid")
    assert isinstance(graph, str)
    assert "stateDiagram-v2" in graph
    assert "pending" in graph


def test_export_transition_graph_dot(sample_choices):
    """Test exporting transition graph as DOT."""
    registry_instance.build_registry_from_choices("test_states", "test")

    graph = registry_instance.export_transition_graph("test_states", "test", format="dot")
    assert isinstance(graph, str)
    assert "digraph" in graph
    assert "pending" in graph


def test_export_invalid_format(sample_choices):
    """Test exporting with invalid format."""
    registry_instance.build_registry_from_choices("test_states", "test")

    with pytest.raises(ValueError):
        registry_instance.export_transition_graph("test_states", "test", format="invalid")


def test_get_all_registered_groups():
    """Test getting all registered choice groups."""
    registry_instance.register_transition(
        choice_group="test_states",
        domain="test",
        source="pending",
        target="approved",
        method_name="approve",
    )

    groups = registry_instance.get_all_registered_groups()
    assert ("test", "test_states") in groups
