"""Tests for the Actron Air climate platform."""

from unittest.mock import MagicMock, patch

from actron_neo_api import ActronAirAPIError
from actron_neo_api.models.settings import ActronAirModeSupport
import pytest
from syrupy.assertion import SnapshotAssertion

from homeassistant.components.actron_air.climate import (
    ActronSystemClimate,
    ActronZoneClimate,
)
from homeassistant.components.climate import (
    ATTR_FAN_MODE,
    ATTR_HVAC_MODE,
    ATTR_TARGET_TEMP_HIGH,
    ATTR_TARGET_TEMP_LOW,
    DOMAIN as CLIMATE_DOMAIN,
    SERVICE_SET_FAN_MODE,
    SERVICE_SET_HVAC_MODE,
    SERVICE_SET_TEMPERATURE,
    HVACMode,
)
from homeassistant.const import ATTR_ENTITY_ID, ATTR_TEMPERATURE, Platform
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
from homeassistant.helpers import entity_registry as er

from . import setup_integration

from tests.common import MockConfigEntry, snapshot_platform


async def test_climate_entities(
    hass: HomeAssistant,
    mock_actron_api: MagicMock,
    entity_registry: er.EntityRegistry,
    snapshot: SnapshotAssertion,
    mock_config_entry: MockConfigEntry,
    mock_zone: MagicMock,
) -> None:
    """Test climate entities."""
    status = mock_actron_api.state_manager.get_status.return_value
    status.remote_zone_info = [mock_zone]

    with patch("homeassistant.components.actron_air.PLATFORMS", [Platform.CLIMATE]):
        await setup_integration(hass, mock_config_entry)
    await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)


async def test_system_set_temperature(
    hass: HomeAssistant,
    mock_actron_api: MagicMock,
    mock_config_entry: MockConfigEntry,
) -> None:
    """Test setting temperature for system climate entity."""
    with patch("homeassistant.components.actron_air.PLATFORMS", [Platform.CLIMATE]):
        await setup_integration(hass, mock_config_entry)

    status = mock_actron_api.state_manager.get_status.return_value

    await hass.services.async_call(
        CLIMATE_DOMAIN,
        SERVICE_SET_TEMPERATURE,
        {ATTR_ENTITY_ID: "climate.test_system", ATTR_TEMPERATURE: 22.5},
        blocking=True,
    )

    status.user_aircon_settings.set_temperature.assert_awaited_once_with(
        temperature=22.5
    )


async def test_system_set_temperature_api_error(
    hass: HomeAssistant,
    mock_actron_api: MagicMock,
    mock_config_entry: MockConfigEntry,
) -> None:
    """Test API error when setting temperature for system climate entity."""
    with patch("homeassistant.components.actron_air.PLATFORMS", [Platform.CLIMATE]):
        await setup_integration(hass, mock_config_entry)

    status = mock_actron_api.state_manager.get_status.return_value
    status.user_aircon_settings.set_temperature.side_effect = ActronAirAPIError(
        "Test error"
    )

    with pytest.raises(HomeAssistantError, match="Test error"):
        await hass.services.async_call(
            CLIMATE_DOMAIN,
            SERVICE_SET_TEMPERATURE,
            {ATTR_ENTITY_ID: "climate.test_system", ATTR_TEMPERATURE: 22.5},
            blocking=True,
        )


async def test_system_set_temperature_missing_temperature(
    hass: HomeAssistant,
    mock_actron_api: MagicMock,
    mock_config_entry: MockConfigEntry,
) -> None:
    """Test validation when temperature is not provided for system entity."""
    with patch("homeassistant.components.actron_air.PLATFORMS", [Platform.CLIMATE]):
        await setup_integration(hass, mock_config_entry)

    coordinator = next(
        iter(mock_config_entry.runtime_data.system_coordinators.values())
    )
    entity = ActronSystemClimate(coordinator)
    status = mock_actron_api.state_manager.get_status.return_value

    with pytest.raises(ServiceValidationError):
        await entity.async_set_temperature(
            **{ATTR_TARGET_TEMP_HIGH: 24, ATTR_TARGET_TEMP_LOW: 18}
        )

    status.user_aircon_settings.set_temperature.assert_not_awaited()


async def test_system_set_fan_mode(
    hass: HomeAssistant,
    mock_actron_api: MagicMock,
    mock_config_entry: MockConfigEntry,
) -> None:
    """Test setting fan mode for system climate entity."""
    with patch("homeassistant.components.actron_air.PLATFORMS", [Platform.CLIMATE]):
        await setup_integration(hass, mock_config_entry)

    status = mock_actron_api.state_manager.get_status.return_value

    await hass.services.async_call(
        CLIMATE_DOMAIN,
        SERVICE_SET_FAN_MODE,
        {ATTR_ENTITY_ID: "climate.test_system", ATTR_FAN_MODE: "low"},
        blocking=True,
    )

    status.user_aircon_settings.set_fan_mode.assert_awaited_once_with("LOW")


async def test_system_set_fan_mode_api_error(
    hass: HomeAssistant,
    mock_actron_api: MagicMock,
    mock_config_entry: MockConfigEntry,
) -> None:
    """Test API error when setting fan mode for system climate entity."""
    with patch("homeassistant.components.actron_air.PLATFORMS", [Platform.CLIMATE]):
        await setup_integration(hass, mock_config_entry)

    status = mock_actron_api.state_manager.get_status.return_value
    status.user_aircon_settings.set_fan_mode.side_effect = ActronAirAPIError(
        "Test error"
    )

    with pytest.raises(HomeAssistantError, match="Test error"):
        await hass.services.async_call(
            CLIMATE_DOMAIN,
            SERVICE_SET_FAN_MODE,
            {ATTR_ENTITY_ID: "climate.test_system", ATTR_FAN_MODE: "high"},
            blocking=True,
        )


async def test_system_set_hvac_mode(
    hass: HomeAssistant,
    mock_actron_api: MagicMock,
    mock_config_entry: MockConfigEntry,
) -> None:
    """Test setting HVAC mode for system climate entity."""
    with patch("homeassistant.components.actron_air.PLATFORMS", [Platform.CLIMATE]):
        await setup_integration(hass, mock_config_entry)

    status = mock_actron_api.state_manager.get_status.return_value

    await hass.services.async_call(
        CLIMATE_DOMAIN,
        SERVICE_SET_HVAC_MODE,
        {ATTR_ENTITY_ID: "climate.test_system", ATTR_HVAC_MODE: HVACMode.COOL},
        blocking=True,
    )

    status.ac_system.set_system_mode.assert_awaited_once_with("COOL")


async def test_system_set_hvac_mode_api_error(
    hass: HomeAssistant,
    mock_actron_api: MagicMock,
    mock_config_entry: MockConfigEntry,
) -> None:
    """Test API error when setting HVAC mode for system climate entity."""
    with patch("homeassistant.components.actron_air.PLATFORMS", [Platform.CLIMATE]):
        await setup_integration(hass, mock_config_entry)

    status = mock_actron_api.state_manager.get_status.return_value
    status.ac_system.set_system_mode.side_effect = ActronAirAPIError("Test error")

    with pytest.raises(HomeAssistantError, match="Test error"):
        await hass.services.async_call(
            CLIMATE_DOMAIN,
            SERVICE_SET_HVAC_MODE,
            {ATTR_ENTITY_ID: "climate.test_system", ATTR_HVAC_MODE: HVACMode.HEAT},
            blocking=True,
        )


async def test_zone_set_temperature(
    hass: HomeAssistant,
    init_integration_with_zone: None,
    mock_zone: MagicMock,
) -> None:
    """Test setting temperature for zone climate entity."""
    await hass.services.async_call(
        CLIMATE_DOMAIN,
        SERVICE_SET_TEMPERATURE,
        {ATTR_ENTITY_ID: "climate.living_room_living_room", ATTR_TEMPERATURE: 23.0},
        blocking=True,
    )

    mock_zone.set_temperature.assert_awaited_once_with(temperature=23.0)


async def test_zone_set_temperature_api_error(
    hass: HomeAssistant,
    init_integration_with_zone: None,
    mock_zone: MagicMock,
) -> None:
    """Test API error when setting temperature for zone climate entity."""
    mock_zone.set_temperature.side_effect = ActronAirAPIError("Test error")

    with pytest.raises(HomeAssistantError, match="Test error"):
        await hass.services.async_call(
            CLIMATE_DOMAIN,
            SERVICE_SET_TEMPERATURE,
            {ATTR_ENTITY_ID: "climate.living_room_living_room", ATTR_TEMPERATURE: 23.0},
            blocking=True,
        )


async def test_zone_set_temperature_missing_temperature(
    hass: HomeAssistant,
    init_integration_with_zone: None,
    mock_config_entry: MockConfigEntry,
    mock_zone: MagicMock,
) -> None:
    """Test validation when temperature is not provided for zone entity."""
    coordinator = next(
        iter(mock_config_entry.runtime_data.system_coordinators.values())
    )
    entity = ActronZoneClimate(coordinator, mock_zone)

    with pytest.raises(ServiceValidationError):
        await entity.async_set_temperature(
            **{ATTR_TARGET_TEMP_HIGH: 24, ATTR_TARGET_TEMP_LOW: 18}
        )

    mock_zone.set_temperature.assert_not_awaited()


async def test_zone_set_hvac_mode_on(
    hass: HomeAssistant,
    init_integration_with_zone: None,
    mock_zone: MagicMock,
) -> None:
    """Test setting HVAC mode to on for zone climate entity."""
    mock_zone.is_active = False
    mock_zone.hvac_mode = "OFF"

    await hass.services.async_call(
        CLIMATE_DOMAIN,
        SERVICE_SET_HVAC_MODE,
        {
            ATTR_ENTITY_ID: "climate.living_room_living_room",
            ATTR_HVAC_MODE: HVACMode.COOL,
        },
        blocking=True,
    )

    mock_zone.enable.assert_awaited_once_with(True)


async def test_zone_set_hvac_mode_off(
    hass: HomeAssistant,
    init_integration_with_zone: None,
    mock_zone: MagicMock,
) -> None:
    """Test setting HVAC mode to off for zone climate entity."""
    await hass.services.async_call(
        CLIMATE_DOMAIN,
        SERVICE_SET_HVAC_MODE,
        {
            ATTR_ENTITY_ID: "climate.living_room_living_room",
            ATTR_HVAC_MODE: HVACMode.OFF,
        },
        blocking=True,
    )

    mock_zone.enable.assert_awaited_once_with(False)


async def test_zone_set_hvac_mode_api_error(
    hass: HomeAssistant,
    init_integration_with_zone: None,
    mock_zone: MagicMock,
) -> None:
    """Test API error when setting HVAC mode for zone climate entity."""
    mock_zone.enable.side_effect = ActronAirAPIError("Test error")

    with pytest.raises(HomeAssistantError, match="Test error"):
        await hass.services.async_call(
            CLIMATE_DOMAIN,
            SERVICE_SET_HVAC_MODE,
            {
                ATTR_ENTITY_ID: "climate.living_room_living_room",
                ATTR_HVAC_MODE: HVACMode.OFF,
            },
            blocking=True,
        )


async def test_system_hvac_mode_unmapped(
    hass: HomeAssistant,
    mock_actron_api: MagicMock,
    mock_config_entry: MockConfigEntry,
) -> None:
    """Test system climate entity returns None for unmapped HVAC mode."""
    status = mock_actron_api.state_manager.get_status.return_value
    status.user_aircon_settings.is_on = True
    status.user_aircon_settings.mode = "UNKNOWN_MODE"

    with patch("homeassistant.components.actron_air.PLATFORMS", [Platform.CLIMATE]):
        await setup_integration(hass, mock_config_entry)

    state = hass.states.get("climate.test_system")
    assert state.state == "unknown"


async def test_zone_hvac_mode_unmapped(
    hass: HomeAssistant,
    mock_actron_api: MagicMock,
    mock_config_entry: MockConfigEntry,
    mock_zone: MagicMock,
) -> None:
    """Test zone climate entity returns None for unmapped HVAC mode."""
    mock_zone.is_active = True
    mock_zone.hvac_mode = "UNKNOWN_MODE"

    status = mock_actron_api.state_manager.get_status.return_value
    status.remote_zone_info = [mock_zone]

    with patch("homeassistant.components.actron_air.PLATFORMS", [Platform.CLIMATE]):
        await setup_integration(hass, mock_config_entry)

    state = hass.states.get("climate.living_room_living_room")
    assert state.state == "unknown"


async def test_zone_hvac_mode_inactive(
    hass: HomeAssistant,
    mock_actron_api: MagicMock,
    mock_config_entry: MockConfigEntry,
    mock_zone: MagicMock,
) -> None:
    """Test zone climate entity returns OFF when zone is inactive."""
    mock_zone.is_active = False

    status = mock_actron_api.state_manager.get_status.return_value
    status.remote_zone_info = [mock_zone]

    with patch("homeassistant.components.actron_air.PLATFORMS", [Platform.CLIMATE]):
        await setup_integration(hass, mock_config_entry)

    state = hass.states.get("climate.living_room_living_room")
    assert state.state == "off"


async def test_system_hvac_modes_default(
    hass: HomeAssistant,
    mock_actron_api: MagicMock,
    mock_config_entry: MockConfigEntry,
) -> None:
    """Test system reports correct HVAC modes when DRY is not supported."""
    with patch("homeassistant.components.actron_air.PLATFORMS", [Platform.CLIMATE]):
        await setup_integration(hass, mock_config_entry)

    state = hass.states.get("climate.test_system")
    assert state.attributes["hvac_modes"] == [
        HVACMode.COOL,
        HVACMode.HEAT,
        HVACMode.FAN_ONLY,
        HVACMode.AUTO,
        HVACMode.OFF,
    ]


async def test_system_hvac_modes_with_dry(
    hass: HomeAssistant,
    mock_actron_api: MagicMock,
    mock_config_entry: MockConfigEntry,
) -> None:
    """Test system reports DRY HVAC mode when hardware supports it."""

    status = mock_actron_api.state_manager.get_status.return_value
    status.user_aircon_settings.mode_support = ActronAirModeSupport(
        Cool=True, Heat=True, Fan=True, Auto=True, Dry=True
    )

    with patch("homeassistant.components.actron_air.PLATFORMS", [Platform.CLIMATE]):
        await setup_integration(hass, mock_config_entry)

    state = hass.states.get("climate.test_system")
    assert state.attributes["hvac_modes"] == [
        HVACMode.COOL,
        HVACMode.HEAT,
        HVACMode.FAN_ONLY,
        HVACMode.AUTO,
        HVACMode.DRY,
        HVACMode.OFF,
    ]


async def test_system_hvac_modes_no_mode_support(
    hass: HomeAssistant,
    mock_actron_api: MagicMock,
    mock_config_entry: MockConfigEntry,
) -> None:
    """Test system falls back to default modes when ModeSupport is absent."""
    status = mock_actron_api.state_manager.get_status.return_value
    status.user_aircon_settings.mode_support = None

    with patch("homeassistant.components.actron_air.PLATFORMS", [Platform.CLIMATE]):
        await setup_integration(hass, mock_config_entry)

    state = hass.states.get("climate.test_system")
    assert state.attributes["hvac_modes"] == [
        HVACMode.COOL,
        HVACMode.HEAT,
        HVACMode.FAN_ONLY,
        HVACMode.AUTO,
        HVACMode.OFF,
    ]


async def test_zone_hvac_modes_with_dry(
    hass: HomeAssistant,
    mock_actron_api: MagicMock,
    mock_config_entry: MockConfigEntry,
    mock_zone: MagicMock,
) -> None:
    """Test zone reports DRY HVAC mode when hardware supports it."""

    status = mock_actron_api.state_manager.get_status.return_value
    status.user_aircon_settings.mode_support = ActronAirModeSupport(
        Cool=True, Heat=True, Fan=True, Auto=True, Dry=True
    )
    status.remote_zone_info = [mock_zone]

    with patch("homeassistant.components.actron_air.PLATFORMS", [Platform.CLIMATE]):
        await setup_integration(hass, mock_config_entry)

    state = hass.states.get("climate.living_room_living_room")
    assert state.attributes["hvac_modes"] == [
        HVACMode.COOL,
        HVACMode.HEAT,
        HVACMode.FAN_ONLY,
        HVACMode.AUTO,
        HVACMode.DRY,
        HVACMode.OFF,
    ]


async def test_zone_hvac_modes_no_mode_support(
    hass: HomeAssistant,
    mock_actron_api: MagicMock,
    mock_config_entry: MockConfigEntry,
    mock_zone: MagicMock,
) -> None:
    """Test zone falls back to default modes when ModeSupport is absent."""
    status = mock_actron_api.state_manager.get_status.return_value
    status.user_aircon_settings.mode_support = None
    status.remote_zone_info = [mock_zone]

    with patch("homeassistant.components.actron_air.PLATFORMS", [Platform.CLIMATE]):
        await setup_integration(hass, mock_config_entry)

    state = hass.states.get("climate.living_room_living_room")
    assert state.attributes["hvac_modes"] == [
        HVACMode.COOL,
        HVACMode.HEAT,
        HVACMode.FAN_ONLY,
        HVACMode.AUTO,
        HVACMode.OFF,
    ]
