"""Switch platform for the Orvibo integration."""

import logging
from typing import Any, override

from orvibo.s20 import S20, S20Exception
import voluptuous as vol

from homeassistant import config_entries
from homeassistant.components.switch import (
    PLATFORM_SCHEMA as SWITCH_PLATFORM_SCHEMA,
    SwitchEntity,
)
from homeassistant.const import (
    CONF_DISCOVERY,
    CONF_HOST,
    CONF_MAC,
    CONF_NAME,
    CONF_SWITCHES,
)
from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultType
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import config_validation as cv, issue_registry as ir
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, DeviceInfo
from homeassistant.helpers.entity_platform import (
    AddConfigEntryEntitiesCallback,
    AddEntitiesCallback,
)
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType

from .const import DEFAULT_NAME, DOMAIN
from .models import S20ConfigEntry

_LOGGER = logging.getLogger(__name__)

DEFAULT_DISCOVERY = False

# Library is not thread safe and uses global variables,
# so we limit to 1 update at a time
PARALLEL_UPDATES = 1

PLATFORM_SCHEMA = SWITCH_PLATFORM_SCHEMA.extend(
    {
        vol.Required(CONF_SWITCHES, default=[]): vol.All(
            cv.ensure_list,
            [
                {
                    vol.Required(CONF_HOST): cv.string,
                    vol.Optional(CONF_MAC): cv.string,
                    vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
                }
            ],
        ),
        vol.Optional(CONF_DISCOVERY, default=DEFAULT_DISCOVERY): cv.boolean,
    }
)


async def async_setup_platform(
    hass: HomeAssistant,
    config: ConfigType,
    add_entities_callback: AddEntitiesCallback,
    discovery_info: DiscoveryInfoType | None = None,
) -> None:
    """Set up the integration from configuration.yaml."""
    for switch in config.get(CONF_SWITCHES, []):
        result = await hass.config_entries.flow.async_init(
            DOMAIN,
            context={"source": config_entries.SOURCE_IMPORT},
            data=switch,
        )

        if (
            result.get("type") is FlowResultType.ABORT
            and result.get("reason") != "already_configured"
        ):
            ir.async_create_issue(
                hass,
                DOMAIN,
                f"yaml_deprecation_import_issue_{switch.get('host')}"
                f"_{(switch.get('mac') or 'unknown_mac').replace(':', '').lower()}",
                breaks_in_ha_version="2026.9.0",
                is_fixable=False,
                is_persistent=False,
                issue_domain=DOMAIN,
                severity=ir.IssueSeverity.WARNING,
                translation_key="yaml_deprecation_import_issue",
                translation_placeholders={
                    "reason": str(result.get("reason")),
                    "host": switch.get("host"),
                    "mac": switch.get("mac", ""),
                },
            )
            continue

        ir.async_create_issue(
            hass,
            DOMAIN,
            f"yaml_deprecation_{switch.get('host')}"
            f"_{(switch.get('mac') or 'unknown_mac').replace(':', '').lower()}",
            breaks_in_ha_version="2026.9.0",
            is_fixable=False,
            is_persistent=False,
            severity=ir.IssueSeverity.WARNING,
            translation_key="yaml_deprecation",
            translation_placeholders={
                "host": switch.get("host"),
                "mac": switch.get("mac") or "Unknown MAC",
            },
        )


async def async_setup_entry(
    hass: HomeAssistant,
    entry: S20ConfigEntry,
    async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
    """Set up orvibo from a config entry."""
    async_add_entities(
        [
            S20Switch(
                entry.title,
                entry.data[CONF_HOST],
                entry.data[CONF_MAC],
                entry.runtime_data,
            )
        ]
    )


class S20Switch(SwitchEntity):
    """Representation of an S20 switch."""

    _attr_has_entity_name = True

    def __init__(self, name: str, host: str, mac: str, s20: S20) -> None:
        """Initialize the S20 device."""

        self._attr_is_on = False
        self._host = host
        self._mac = mac
        self._s20 = s20
        self._attr_unique_id = self._mac
        self._name = name
        self._attr_name = None
        self._attr_device_info = DeviceInfo(
            identifiers={
                # MAC addresses are used as unique identifiers within this domain
                (DOMAIN, self._attr_unique_id)
            },
            name=name,
            manufacturer="Orvibo",
            model="S20",
            connections={(CONNECTION_NETWORK_MAC, self._mac)},
        )

    @override
    def turn_on(self, **kwargs: Any) -> None:
        """Turn the device on."""
        try:
            self._s20.on = True
        except S20Exception as err:
            raise HomeAssistantError(
                translation_domain=DOMAIN,
                translation_key="turn_on_error",
                translation_placeholders={"name": self._name},
            ) from err

    @override
    def turn_off(self, **kwargs: Any) -> None:
        """Turn the device off."""
        try:
            self._s20.on = False
        except S20Exception as err:
            raise HomeAssistantError(
                translation_domain=DOMAIN,
                translation_key="turn_off_error",
                translation_placeholders={"name": self._name},
            ) from err

    def update(self) -> None:
        """Update device state."""
        try:
            self._attr_is_on = self._s20.on

            # If the device was previously offline, let the user know it's back!
            if not self._attr_available:
                _LOGGER.info("Orvibo switch %s reconnected", self._name)
                self._attr_available = True

        except S20Exception as err:
            # Only log the error if this is the FIRST time it failed
            if self._attr_available:
                _LOGGER.info(
                    "Error communicating with Orvibo switch %s: %s", self._name, err
                )
                self._attr_available = False
