"""The sensor tests for the nut platform."""

from unittest.mock import patch

import pytest

from homeassistant.components.nut.const import DOMAIN
from homeassistant.components.sensor import SensorDeviceClass, SensorStateClass
from homeassistant.const import (
    ATTR_DEVICE_CLASS,
    ATTR_FRIENDLY_NAME,
    ATTR_UNIT_OF_MEASUREMENT,
    CONF_HOST,
    CONF_PORT,
    CONF_RESOURCES,
    PERCENTAGE,
    STATE_UNKNOWN,
    Platform,
    UnitOfElectricCurrent,
    UnitOfElectricPotential,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er, translation

from .util import (
    _get_mock_nutclient,
    _test_sensor_and_attributes,
    async_init_integration,
)

from tests.common import MockConfigEntry


@pytest.mark.parametrize(
    "model",
    [
        "CP1350C",
        "5E650I",
        "5E850I",
        "CP1500PFCLCD",
        "DL650ELCD",
        "EATON5P1550",
        "blazer_usb",
    ],
)
async def test_ups_devices(
    hass: HomeAssistant, entity_registry: er.EntityRegistry, model: str
) -> None:
    """Test creation of device sensors."""

    config_entry = await async_init_integration(hass, model)
    entry = entity_registry.async_get("sensor.ups1_battery_charge")
    assert entry
    assert entry.unique_id == f"{config_entry.entry_id}_battery.charge"

    state = hass.states.get("sensor.ups1_battery_charge")
    assert state.state == "100"

    expected_attributes = {
        ATTR_DEVICE_CLASS: "battery",
        ATTR_FRIENDLY_NAME: "Ups1 Battery charge",
        ATTR_UNIT_OF_MEASUREMENT: PERCENTAGE,
    }
    # Only test for a subset of attributes in case
    # HA changes the implementation and a new one appears
    assert all(
        state.attributes[key] == attr for key, attr in expected_attributes.items()
    )


@pytest.mark.parametrize(
    ("model", "unique_id"),
    [
        ("PR3000RT2U", "CPS_PR3000RT2U_PYVJO2000034_battery.charge"),
        (
            "BACKUPSES600M1",
            "American Power Conversion_Back-UPS ES 600M1_4B1713P32195 _battery.charge",
        ),
    ],
)
async def test_ups_devices_with_unique_ids(
    hass: HomeAssistant, entity_registry: er.EntityRegistry, model: str, unique_id: str
) -> None:
    """Test creation of device sensors with unique ids."""

    await async_init_integration(hass, model)
    entry = entity_registry.async_get("sensor.ups1_battery_charge")
    assert entry
    assert entry.unique_id == unique_id

    state = hass.states.get("sensor.ups1_battery_charge")
    assert state.state == "100"

    expected_attributes = {
        ATTR_DEVICE_CLASS: "battery",
        ATTR_FRIENDLY_NAME: "Ups1 Battery charge",
        ATTR_UNIT_OF_MEASUREMENT: PERCENTAGE,
    }
    # Only test for a subset of attributes in case
    # HA changes the implementation and a new one appears
    assert all(
        state.attributes[key] == attr for key, attr in expected_attributes.items()
    )


@pytest.mark.parametrize(
    ("model", "unique_id_base"),
    [
        (
            "EATON-EPDU-G3",
            "EATON_ePDU MA 00U-C IN: TYPE 00A 0P OUT: 00xTYPE_A000A00000",
        ),
    ],
)
async def test_pdu_devices_with_unique_ids(
    hass: HomeAssistant,
    entity_registry: er.EntityRegistry,
    model: str,
    unique_id_base: str,
) -> None:
    """Test creation of device sensors with unique ids."""

    await async_init_integration(hass, model)

    _test_sensor_and_attributes(
        hass,
        entity_registry,
        unique_id=f"{unique_id_base}_input.voltage",
        device_id="sensor.ups1_input_voltage",
        state_value="122.91",
        expected_attributes={
            ATTR_DEVICE_CLASS: SensorDeviceClass.VOLTAGE,
            "state_class": SensorStateClass.MEASUREMENT,
            ATTR_FRIENDLY_NAME: "Ups1 Input voltage",
            ATTR_UNIT_OF_MEASUREMENT: UnitOfElectricPotential.VOLT,
        },
    )

    _test_sensor_and_attributes(
        hass,
        entity_registry,
        unique_id=f"{unique_id_base}_ambient.humidity.status",
        device_id="sensor.ups1_ambient_humidity_status",
        state_value="good",
        expected_attributes={
            ATTR_DEVICE_CLASS: SensorDeviceClass.ENUM,
            ATTR_FRIENDLY_NAME: "Ups1 Ambient humidity status",
        },
    )

    _test_sensor_and_attributes(
        hass,
        entity_registry,
        unique_id=f"{unique_id_base}_ambient.temperature.status",
        device_id="sensor.ups1_ambient_temperature_status",
        state_value="good",
        expected_attributes={
            ATTR_DEVICE_CLASS: SensorDeviceClass.ENUM,
            ATTR_FRIENDLY_NAME: "Ups1 Ambient temperature status",
        },
    )


async def test_state_sensors(hass: HomeAssistant) -> None:
    """Test creation of status display sensors."""
    entry = MockConfigEntry(
        domain=DOMAIN,
        data={CONF_HOST: "mock", CONF_PORT: "mock"},
    )
    entry.add_to_hass(hass)

    mock_pynut = _get_mock_nutclient(
        list_ups={"ups1": "UPS 1"}, list_vars={"ups.status": "OL"}
    )

    with patch(
        "homeassistant.components.nut.AIONUTClient",
        return_value=mock_pynut,
    ):
        await hass.config_entries.async_setup(entry.entry_id)
        await hass.async_block_till_done()

        state1 = hass.states.get("sensor.ups1_status")
        state2 = hass.states.get("sensor.ups1_status_data")
        assert state1.state == "Online"
        assert state2.state == "OL"


async def test_unknown_state_sensors(hass: HomeAssistant) -> None:
    """Test creation of unknown status display sensors."""
    entry = MockConfigEntry(
        domain=DOMAIN,
        data={CONF_HOST: "mock", CONF_PORT: "mock"},
    )
    entry.add_to_hass(hass)

    mock_pynut = _get_mock_nutclient(
        list_ups={"ups1": "UPS 1"}, list_vars={"ups.status": "OQ"}
    )

    with patch(
        "homeassistant.components.nut.AIONUTClient",
        return_value=mock_pynut,
    ):
        await hass.config_entries.async_setup(entry.entry_id)
        await hass.async_block_till_done()

        state1 = hass.states.get("sensor.ups1_status")
        state2 = hass.states.get("sensor.ups1_status_data")
        assert state1.state == STATE_UNKNOWN
        assert state2.state == "OQ"


async def test_stale_options(
    hass: HomeAssistant, entity_registry: er.EntityRegistry
) -> None:
    """Test creation of sensors with stale options to remove."""
    config_entry = MockConfigEntry(
        domain=DOMAIN,
        data={
            CONF_HOST: "mock",
            CONF_PORT: "mock",
            CONF_RESOURCES: ["ups.load"],
        },
        options={CONF_RESOURCES: ["battery.charge"]},
    )
    config_entry.add_to_hass(hass)

    mock_pynut = _get_mock_nutclient(
        list_ups={"ups1": "UPS 1"}, list_vars={"battery.charge": "10"}
    )

    with patch(
        "homeassistant.components.nut.AIONUTClient",
        return_value=mock_pynut,
    ):
        await hass.config_entries.async_setup(config_entry.entry_id)
        await hass.async_block_till_done()

        entry = entity_registry.async_get("sensor.ups1_battery_charge")
        assert entry
        assert entry.unique_id == f"{config_entry.entry_id}_battery.charge"
        assert config_entry.data[CONF_RESOURCES] == ["battery.charge"]
        assert config_entry.options == {}

        state = hass.states.get("sensor.ups1_battery_charge")
        assert state.state == "10"


async def test_state_ambient_translation(hass: HomeAssistant) -> None:
    """Test translation of ambient state sensor."""
    entry = MockConfigEntry(
        domain=DOMAIN,
        data={CONF_HOST: "mock", CONF_PORT: "mock"},
    )
    entry.add_to_hass(hass)

    mock_pynut = _get_mock_nutclient(
        list_ups={"ups1": "UPS 1"}, list_vars={"ambient.humidity.status": "good"}
    )

    with patch(
        "homeassistant.components.nut.AIONUTClient",
        return_value=mock_pynut,
    ):
        await hass.config_entries.async_setup(entry.entry_id)
        await hass.async_block_till_done()

        key = "ambient_humidity_status"
        state = hass.states.get(f"sensor.ups1_{key}")
        assert state.state == "good"

        result = translation.async_translate_state(
            hass, state.state, Platform.SENSOR, DOMAIN, key, None
        )

        assert result == "Good"


@pytest.mark.parametrize(
    ("model", "unique_id_base"),
    [
        (
            "EATON-EPDU-G3-AMBIENT-NOT-PRESENT",
            "EATON_ePDU MA 00U-C IN: TYPE 00A 0P OUT: 00xTYPE_A000A00000",
        ),
    ],
)
async def test_pdu_devices_ambient_not_present(
    hass: HomeAssistant,
    entity_registry: er.EntityRegistry,
    model: str,
    unique_id_base: str,
) -> None:
    """Test that ambient sensors not created."""

    await async_init_integration(hass, model)

    entry = entity_registry.async_get("sensor.ups1_ambient_humidity")
    assert not entry

    entry = entity_registry.async_get("sensor.ups1_ambient_humidity_status")
    assert not entry

    entry = entity_registry.async_get("sensor.ups1_ambient_temperature")
    assert not entry

    entry = entity_registry.async_get("sensor.ups1_ambient_temperature_status")
    assert not entry


@pytest.mark.parametrize(
    ("model", "unique_id_base"),
    [
        (
            "EATON-EPDU-G3",
            "EATON_ePDU MA 00U-C IN: TYPE 00A 0P OUT: 00xTYPE_A000A00000",
        ),
    ],
)
async def test_pdu_dynamic_outlets(
    hass: HomeAssistant,
    entity_registry: er.EntityRegistry,
    model: str,
    unique_id_base: str,
) -> None:
    """Test for dynamically created outlet sensors."""

    await async_init_integration(hass, model)

    _test_sensor_and_attributes(
        hass,
        entity_registry,
        unique_id=f"{unique_id_base}_outlet.1.current",
        device_id="sensor.ups1_outlet_a1_current",
        state_value="0",
        expected_attributes={
            ATTR_DEVICE_CLASS: SensorDeviceClass.CURRENT,
            ATTR_FRIENDLY_NAME: "Ups1 Outlet A1 current",
            ATTR_UNIT_OF_MEASUREMENT: UnitOfElectricCurrent.AMPERE,
        },
    )

    _test_sensor_and_attributes(
        hass,
        entity_registry,
        unique_id=f"{unique_id_base}_outlet.24.current",
        device_id="sensor.ups1_outlet_a24_current",
        state_value="0.19",
        expected_attributes={
            ATTR_DEVICE_CLASS: SensorDeviceClass.CURRENT,
            ATTR_FRIENDLY_NAME: "Ups1 Outlet A24 current",
            ATTR_UNIT_OF_MEASUREMENT: UnitOfElectricCurrent.AMPERE,
        },
    )

    entry = entity_registry.async_get("sensor.ups1_outlet_25_current")
    assert not entry

    entry = entity_registry.async_get("sensor.ups1_outlet_a25_current")
    assert not entry