"""Test ESPHome entry data."""

from unittest.mock import Mock, patch

from aioesphomeapi import (
    APIClient,
    EntityCategory as ESPHomeEntityCategory,
    SensorInfo,
    SensorState,
)

from homeassistant.components.esphome import DOMAIN
from homeassistant.components.esphome.entry_data import RuntimeEntryData
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
from homeassistant.core import HomeAssistant
from homeassistant.helpers import discovery_flow, entity_registry as er
from homeassistant.helpers.service_info.esphome import ESPHomeServiceInfo

from .conftest import MockGenericDeviceEntryType


async def test_migrate_entity_unique_id_downgrade_upgrade(
    hass: HomeAssistant,
    entity_registry: er.EntityRegistry,
    mock_client: APIClient,
    mock_generic_device_entry: MockGenericDeviceEntryType,
) -> None:
    """Test unique id migration prefers the original entity on downgrade upgrade."""
    entity_registry.async_get_or_create(
        SENSOR_DOMAIN,
        DOMAIN,
        "my_sensor",
        suggested_object_id="old_sensor",
        disabled_by=None,
    )
    entity_registry.async_get_or_create(
        SENSOR_DOMAIN,
        DOMAIN,
        "11:22:33:44:55:AA-sensor-mysensor",
        suggested_object_id="new_sensor",
        disabled_by=None,
    )
    entity_info = [
        SensorInfo(
            object_id="mysensor",
            key=1,
            name="my sensor",
            entity_category=ESPHomeEntityCategory.DIAGNOSTIC,
            icon="mdi:leaf",
        )
    ]
    states = [SensorState(key=1, state=50)]
    user_service = []
    await mock_generic_device_entry(
        mock_client=mock_client,
        entity_info=entity_info,
        user_service=user_service,
        states=states,
    )
    state = hass.states.get("sensor.new_sensor")
    assert state is not None
    assert state.state == "50"
    entry = entity_registry.async_get("sensor.new_sensor")
    assert entry is not None
    # Confirm we did not touch the entity that was created
    # on downgrade so when they upgrade again they can delete the
    # entity that was only created on downgrade and they keep
    # the original one.
    assert (
        entity_registry.async_get_entity_id(SENSOR_DOMAIN, DOMAIN, "my_sensor")
        is not None
    )
    # Note that ESPHome includes the EntityInfo type in the unique id
    # as this is not a 1:1 mapping to the entity platform (ie. text_sensor)
    assert entry.unique_id == "11:22:33:44:55:AA-sensor-mysensor"


async def test_discover_zwave() -> None:
    """Test ESPHome discovery of Z-Wave JS."""
    hass = Mock()
    entry_data = RuntimeEntryData(
        "mock-id",
        "mock-title",
        Mock(
            connected_address="mock-client-address",
            port=1234,
            noise_psk=None,
        ),
        None,
    )
    device_info = Mock(
        mac_address="mock-device-info-mac",
        zwave_proxy_feature_flags=1,
        zwave_home_id=1234,
    )
    device_info.name = "mock-device-infoname"

    with patch(
        "homeassistant.helpers.discovery_flow.async_create_flow"
    ) as mock_create_flow:
        entry_data.async_on_connect(
            hass,
            device_info,
            None,
        )
        mock_create_flow.assert_called_once_with(
            hass,
            "zwave_js",
            {"source": "esphome"},
            ESPHomeServiceInfo(
                name="mock-device-infoname",
                zwave_home_id=1234,
                ip_address="mock-client-address",
                port=1234,
                noise_psk=None,
            ),
            discovery_key=discovery_flow.DiscoveryKey(
                domain="esphome",
                key="mock-device-info-mac",
                version=1,
            ),
        )


async def test_discover_zwave_without_home_id() -> None:
    """Test ESPHome does not start Z-Wave discovery without home ID."""
    hass = Mock()
    entry_data = RuntimeEntryData(
        "mock-id",
        "mock-title",
        Mock(
            connected_address="mock-client-address",
            port=1234,
            noise_psk=None,
        ),
        None,
    )
    device_info = Mock(
        mac_address="mock-device-info-mac",
        zwave_proxy_feature_flags=1,
        zwave_home_id=0,  # No home ID (fresh adapter or unplugged)
    )
    device_info.name = "mock-device-infoname"

    with patch(
        "homeassistant.helpers.discovery_flow.async_create_flow"
    ) as mock_create_flow:
        entry_data.async_on_connect(
            hass,
            device_info,
            None,
        )
        # Verify async_create_flow was NOT called when zwave_home_id is 0
        mock_create_flow.assert_not_called()
