"""Tests for the Risco integration."""

import logging
from typing import Any, cast
from unittest.mock import AsyncMock, MagicMock, patch

from pyrisco import OperationError
import pytest

from homeassistant.components.risco.const import (
    CONF_COMMUNICATION_DELAY,
    DEFAULT_CONCURRENCY,
    DOMAIN,
    TYPE_LOCAL,
)
from homeassistant.const import CONF_HOST, CONF_PIN, CONF_PORT, CONF_TYPE
from homeassistant.core import HomeAssistant

from tests.common import MockConfigEntry


@pytest.fixture
def mock_error_handler() -> MagicMock:
    """Create a mock for add_error_handler."""
    with patch("homeassistant.components.risco.RiscoLocal.add_error_handler") as mock:
        yield mock


async def test_connection_reset(
    hass: HomeAssistant,
    two_zone_local: dict[int, Any],
    mock_error_handler: MagicMock,
    setup_risco_local: MockConfigEntry,
    caplog: pytest.LogCaptureFixture,
) -> None:
    """Test that ConnectionResetError triggers a reload but generic errors do not."""
    callback = mock_error_handler.call_args.args[0]
    assert callback is not None

    local_data = setup_risco_local.runtime_data.local_data
    disconnect_mock = cast(AsyncMock, local_data.system.disconnect)
    connect_mock = cast(AsyncMock, local_data.system.connect)

    caplog.set_level(logging.DEBUG, logger="homeassistant.components.risco")

    # Generic error should not trigger reload — unload/setup not invoked again
    await callback(Exception())
    await hass.async_block_till_done()
    disconnect_mock.assert_not_called()
    assert connect_mock.call_count == 1

    # ConnectionResetError should trigger a reload
    await callback(ConnectionResetError())
    await hass.async_block_till_done()
    disconnect_mock.assert_awaited_once()
    assert connect_mock.call_count == 2
    assert "Disconnected from panel. Reloading integration" in caplog.text


async def test_unload_handles_disconnect_error(
    hass: HomeAssistant,
    two_zone_local: dict[int, Any],
    setup_risco_local: MockConfigEntry,
) -> None:
    """Test unload succeeds when local disconnect errors out."""
    with patch(
        "homeassistant.components.risco.RiscoLocal.disconnect",
        side_effect=RuntimeError("disconnect failed"),
    ) as disconnect_mock:
        assert await hass.config_entries.async_unload(setup_risco_local.entry_id)
        disconnect_mock.assert_awaited_once()


async def test_local_setup_uses_stored_communication_delay(
    hass: HomeAssistant,
) -> None:
    """Test local setup passes stored communication delay to the client."""
    config_entry = MockConfigEntry(
        domain=DOMAIN,
        data={
            CONF_TYPE: TYPE_LOCAL,
            CONF_HOST: "test-host",
            CONF_PORT: 5004,
            CONF_PIN: "1234",
            CONF_COMMUNICATION_DELAY: 2,
        },
    )
    config_entry.add_to_hass(hass)

    with (
        patch(
            "homeassistant.components.risco.RiscoLocal", autospec=True
        ) as risco_local,
        patch.object(
            hass.config_entries,
            "async_forward_entry_setups",
            AsyncMock(return_value=True),
        ),
    ):
        risco_local.return_value.connect = AsyncMock()

        assert await hass.config_entries.async_setup(config_entry.entry_id)
        await hass.async_block_till_done()

        risco_local.assert_called_once_with(
            "test-host",
            5004,
            "1234",
            communication_delay=2,
            concurrency=DEFAULT_CONCURRENCY,
        )


async def test_clock_operation_error_is_downgraded(
    hass: HomeAssistant,
    two_zone_local: dict[int, Any],
    mock_error_handler: MagicMock,
    setup_risco_local: MockConfigEntry,
    caplog: pytest.LogCaptureFixture,
) -> None:
    """Test CLOCK keep-alive operation errors warn without triggering reload."""
    callback = mock_error_handler.call_args.args[0]
    assert callback is not None

    local_data = setup_risco_local.runtime_data.local_data
    disconnect_mock = cast(AsyncMock, local_data.system.disconnect)

    caplog.set_level(logging.WARNING, logger="homeassistant.components.risco")
    await callback(OperationError("Timeout in command: CLOCK"))

    disconnect_mock.assert_not_awaited()
    assert "Error in Risco library" not in caplog.text

    expected_warning = (
        "Risco keep-alive timeout for entry "
        f"{setup_risco_local.title} (host: "
        f"{setup_risco_local.data.get(CONF_HOST, 'unknown')})"
    )
    assert expected_warning in caplog.text
