"""Tests for the ARWN sensor platform."""

import json
from typing import Any

import pytest

from homeassistant.components.sensor import SensorDeviceClass, SensorStateClass
from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component

from tests.common import async_fire_mqtt_message
from tests.typing import MqttMockHAClient


async def test_temperature_sensor_created(
    hass: HomeAssistant,
    mqtt_mock: MqttMockHAClient,
) -> None:
    """Test that a temperature MQTT message creates a sensor entity."""
    assert await async_setup_component(
        hass,
        "sensor",
        {"sensor": {"platform": "arwn"}},
    )
    await hass.async_block_till_done()

    async_fire_mqtt_message(
        hass,
        "arwn/temperature/BackYard",
        json.dumps({"temp": 22.5, "units": "C"}),
    )
    await hass.async_block_till_done()

    state = hass.states.get("sensor.backyard_temperature")
    assert state is not None
    assert state.state == "22.5"
    assert state.attributes["device_class"] == SensorDeviceClass.TEMPERATURE
    assert state.attributes["state_class"] == SensorStateClass.MEASUREMENT


async def test_temperature_sensor_updates(
    hass: HomeAssistant,
    mqtt_mock: MqttMockHAClient,
) -> None:
    """Test that a second MQTT message updates an existing sensor."""
    assert await async_setup_component(
        hass,
        "sensor",
        {"sensor": {"platform": "arwn"}},
    )
    await hass.async_block_till_done()

    async_fire_mqtt_message(
        hass,
        "arwn/temperature/BackYard",
        json.dumps({"temp": 22.5, "units": "C"}),
    )
    await hass.async_block_till_done()

    async_fire_mqtt_message(
        hass,
        "arwn/temperature/BackYard",
        json.dumps({"temp": 25.0, "units": "C"}),
    )
    await hass.async_block_till_done()

    state = hass.states.get("sensor.backyard_temperature")
    assert state is not None
    assert state.state == "25.0"


async def test_rain_rate_exposed_total_suppressed(
    hass: HomeAssistant,
    mqtt_mock: MqttMockHAClient,
) -> None:
    """Test rain/rate is created but rain/total is suppressed (expose=False)."""
    assert await async_setup_component(
        hass,
        "sensor",
        {"sensor": {"platform": "arwn"}},
    )
    await hass.async_block_till_done()

    async_fire_mqtt_message(
        hass,
        "arwn/rain",
        json.dumps({"total": 1.2, "rate": 0.05, "units": "in"}),
    )
    await hass.async_block_till_done()

    assert hass.states.get("sensor.rainfall_rate") is not None
    assert hass.states.get("sensor.total_rainfall") is None


@pytest.mark.parametrize(
    ("topic", "payload", "entity_id", "expected_state"),
    [
        pytest.param(
            "arwn/temperature/BackYard",
            {"temp": 22.5, "units": "C"},
            "sensor.backyard_temperature",
            "22.5",
            id="temperature",
        ),
        pytest.param(
            "arwn/barometer",
            {"pressure": 1013.25, "units": "mb"},
            "sensor.barometer",
            "1013.25",
            id="barometer",
        ),
        pytest.param(
            "arwn/moisture/FrontLawn",
            {"moisture": 45.2, "units": "%"},
            "sensor.frontlawn_moisture",
            "45.2",
            id="moisture",
        ),
    ],
)
async def test_single_reading_sensor_created(
    hass: HomeAssistant,
    mqtt_mock: MqttMockHAClient,
    topic: str,
    payload: dict[str, Any],
    entity_id: str,
    expected_state: str,
) -> None:
    """Test single-reading sensor types are discovered and populated."""
    assert await async_setup_component(
        hass,
        "sensor",
        {"sensor": {"platform": "arwn"}},
    )
    await hass.async_block_till_done()

    async_fire_mqtt_message(hass, topic, json.dumps(payload))
    await hass.async_block_till_done()

    state = hass.states.get(entity_id)
    assert state is not None
    assert state.state == expected_state


async def test_wind_sensors_created(
    hass: HomeAssistant,
    mqtt_mock: MqttMockHAClient,
) -> None:
    """Test wind message creates speed, gust, and direction sensors."""
    assert await async_setup_component(
        hass,
        "sensor",
        {"sensor": {"platform": "arwn"}},
    )
    await hass.async_block_till_done()

    async_fire_mqtt_message(
        hass,
        "arwn/wind",
        json.dumps({"speed": 12.3, "gust": 18.0, "direction": 270, "units": "mph"}),
    )
    await hass.async_block_till_done()

    assert hass.states.get("sensor.wind_speed") is not None
    assert hass.states.get("sensor.wind_gust") is not None
    assert hass.states.get("sensor.wind_direction") is not None
    assert hass.states.get("sensor.wind_direction").state == "270"


async def test_unknown_topic_ignored(
    hass: HomeAssistant,
    mqtt_mock: MqttMockHAClient,
) -> None:
    """Test that messages on unknown topics do not create sensors."""
    assert await async_setup_component(
        hass,
        "sensor",
        {"sensor": {"platform": "arwn"}},
    )
    await hass.async_block_till_done()

    async_fire_mqtt_message(hass, "arwn/unknown_domain", json.dumps({"value": 1.0}))
    await hass.async_block_till_done()

    assert hass.data.get("arwn") is None


async def test_wind_direction_state_class(
    hass: HomeAssistant,
    mqtt_mock: MqttMockHAClient,
) -> None:
    """Test wind direction sensor has measurement_angle state class."""
    assert await async_setup_component(
        hass,
        "sensor",
        {"sensor": {"platform": "arwn"}},
    )
    await hass.async_block_till_done()

    async_fire_mqtt_message(
        hass,
        "arwn/wind",
        json.dumps({"speed": 12.3, "gust": 18.0, "direction": 270, "units": "mph"}),
    )
    await hass.async_block_till_done()

    state = hass.states.get("sensor.wind_direction")
    assert state is not None
    assert state.state == "270"
    assert state.attributes["state_class"] == SensorStateClass.MEASUREMENT_ANGLE


async def test_malformed_json_ignored(
    hass: HomeAssistant,
    mqtt_mock: MqttMockHAClient,
) -> None:
    """Test that a malformed JSON payload does not raise and is silently ignored."""
    assert await async_setup_component(
        hass,
        "sensor",
        {"sensor": {"platform": "arwn"}},
    )
    await hass.async_block_till_done()

    async_fire_mqtt_message(hass, "arwn/temperature/BackYard", "not valid json{{")
    await hass.async_block_till_done()

    assert hass.data.get("arwn") is None
