"""Tests for SLZB-Ultima infrared entity."""

from unittest.mock import MagicMock

from infrared_protocols.commands import Command
from pysmlight.const import Events as SmEvents
from pysmlight.exceptions import SmlightError
from pysmlight.models import IRPayload
import pytest

from homeassistant.components.infrared import (
    async_send_command,
    async_subscribe_receiver,
)
from homeassistant.const import STATE_UNKNOWN, Platform
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError

from . import get_mock_event_function
from .conftest import setup_integration

from tests.common import MockConfigEntry


class MockCommand(Command):
    """Mock InfraredCommand."""

    def __init__(self) -> None:
        """Initialize with fixed 38kHz modulation."""
        super().__init__(modulation=38000)

    def get_raw_timings(self) -> list[int]:
        """Return some fake timings."""
        return [9000, -4500, 560, -1690]


@pytest.fixture
def platforms() -> list[Platform]:
    """Platforms, which should be loaded during the test."""
    return [Platform.INFRARED]


async def test_infrared_setup_ultima(
    hass: HomeAssistant,
    mock_config_entry: MockConfigEntry,
    mock_ultima_client: MagicMock,
) -> None:
    """Test infrared entities are created for Ultima devices."""
    await setup_integration(hass, mock_config_entry)

    state = hass.states.get("infrared.mock_title_infrared_emitter")
    assert state is not None

    state = hass.states.get("infrared.mock_title_infrared_receiver")
    assert state is not None


async def test_infrared_not_created_non_ultima(
    hass: HomeAssistant,
    mock_config_entry: MockConfigEntry,
    mock_smlight_client: MagicMock,
) -> None:
    """Test infrared entities are not created for non-Ultima devices."""
    await setup_integration(hass, mock_config_entry)

    state = hass.states.get("infrared.mock_title_infrared_emitter")
    assert state is None

    state = hass.states.get("infrared.mock_title_infrared_receiver")
    assert state is None


async def test_infrared_send_command(
    hass: HomeAssistant,
    mock_config_entry: MockConfigEntry,
    mock_ultima_client: MagicMock,
) -> None:
    """Test sending IR command."""
    await setup_integration(hass, mock_config_entry)

    entity_id = "infrared.mock_title_infrared_emitter"
    state = hass.states.get(entity_id)
    assert state is not None

    await async_send_command(
        hass,
        entity_id,
        MockCommand(),
    )

    mock_ultima_client.actions.send_ir_code.assert_called_once_with(
        IRPayload.from_raw_timings([9000, 4500, 560, 1690], freq=38000)
    )


async def test_infrared_send_command_error(
    hass: HomeAssistant,
    mock_config_entry: MockConfigEntry,
    mock_ultima_client: MagicMock,
) -> None:
    """Test connection error handling."""
    await setup_integration(hass, mock_config_entry)

    entity_id = "infrared.mock_title_infrared_emitter"
    state = hass.states.get(entity_id)
    assert state is not None

    mock_ultima_client.actions.send_ir_code.side_effect = SmlightError("Failed")

    with pytest.raises(HomeAssistantError) as exc_info:
        await async_send_command(
            hass,
            entity_id,
            MockCommand(),
        )
    assert exc_info.value.translation_key == "send_ir_code_failed"


async def test_infrared_send_empty_command_error(
    hass: HomeAssistant,
    mock_config_entry: MockConfigEntry,
    mock_ultima_client: MagicMock,
) -> None:
    """Test ValueError from pysmlight is surfaced as HomeAssistantError."""
    await setup_integration(hass, mock_config_entry)

    entity_id = "infrared.mock_title_infrared_emitter"
    state = hass.states.get(entity_id)
    assert state is not None

    mock_ultima_client.actions.send_ir_code.side_effect = ValueError("empty payload")

    with pytest.raises(HomeAssistantError) as exc_info:
        await async_send_command(
            hass,
            entity_id,
            MockCommand(),
        )
    assert exc_info.value.translation_key == "send_ir_code_failed"


@pytest.mark.freeze_time("2025-09-03T22:00:00+00:00")
async def test_infrared_state_updated_after_send(
    hass: HomeAssistant,
    mock_config_entry: MockConfigEntry,
    mock_ultima_client: MagicMock,
) -> None:
    """Test that entity state is updated with a timestamp after a successful send."""
    await setup_integration(hass, mock_config_entry)

    entity_id = "infrared.mock_title_infrared_emitter"
    state = hass.states.get(entity_id)
    assert state is not None
    assert state.state == STATE_UNKNOWN

    await async_send_command(hass, entity_id, MockCommand())

    state = hass.states.get(entity_id)
    assert state.state == "2025-09-03T22:00:00.000+00:00"


@pytest.mark.freeze_time("2025-09-03T22:00:00+00:00")
async def test_infrared_receiver_event(
    hass: HomeAssistant,
    mock_config_entry: MockConfigEntry,
    mock_ultima_client: MagicMock,
) -> None:
    """Test infrared receiver receives event and updates state."""
    await setup_integration(hass, mock_config_entry)

    entity_id = "infrared.mock_title_infrared_receiver"
    state = hass.states.get(entity_id)
    assert state is not None
    assert state.state == STATE_UNKNOWN

    signals = []
    async_subscribe_receiver(hass, entity_id, signals.append)

    event_function = get_mock_event_function(mock_ultima_client, SmEvents.IR_CODE)
    assert event_function is not None

    event_function([9000, 4500, 560, 1690])
    await hass.async_block_till_done()

    state = hass.states.get(entity_id)
    assert state.state == "2025-09-03T22:00:00.000+00:00"

    assert len(signals) == 1
    assert signals[0].timings == [9000, 4500, 560, 1690]
