"""Fixtures for Midea tests."""

from collections.abc import Callable, Generator
from typing import Any
from unittest.mock import AsyncMock, patch

from midealocal.const import DeviceType
import pytest

from homeassistant.components.midea.const import CONF_KEY, CONF_SUBTYPE, DOMAIN
from homeassistant.const import CONF_NAME, CONF_TOKEN, CONF_TYPE
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er

from .const import (
    BASE_DATA,
    TEST_DEVICE_ID,
    TEST_KEY,
    TEST_MAC_ADDRESS,
    TEST_MODEL,
    TEST_NAME,
    TEST_SERIAL_NUMBER,
    TEST_SUBTYPE,
    TEST_TOKEN,
)

from tests.common import MockConfigEntry


class DummyDevice:
    """Shared fake Midea device for tests."""

    def __init__(
        self,
        device_type: DeviceType,
        *,
        attributes: dict | None = None,
    ) -> None:
        """Initialize fake device."""
        self.device_type = device_type
        self.device_id = TEST_DEVICE_ID
        self.name = TEST_NAME
        self.model = TEST_MODEL
        self.subtype = TEST_SUBTYPE
        self.available = False
        self.attributes = attributes or {}
        self._callbacks: list[Callable] = []
        self.calls: list[tuple] = []
        self.temperature_step = 1
        self.fan_modes = ["Low", "Medium", "High", "Auto"]
        self.modes = [
            "Auto",
            "ECO",
            "Sleep",
            "Anti-freezing",
            "Comfort",
            "Constant-temperature",
            "Normal",
            "Fast-heating",
            "Standby",
        ]
        self.mac = TEST_MAC_ADDRESS
        self.serial_number = TEST_SERIAL_NUMBER

    def register_update(self, callback: Callable) -> None:
        """Record update callback registration."""
        self._callbacks.append(callback)

    def unregister_update(self, callback: Callable) -> None:
        """Record update callback removal."""
        self._callbacks.remove(callback)

    def notify_update(self, status: dict[str, Any]) -> None:
        """Notify all registered callbacks with new state."""
        for callback in self._callbacks.copy():
            callback(status)

    def get_attribute(self, attr: str) -> Any:
        """Return attribute value."""
        return self.attributes.get(attr)

    def set_attribute(self, attr: str, value: Any) -> None:
        """Record set attribute call."""
        self.calls.append(("set_attribute", attr, value))

    def set_target_temperature(self, **kwargs: Any) -> None:
        """Record set target temperature call."""
        self.calls.append(("set_target_temperature", kwargs))

    def set_swing(self, **kwargs: Any) -> None:
        """Record set swing call."""
        self.calls.append(("set_swing", kwargs))

    def set_mode(self, zone: int, mode: int) -> None:
        """Record set mode call."""
        self.calls.append(("set_mode", zone, mode))

    def connect(self, check_protocol: bool = False) -> bool:
        """Record connect call and mirror midealocal's availability handling."""
        self.calls.append(("connect", check_protocol))
        self.available = check_protocol
        return check_protocol

    def open(self) -> None:
        """Record open call."""
        self.calls.append(("open",))

    def close(self) -> None:
        """Record close call."""
        self.calls.append(("close",))

    def close_socket(self) -> None:
        """Record close_socket call."""
        self.calls.append(("close_socket",))


def default_ac_device() -> DummyDevice:
    """Return a default AC device for tests."""
    return DummyDevice(
        DeviceType.AC,
        attributes={
            "power": True,
            "mode": 1,
            "target_temperature": 22.0,
            "indoor_temperature": 21.0,
            "fan_speed": 103,
            "swing_vertical": True,
            "swing_horizontal": True,
            "indoor_humidity": 50,
        },
    )


def entity_entries(
    hass: HomeAssistant, entry: MockConfigEntry
) -> dict[str, er.RegistryEntry]:
    """Return entity registry entries for a config entry, keyed by unique id."""
    entity_registry = er.async_get(hass)
    return {
        entity_entry.unique_id: entity_entry
        for entity_entry in er.async_entries_for_config_entry(
            entity_registry, entry.entry_id
        )
    }


@pytest.fixture
def mock_setup_entry() -> Generator[AsyncMock]:
    """Prevent loading the integration during config flow tests."""
    with patch(
        "homeassistant.components.midea.async_setup_entry",
        return_value=True,
    ) as mock_entry:
        yield mock_entry


@pytest.fixture
def mock_config_entry() -> Callable[[DummyDevice], MockConfigEntry]:
    """Return a function that creates a mock config entry for a given device."""

    def _create(device: DummyDevice) -> MockConfigEntry:
        return MockConfigEntry(
            domain=DOMAIN,
            data={
                **BASE_DATA,
                CONF_TYPE: device.device_type,
                CONF_NAME: TEST_NAME,
                CONF_TOKEN: TEST_TOKEN,
                CONF_KEY: TEST_KEY,
                CONF_SUBTYPE: TEST_SUBTYPE,
            },
        )

    return _create
