"""Tests for calendar platform."""

from collections.abc import Awaitable, Callable
import datetime
from http import HTTPStatus
from typing import Any
from unittest.mock import AsyncMock
import urllib
import zoneinfo

from aioautomower.utils import mower_list_to_dictionary_dataclass
from freezegun.api import FrozenDateTimeFactory
import pytest
from syrupy.assertion import SnapshotAssertion

from homeassistant.components.calendar import (
    DOMAIN as CALENDAR_DOMAIN,
    EVENT_END_DATETIME,
    EVENT_START_DATETIME,
    SERVICE_GET_EVENTS,
)
from homeassistant.components.husqvarna_automower.const import DOMAIN
from homeassistant.components.husqvarna_automower.coordinator import SCAN_INTERVAL
from homeassistant.const import ATTR_ENTITY_ID
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er

from . import setup_integration

from tests.common import (
    MockConfigEntry,
    async_fire_time_changed,
    load_json_value_fixture,
)
from tests.typing import ClientSessionGenerator

TEST_ENTITY = "calendar.test_mower_1"
type GetEventsFn = Callable[[str, str], Awaitable[dict[str, Any]]]


@pytest.fixture(name="get_events")
def get_events_fixture(
    hass_client: ClientSessionGenerator,
) -> GetEventsFn:
    """Fetch calendar events from the HTTP API."""

    async def _fetch(start: str, end: str) -> list[dict[str, Any]]:
        client = await hass_client()
        response = await client.get(
            f"/api/calendars/{TEST_ENTITY}?start={urllib.parse.quote(start)}&end={urllib.parse.quote(end)}"
        )
        assert response.status == HTTPStatus.OK
        results = await response.json()
        return [{k: event[k] for k in ("summary", "start", "end")} for event in results]

    return _fetch


@pytest.mark.freeze_time(datetime.datetime(2023, 6, 5, 12))
async def test_calendar_state_off(
    hass: HomeAssistant,
    entity_registry: er.EntityRegistry,
    mock_automower_client: AsyncMock,
    mock_config_entry: MockConfigEntry,
    freezer: FrozenDateTimeFactory,
) -> None:
    """State test of the calendar."""
    await setup_integration(hass, mock_config_entry)
    state = hass.states.get("calendar.test_mower_1")
    assert state is not None
    assert state.state == "off"


@pytest.mark.freeze_time(datetime.datetime(2023, 6, 5, 19))
async def test_calendar_state_on(
    hass: HomeAssistant,
    entity_registry: er.EntityRegistry,
    mock_automower_client: AsyncMock,
    mock_config_entry: MockConfigEntry,
    freezer: FrozenDateTimeFactory,
) -> None:
    """State test of the calendar."""
    await setup_integration(hass, mock_config_entry)
    state = hass.states.get("calendar.test_mower_1")
    assert state is not None
    assert state.state == "on"


@pytest.mark.freeze_time(datetime.datetime(2023, 6, 5))
async def test_empty_calendar(
    hass: HomeAssistant,
    entity_registry: er.EntityRegistry,
    mock_automower_client: AsyncMock,
    mock_config_entry: MockConfigEntry,
    freezer: FrozenDateTimeFactory,
    get_events: GetEventsFn,
    mower_time_zone: zoneinfo.ZoneInfo,
) -> None:
    """State if there is no schedule set."""
    await setup_integration(hass, mock_config_entry)
    json_values = load_json_value_fixture("mower.json", DOMAIN)
    json_values["data"][0]["attributes"]["calendar"]["tasks"] = []
    values = mower_list_to_dictionary_dataclass(
        json_values,
        mower_time_zone,
    )
    mock_automower_client.get_status.return_value = values
    freezer.tick(SCAN_INTERVAL)
    async_fire_time_changed(hass)
    await hass.async_block_till_done()
    state = hass.states.get("calendar.test_mower_1")
    assert state is not None
    assert state.state == "off"
    events = await get_events("2023-06-05T00:00:00", "2023-06-12T00:00:00")
    assert events == []


@pytest.mark.freeze_time(datetime.datetime(2023, 6, 5))
@pytest.mark.parametrize(
    (
        "start_date",
        "end_date",
    ),
    [
        (
            datetime.datetime(2023, 6, 5, tzinfo=datetime.UTC),
            datetime.datetime(2023, 6, 12, tzinfo=datetime.UTC),
        ),
    ],
)
async def test_calendar_snapshot(
    hass: HomeAssistant,
    entity_registry: er.EntityRegistry,
    mock_automower_client: AsyncMock,
    mock_config_entry: MockConfigEntry,
    snapshot: SnapshotAssertion,
    start_date: datetime,
    end_date: datetime,
) -> None:
    """Snapshot test of the calendar entity."""
    await setup_integration(hass, mock_config_entry)
    events = await hass.services.async_call(
        CALENDAR_DOMAIN,
        SERVICE_GET_EVENTS,
        {
            ATTR_ENTITY_ID: ["calendar.test_mower_1", "calendar.test_mower_2"],
            EVENT_START_DATETIME: start_date,
            EVENT_END_DATETIME: end_date,
        },
        blocking=True,
        return_response=True,
    )

    assert events == snapshot
