"""
Unit test conftest.py - Fixtures specific to unit tests.

Provides fixtures for mocking FastAPI dependencies and isolating tests
from real state and hardware connections.
"""
import pytest
from unittest.mock import MagicMock, AsyncMock, patch


@pytest.fixture
def mock_state_unit():
    """Mock state for unit tests with common defaults.

    This is a more comprehensive mock than the root conftest version,
    specifically designed for API endpoint testing where we need to
    control the application state precisely.
    """
    mock = MagicMock()

    # Connection mock
    mock.conn = MagicMock()
    mock.conn.is_connected.return_value = False
    mock.port = None
    mock.is_connected = False
    mock.preferred_port = None

    # Pattern execution state
    mock.current_playing_file = None
    mock.is_running = False
    mock.pause_requested = False
    mock.stop_requested = False
    mock.skip_requested = False
    mock.execution_progress = None
    mock.is_homing = False
    mock.is_clearing = False

    # Position state
    mock.current_theta = 0.0
    mock.current_rho = 0.0
    mock.machine_x = 0.0
    mock.machine_y = 0.0

    # Speed and settings
    mock.speed = 100
    mock.clear_pattern_speed = None
    mock.table_type = "dune_weaver"
    mock.table_type_override = None
    mock.homing = 0

    # Playlist state
    mock.current_playlist = None
    mock.current_playlist_name = None
    mock.current_playlist_index = None
    mock.playlist_mode = None
    mock.pause_time_remaining = 0
    mock.original_pause_time = None

    # LED state
    mock.led_controller = None
    mock.led_provider = "none"
    mock.wled_ip = None
    mock.hyperion_ip = None
    mock.hyperion_port = 19444
    mock.dw_led_num_leds = 60
    mock.dw_led_gpio_pin = 18
    mock.dw_led_pixel_order = "GRB"
    mock.dw_led_brightness = 50
    mock.dw_led_speed = 128
    mock.dw_led_intensity = 128
    mock.dw_led_idle_effect = "solid"
    mock.dw_led_playing_effect = "rainbow"
    mock.dw_led_idle_timeout_enabled = False
    mock.dw_led_idle_timeout_minutes = 30
    mock.dw_led_last_activity_time = 0

    # Scheduled pause
    mock.scheduled_pause_enabled = False
    mock.scheduled_pause_time_slots = []
    mock.scheduled_pause_control_wled = False
    mock.scheduled_pause_finish_pattern = False
    mock.scheduled_pause_timezone = None

    # Steps and gear ratio
    mock.x_steps_per_mm = 200.0
    mock.y_steps_per_mm = 287.0
    mock.gear_ratio = 10.0

    # Auto-home settings
    mock.auto_home_enabled = False
    mock.auto_home_after_patterns = 10
    mock.patterns_since_last_home = 0

    # Custom clear patterns
    mock.custom_clear_from_out = None
    mock.custom_clear_from_in = None

    # Homing offset
    mock.angular_homing_offset_degrees = 0.0

    # App settings
    mock.app_name = "Dune Weaver"
    mock.custom_logo_path = None

    # MQTT settings
    mock.mqtt_enabled = False
    mock.mqtt_broker = None
    mock.mqtt_port = 1883
    mock.mqtt_username = None
    mock.mqtt_password = None
    mock.mqtt_topic_prefix = "dune_weaver"

    # Table info
    mock.table_id = None
    mock.table_name = None
    mock.known_tables = []

    # Methods
    mock.save = MagicMock()
    mock.get_stop_event = MagicMock(return_value=None)
    mock.get_skip_event = MagicMock(return_value=None)
    mock.wait_for_interrupt = AsyncMock(return_value='timeout')
    mock.pause_condition = MagicMock()
    mock.pause_condition.__enter__ = MagicMock()
    mock.pause_condition.__exit__ = MagicMock()
    mock.pause_condition.notify_all = MagicMock()

    return mock


@pytest.fixture
def mock_connection_unit():
    """Mock connection for unit tests.

    Provides a connection mock that simulates a connected device
    without requiring actual hardware.
    """
    mock = MagicMock()
    mock.is_connected.return_value = True
    mock.send = MagicMock()
    mock.readline = MagicMock(return_value="ok")
    mock.in_waiting = MagicMock(return_value=0)
    mock.flush = MagicMock()
    mock.close = MagicMock()
    mock.reset_input_buffer = MagicMock()
    return mock


@pytest.fixture
def app_with_mocked_state(mock_state_unit):
    """Fixture that patches state module before importing app.

    This ensures the app uses mocked state for all operations.
    Must be used before creating async_client.
    """
    with patch("modules.core.state.state", mock_state_unit):
        with patch("modules.core.pattern_manager.state", mock_state_unit):
            with patch("modules.core.playlist_manager.state", mock_state_unit):
                with patch("modules.connection.connection_manager.state", mock_state_unit):
                    from main import app
                    yield app, mock_state_unit


@pytest.fixture
async def async_client_with_mocked_state(app_with_mocked_state):
    """AsyncClient with mocked state for isolated API testing.

    This fixture combines the app patching with the async client creation.
    """
    from httpx import ASGITransport, AsyncClient

    app, mock_state = app_with_mocked_state

    async with AsyncClient(
        transport=ASGITransport(app=app),
        base_url="http://test"
    ) as client:
        yield client, mock_state


@pytest.fixture
def cleanup_app_overrides():
    """Fixture to ensure app.dependency_overrides is cleaned up after tests."""
    from main import app

    yield

    # Cleanup after test
    app.dependency_overrides.clear()
