"""Support for LaMetric notifications."""
from __future__ import annotations

import logging
from typing import Any

from lmnotify import Model, SimpleFrame, Sound
from oauthlib.oauth2 import TokenExpiredError
from requests.exceptions import ConnectionError as RequestsConnectionError
import voluptuous as vol

from homeassistant.components.notify import (
    ATTR_DATA,
    ATTR_TARGET,
    PLATFORM_SCHEMA,
    BaseNotificationService,
)
from homeassistant.const import CONF_ICON
from homeassistant.core import HomeAssistant
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType

from . import DOMAIN, HassLaMetricManager

_LOGGER = logging.getLogger(__name__)

AVAILABLE_PRIORITIES = ["info", "warning", "critical"]
AVAILABLE_ICON_TYPES = ["none", "info", "alert"]

CONF_CYCLES = "cycles"
CONF_LIFETIME = "lifetime"
CONF_PRIORITY = "priority"
CONF_ICON_TYPE = "icon_type"

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
    {
        vol.Optional(CONF_ICON, default="a7956"): cv.string,
        vol.Optional(CONF_LIFETIME, default=10): cv.positive_int,
        vol.Optional(CONF_CYCLES, default=1): cv.positive_int,
        vol.Optional(CONF_PRIORITY, default="warning"): vol.In(AVAILABLE_PRIORITIES),
        vol.Optional(CONF_ICON_TYPE, default="info"): vol.In(AVAILABLE_ICON_TYPES),
    }
)


def get_service(
    hass: HomeAssistant,
    config: ConfigType,
    discovery_info: DiscoveryInfoType | None = None,
) -> LaMetricNotificationService:
    """Get the LaMetric notification service."""
    return LaMetricNotificationService(
        hass.data[DOMAIN],
        config[CONF_ICON],
        config[CONF_LIFETIME] * 1000,
        config[CONF_CYCLES],
        config[CONF_PRIORITY],
        config[CONF_ICON_TYPE],
    )


class LaMetricNotificationService(BaseNotificationService):
    """Implement the notification service for LaMetric."""

    def __init__(
        self,
        hasslametricmanager: HassLaMetricManager,
        icon: str,
        lifetime: int,
        cycles: int,
        priority: str,
        icon_type: str,
    ) -> None:
        """Initialize the service."""
        self.hasslametricmanager = hasslametricmanager
        self._icon = icon
        self._lifetime = lifetime
        self._cycles = cycles
        self._priority = priority
        self._icon_type = icon_type
        self._devices: list[dict[str, Any]] = []

    def send_message(self, message: str = "", **kwargs: Any) -> None:
        """Send a message to some LaMetric device."""

        targets = kwargs.get(ATTR_TARGET)
        data = kwargs.get(ATTR_DATA)
        _LOGGER.debug("Targets/Data: %s/%s", targets, data)
        icon = self._icon
        cycles = self._cycles
        sound = None
        priority = self._priority
        icon_type = self._icon_type

        # Additional data?
        if data is not None:
            if "icon" in data:
                icon = data["icon"]
            if "sound" in data:
                try:
                    sound = Sound(category="notifications", sound_id=data["sound"])
                    _LOGGER.debug("Adding notification sound %s", data["sound"])
                except AssertionError:
                    _LOGGER.error("Sound ID %s unknown, ignoring", data["sound"])
            if "cycles" in data:
                cycles = int(data["cycles"])
            if "icon_type" in data:
                if data["icon_type"] in AVAILABLE_ICON_TYPES:
                    icon_type = data["icon_type"]
                else:
                    _LOGGER.warning(
                        "Priority %s invalid, using default %s",
                        data["priority"],
                        priority,
                    )
            if "priority" in data:
                if data["priority"] in AVAILABLE_PRIORITIES:
                    priority = data["priority"]
                else:
                    _LOGGER.warning(
                        "Priority %s invalid, using default %s",
                        data["priority"],
                        priority,
                    )
        text_frame = SimpleFrame(icon, message)
        _LOGGER.debug(
            "Icon/Message/Cycles/Lifetime: %s, %s, %d, %d",
            icon,
            message,
            self._cycles,
            self._lifetime,
        )

        frames = [text_frame]

        model = Model(frames=frames, cycles=cycles, sound=sound)
        lmn = self.hasslametricmanager.manager
        try:
            self._devices = lmn.get_devices()
        except TokenExpiredError:
            _LOGGER.debug("Token expired, fetching new token")
            lmn.get_token()
            self._devices = lmn.get_devices()
        except RequestsConnectionError:
            _LOGGER.warning(
                "Problem connecting to LaMetric, using cached devices instead"
            )
        for dev in self._devices:
            if targets is None or dev["name"] in targets:
                try:
                    lmn.set_device(dev)
                    lmn.send_notification(
                        model,
                        lifetime=self._lifetime,
                        priority=priority,
                        icon_type=icon_type,
                    )
                    _LOGGER.debug("Sent notification to LaMetric %s", dev["name"])
                except OSError:
                    _LOGGER.warning("Cannot connect to LaMetric %s", dev["name"])
