"""Support for Notion binary sensors."""
from __future__ import annotations

from dataclasses import dataclass
from typing import Literal

from homeassistant.components.binary_sensor import (
    BinarySensorDeviceClass,
    BinarySensorEntity,
    BinarySensorEntityDescription,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import EntityCategory
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback

from . import NotionEntity
from .const import (
    DOMAIN,
    LOGGER,
    SENSOR_BATTERY,
    SENSOR_DOOR,
    SENSOR_GARAGE_DOOR,
    SENSOR_LEAK,
    SENSOR_MISSING,
    SENSOR_SAFE,
    SENSOR_SLIDING,
    SENSOR_SMOKE_CO,
    SENSOR_WINDOW_HINGED_HORIZONTAL,
    SENSOR_WINDOW_HINGED_VERTICAL,
)


@dataclass
class NotionBinarySensorDescriptionMixin:
    """Define an entity description mixin for binary and regular sensors."""

    on_state: Literal["alarm", "critical", "leak", "not_missing", "open"]


@dataclass
class NotionBinarySensorDescription(
    BinarySensorEntityDescription, NotionBinarySensorDescriptionMixin
):
    """Describe a Notion binary sensor."""


BINARY_SENSOR_DESCRIPTIONS = (
    NotionBinarySensorDescription(
        key=SENSOR_BATTERY,
        name="Low battery",
        device_class=BinarySensorDeviceClass.BATTERY,
        entity_category=EntityCategory.DIAGNOSTIC,
        on_state="critical",
    ),
    NotionBinarySensorDescription(
        key=SENSOR_DOOR,
        name="Door",
        device_class=BinarySensorDeviceClass.DOOR,
        on_state="open",
    ),
    NotionBinarySensorDescription(
        key=SENSOR_GARAGE_DOOR,
        name="Garage door",
        device_class=BinarySensorDeviceClass.GARAGE_DOOR,
        on_state="open",
    ),
    NotionBinarySensorDescription(
        key=SENSOR_LEAK,
        name="Leak detector",
        device_class=BinarySensorDeviceClass.MOISTURE,
        on_state="leak",
    ),
    NotionBinarySensorDescription(
        key=SENSOR_MISSING,
        name="Missing",
        device_class=BinarySensorDeviceClass.CONNECTIVITY,
        entity_category=EntityCategory.DIAGNOSTIC,
        on_state="not_missing",
    ),
    NotionBinarySensorDescription(
        key=SENSOR_SAFE,
        name="Safe",
        device_class=BinarySensorDeviceClass.DOOR,
        on_state="open",
    ),
    NotionBinarySensorDescription(
        key=SENSOR_SLIDING,
        name="Sliding door/window",
        device_class=BinarySensorDeviceClass.DOOR,
        on_state="open",
    ),
    NotionBinarySensorDescription(
        key=SENSOR_SMOKE_CO,
        name="Smoke/Carbon monoxide detector",
        device_class=BinarySensorDeviceClass.SMOKE,
        on_state="alarm",
    ),
    NotionBinarySensorDescription(
        key=SENSOR_WINDOW_HINGED_HORIZONTAL,
        name="Hinged window",
        device_class=BinarySensorDeviceClass.WINDOW,
        on_state="open",
    ),
    NotionBinarySensorDescription(
        key=SENSOR_WINDOW_HINGED_VERTICAL,
        name="Hinged window",
        device_class=BinarySensorDeviceClass.WINDOW,
        on_state="open",
    ),
)


async def async_setup_entry(
    hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None:
    """Set up Notion sensors based on a config entry."""
    coordinator = hass.data[DOMAIN][entry.entry_id]

    async_add_entities(
        [
            NotionBinarySensor(
                coordinator,
                task_id,
                sensor["id"],
                sensor["bridge"]["id"],
                sensor["system_id"],
                description,
            )
            for task_id, task in coordinator.data["tasks"].items()
            for description in BINARY_SENSOR_DESCRIPTIONS
            if description.key == task["task_type"]
            and (sensor := coordinator.data["sensors"][task["sensor_id"]])
        ]
    )


class NotionBinarySensor(NotionEntity, BinarySensorEntity):
    """Define a Notion sensor."""

    entity_description: NotionBinarySensorDescription

    @callback
    def _async_update_from_latest_data(self) -> None:
        """Fetch new state data for the sensor."""
        task = self.coordinator.data["tasks"][self._task_id]

        if "value" in task["status"]:
            state = task["status"]["value"]
        elif task["status"].get("insights", {}).get("primary"):
            state = task["status"]["insights"]["primary"]["to_state"]
        else:
            LOGGER.warning("Unknown data payload: %s", task["status"])
            state = None

        self._attr_is_on = self.entity_description.on_state == state