"""Spook - Your homie.""" from __future__ import annotations from functools import partial from typing import TYPE_CHECKING, Any, cast import voluptuous as vol from homeassistant.const import CONF_ENTITY_ID, CONF_NAME, Platform from homeassistant.core import HomeAssistant, callback from homeassistant.helpers import entity_registry as er, selector from homeassistant.helpers.schema_config_entry_flow import ( SchemaCommonFlowHandler, SchemaConfigFlowHandler, SchemaFlowFormStep, SchemaFlowMenuStep, SchemaOptionsFlowHandler, entity_selector_without_own_entities, ) from .const import CONF_HIDE_SOURCE, DOMAIN, PLATFORMS if TYPE_CHECKING: from collections.abc import Callable, Coroutine, Mapping async def options_schema( domain: str | list[str], handler: SchemaCommonFlowHandler, ) -> vol.Schema: """Generate options schema.""" return vol.Schema( { vol.Required(CONF_ENTITY_ID): entity_selector_without_own_entities( cast(SchemaOptionsFlowHandler, handler.parent_handler), selector.EntitySelectorConfig(domain=domain), ), vol.Required(CONF_HIDE_SOURCE, default=False): selector.BooleanSelector(), }, ) def config_schema(domain: str | list[str]) -> vol.Schema: """Generate config schema.""" return vol.Schema( { vol.Required(CONF_NAME): selector.TextSelector(), vol.Required(CONF_ENTITY_ID): selector.EntitySelector( selector.EntitySelectorConfig(domain=domain), ), vol.Required(CONF_HIDE_SOURCE, default=False): selector.BooleanSelector(), }, ) async def choose_options_step(options: dict[str, Any]) -> str: """Return next step_id for options flow according to inverse_type.""" return cast(str, options["inverse_type"]) def set_inverse_type( inverse_type: str, ) -> Callable[ [SchemaCommonFlowHandler, dict[str, Any]], Coroutine[Any, Any, dict[str, Any]], ]: """Set inverse type.""" async def _set_inverse_type( _: SchemaCommonFlowHandler, user_input: dict[str, Any], ) -> dict[str, Any]: """Add inverse type to user input.""" return {"inverse_type": inverse_type, **user_input} return _set_inverse_type CONFIG_FLOW = { "user": SchemaFlowMenuStep(PLATFORMS), Platform.BINARY_SENSOR: SchemaFlowFormStep( config_schema(Platform.BINARY_SENSOR), validate_user_input=set_inverse_type(Platform.BINARY_SENSOR), ), Platform.SWITCH: SchemaFlowFormStep( config_schema(Platform.SWITCH), validate_user_input=set_inverse_type(Platform.SWITCH), ), } OPTIONS_FLOW = { "init": SchemaFlowFormStep(next_step=choose_options_step), Platform.BINARY_SENSOR: SchemaFlowFormStep( partial(options_schema, Platform.BINARY_SENSOR), ), Platform.SWITCH: SchemaFlowFormStep(partial(options_schema, Platform.SWITCH)), } class SpookInverseConfigFlowHandler(SchemaConfigFlowHandler, domain=DOMAIN): """Handle config flow for Spook inverse helper.""" VERSION = 1 MINOR_VERSION = 2 config_flow = CONFIG_FLOW options_flow = OPTIONS_FLOW @callback def async_config_entry_title(self, options: Mapping[str, Any]) -> str: """Return config entry title.""" return cast(str, options["name"]) if "name" in options else "" @callback def async_config_flow_finished(self, options: Mapping[str, Any]) -> None: """Hide the source entity if requested.""" if options[CONF_HIDE_SOURCE]: _async_hide_source( self.hass, options[CONF_ENTITY_ID], er.RegistryEntryHider.INTEGRATION, ) @callback @staticmethod def async_options_flow_finished( hass: HomeAssistant, options: Mapping[str, Any], ) -> None: """Hide or unhide the source entity as requested.""" hidden_by = ( er.RegistryEntryHider.INTEGRATION if options[CONF_HIDE_SOURCE] else None ) _async_hide_source(hass, options[CONF_ENTITY_ID], hidden_by) def _async_hide_source( hass: HomeAssistant, source_entity_id: str, hidden_by: er.RegistryEntryHider | None, ) -> None: """Hide or unhide inverse source.""" registry = er.async_get(hass) if not (entity_id := er.async_resolve_entity_id(registry, source_entity_id)): return if entity_id not in registry.entities: return registry.async_update_entity(entity_id, hidden_by=hidden_by)