"""Tests for StateTransitionBuilder."""

import pytest
from django.core.exceptions import ImproperlyConfigured

from apps.core.choices.base import ChoiceCategory, RichChoice
from apps.core.choices.registry import registry
from apps.core.state_machine.builder import StateTransitionBuilder


@pytest.fixture
def sample_choices():
    """Create sample choices for testing."""
    choices = [
        RichChoice(
            value="pending",
            label="Pending",
            description="Awaiting review",
            metadata={"can_transition_to": ["approved", "rejected"]},
            category=ChoiceCategory.STATUS,
        ),
        RichChoice(
            value="approved",
            label="Approved",
            description="Approved by moderator",
            metadata={"is_final": True, "can_transition_to": []},
            category=ChoiceCategory.STATUS,
        ),
        RichChoice(
            value="rejected",
            label="Rejected",
            description="Rejected by moderator",
            metadata={"is_final": True, "can_transition_to": []},
            category=ChoiceCategory.STATUS,
        ),
    ]
    registry.register("test_states", choices, domain="test")
    yield choices
    registry.clear_domain("test")


def test_builder_initialization_valid(sample_choices):
    """Test builder initializes with valid choice group."""
    builder = StateTransitionBuilder("test_states", "test")
    assert builder.choice_group == "test_states"
    assert builder.domain == "test"
    assert len(builder.choices) == 3


def test_builder_initialization_invalid():
    """Test builder raises error for invalid choice group."""
    with pytest.raises(ImproperlyConfigured):
        StateTransitionBuilder("nonexistent", "test")


def test_get_choice_metadata(sample_choices):
    """Test metadata extraction for states."""
    builder = StateTransitionBuilder("test_states", "test")
    metadata = builder.get_choice_metadata("pending")
    assert "can_transition_to" in metadata
    assert metadata["can_transition_to"] == ["approved", "rejected"]


def test_extract_valid_transitions(sample_choices):
    """Test extraction of valid transitions."""
    builder = StateTransitionBuilder("test_states", "test")
    transitions = builder.extract_valid_transitions("pending")
    assert transitions == ["approved", "rejected"]


def test_extract_valid_transitions_invalid_target():
    """Test validation fails for invalid transition targets."""
    invalid_choices = [
        RichChoice(
            value="pending",
            label="Pending",
            metadata={"can_transition_to": ["nonexistent"]},
        ),
    ]
    registry.register("invalid_test", invalid_choices, domain="test")

    builder = StateTransitionBuilder("invalid_test", "test")
    with pytest.raises(ImproperlyConfigured):
        builder.extract_valid_transitions("pending")

    registry.clear_domain("test")


def test_is_terminal_state(sample_choices):
    """Test terminal state detection."""
    builder = StateTransitionBuilder("test_states", "test")
    assert not builder.is_terminal_state("pending")
    assert builder.is_terminal_state("approved")
    assert builder.is_terminal_state("rejected")


def test_build_transition_graph(sample_choices):
    """Test transition graph building."""
    builder = StateTransitionBuilder("test_states", "test")
    graph = builder.build_transition_graph()
    assert graph["pending"] == ["approved", "rejected"]
    assert graph["approved"] == []
    assert graph["rejected"] == []


def test_caching_mechanism(sample_choices):
    """Test that caching works correctly."""
    builder = StateTransitionBuilder("test_states", "test")

    # First call builds cache
    metadata1 = builder.get_choice_metadata("pending")
    # Second call uses cache
    metadata2 = builder.get_choice_metadata("pending")

    assert metadata1 == metadata2
    assert "metadata_pending" in builder._cache


def test_clear_cache(sample_choices):
    """Test cache clearing."""
    builder = StateTransitionBuilder("test_states", "test")
    builder.get_choice_metadata("pending")
    assert len(builder._cache) > 0

    builder.clear_cache()
    assert len(builder._cache) == 0


def test_get_all_states(sample_choices):
    """Test getting all state values."""
    builder = StateTransitionBuilder("test_states", "test")
    states = builder.get_all_states()
    assert set(states) == {"pending", "approved", "rejected"}


def test_get_choice(sample_choices):
    """Test getting RichChoice object."""
    builder = StateTransitionBuilder("test_states", "test")
    choice = builder.get_choice("pending")
    assert choice is not None
    assert choice.value == "pending"
    assert choice.label == "Pending"
