"""Tests for the logbook component."""

import json
from typing import Any

from homeassistant.components import logbook
from homeassistant.components.logbook import processor
from homeassistant.components.logbook.models import EventAsRow, LogbookConfig
from homeassistant.components.recorder.models import (
    process_timestamp_to_utc_isoformat,
    ulid_to_bytes_or_none,
    uuid_hex_to_bytes_or_none,
)
from homeassistant.const import (
    ATTR_DOMAIN,
    ATTR_ENTITY_ID,
    ATTR_FRIENDLY_NAME,
    ATTR_SERVICE,
    EVENT_CALL_SERVICE,
    STATE_OFF,
    STATE_ON,
)
from homeassistant.core import Context, HomeAssistant
from homeassistant.helpers import entity_registry as er
from homeassistant.helpers.json import JSONEncoder
from homeassistant.util import dt as dt_util

IDX_TO_NAME = dict(enumerate(EventAsRow._fields))


class MockRow:
    """Minimal row mock."""

    def __init__(
        self,
        event_type: str,
        data: dict[str, Any] | None = None,
        context: Context | None = None,
    ) -> None:
        """Init the fake row."""
        self.event_type = event_type
        self.event_data = json.dumps(data, cls=JSONEncoder)
        self.data = data
        self.time_fired = dt_util.utcnow()
        self.time_fired_ts = self.time_fired.timestamp()
        self.context_parent_id_bin = (
            ulid_to_bytes_or_none(context.parent_id) if context else None
        )
        self.context_user_id_bin = (
            uuid_hex_to_bytes_or_none(context.user_id) if context else None
        )
        self.context_id_bin = ulid_to_bytes_or_none(context.id) if context else None
        self.state = None
        self.entity_id = None
        self.row_id = None
        self.shared_attrs = None
        self.attributes = None
        self.context_only = False

    def __getitem__(self, idx: int) -> Any:
        """Get item."""
        return getattr(self, IDX_TO_NAME[idx])

    @property
    def time_fired_minute(self):
        """Minute the event was fired."""
        return self.time_fired.minute

    @property
    def time_fired_isoformat(self):
        """Time event was fired in utc isoformat."""
        return process_timestamp_to_utc_isoformat(self.time_fired)


def setup_thermostat_context_test_entities(hass_: HomeAssistant) -> None:
    """Set up initial states for the thermostat context chain test entities."""
    hass_.states.async_set(
        "climate.living_room",
        "off",
        {ATTR_FRIENDLY_NAME: "Living Room Thermostat"},
    )
    hass_.states.async_set("switch.heater", STATE_OFF)


def simulate_thermostat_context_chain(
    hass_: HomeAssistant,
    user_id: str = "b400facee45711eaa9308bfd3d19e474",
) -> tuple[Context, Context]:
    """Simulate the generic_thermostat context chain.

    Fires events in the realistic order:
    1. EVENT_CALL_SERVICE for set_hvac_mode (parent context)
    2. EVENT_CALL_SERVICE for homeassistant.turn_on (child context)
    3. Climate state changes off → heat (parent context)
    4. Switch state changes off → on (child context)

    Returns the (parent_context, child_context) tuple.
    """
    parent_context = Context(
        id="01GTDGKBCH00GW0X476W5TVAAA",
        user_id=user_id,
    )
    child_context = Context(
        id="01GTDGKBCH00GW0X476W5TVDDD",
        parent_id=parent_context.id,
    )

    hass_.bus.async_fire(
        EVENT_CALL_SERVICE,
        {
            ATTR_DOMAIN: "climate",
            ATTR_SERVICE: "set_hvac_mode",
            "service_data": {ATTR_ENTITY_ID: "climate.living_room"},
        },
        context=parent_context,
    )
    hass_.bus.async_fire(
        EVENT_CALL_SERVICE,
        {
            ATTR_DOMAIN: "homeassistant",
            ATTR_SERVICE: "turn_on",
            "service_data": {ATTR_ENTITY_ID: "switch.heater"},
        },
        context=child_context,
    )
    hass_.states.async_set(
        "climate.living_room",
        "heat",
        {ATTR_FRIENDLY_NAME: "Living Room Thermostat"},
        context=parent_context,
    )
    hass_.states.async_set(
        "switch.heater",
        STATE_ON,
        {ATTR_FRIENDLY_NAME: "Heater"},
        context=child_context,
    )
    return parent_context, child_context


def assert_thermostat_context_chain_events(
    events: list[dict[str, Any]], parent_context: Context
) -> None:
    """Assert the logbook events for a thermostat context chain.

    Verifies that climate and switch state changes have correct
    state, user attribution, and service call context.
    """
    climate_entries = [e for e in events if e.get("entity_id") == "climate.living_room"]
    assert len(climate_entries) == 1
    assert climate_entries[0]["state"] == "heat"
    assert climate_entries[0]["context_user_id"] == parent_context.user_id
    assert climate_entries[0]["context_event_type"] == EVENT_CALL_SERVICE
    assert climate_entries[0]["context_domain"] == "climate"
    assert climate_entries[0]["context_service"] == "set_hvac_mode"

    heater_entries = [e for e in events if e.get("entity_id") == "switch.heater"]
    assert len(heater_entries) == 1
    assert heater_entries[0]["state"] == "on"
    assert heater_entries[0]["context_user_id"] == parent_context.user_id
    assert heater_entries[0]["context_event_type"] == EVENT_CALL_SERVICE
    assert heater_entries[0]["context_domain"] == "homeassistant"
    assert heater_entries[0]["context_service"] == "turn_on"


def mock_humanify(hass_, rows):
    """Wrap humanify with mocked logbook objects."""
    entity_name_cache = processor.EntityNameCache(hass_)
    ent_reg = er.async_get(hass_)
    event_cache = processor.EventCache({})
    context_lookup = {}
    logbook_config = hass_.data.get(logbook.DOMAIN, LogbookConfig({}, None, None))
    external_events = logbook_config.external_events
    logbook_run = processor.LogbookRun(
        context_lookup,
        external_events,
        event_cache,
        entity_name_cache,
        include_entity_name=True,
        timestamp=False,
    )
    context_augmenter = processor.ContextAugmenter(logbook_run)
    return list(
        processor._humanify(
            hass_,
            rows,
            ent_reg,
            logbook_run,
            context_augmenter,
            None,
        ),
    )
