"""Preference management for cloud."""
from ipaddress import ip_address
from typing import List, Optional

from homeassistant.auth.const import GROUP_ID_ADMIN
from homeassistant.auth.models import User
from homeassistant.core import callback
from homeassistant.util.logging import async_create_catching_coro

from .const import (
    DEFAULT_ALEXA_REPORT_STATE,
    DEFAULT_EXPOSED_DOMAINS,
    DEFAULT_GOOGLE_REPORT_STATE,
    DOMAIN,
    PREF_ALEXA_DEFAULT_EXPOSE,
    PREF_ALEXA_ENTITY_CONFIGS,
    PREF_ALEXA_REPORT_STATE,
    PREF_ALIASES,
    PREF_CLOUD_USER,
    PREF_CLOUDHOOKS,
    PREF_DISABLE_2FA,
    PREF_ENABLE_ALEXA,
    PREF_ENABLE_GOOGLE,
    PREF_ENABLE_REMOTE,
    PREF_GOOGLE_DEFAULT_EXPOSE,
    PREF_GOOGLE_ENTITY_CONFIGS,
    PREF_GOOGLE_LOCAL_WEBHOOK_ID,
    PREF_GOOGLE_REPORT_STATE,
    PREF_GOOGLE_SECURE_DEVICES_PIN,
    PREF_OVERRIDE_NAME,
    PREF_SHOULD_EXPOSE,
    PREF_USERNAME,
    InvalidTrustedNetworks,
    InvalidTrustedProxies,
)

STORAGE_KEY = DOMAIN
STORAGE_VERSION = 1
_UNDEF = object()


class CloudPreferences:
    """Handle cloud preferences."""

    def __init__(self, hass):
        """Initialize cloud prefs."""
        self._hass = hass
        self._store = hass.helpers.storage.Store(STORAGE_VERSION, STORAGE_KEY)
        self._prefs = None
        self._listeners = []

    async def async_initialize(self):
        """Finish initializing the preferences."""
        prefs = await self._store.async_load()

        if prefs is None:
            prefs = self._empty_config("")

        self._prefs = prefs

        if PREF_GOOGLE_LOCAL_WEBHOOK_ID not in self._prefs:
            await self._save_prefs(
                {
                    **self._prefs,
                    PREF_GOOGLE_LOCAL_WEBHOOK_ID: self._hass.components.webhook.async_generate_id(),
                }
            )

    @callback
    def async_listen_updates(self, listener):
        """Listen for updates to the preferences."""
        self._listeners.append(listener)

    async def async_update(
        self,
        *,
        google_enabled=_UNDEF,
        alexa_enabled=_UNDEF,
        remote_enabled=_UNDEF,
        google_secure_devices_pin=_UNDEF,
        cloudhooks=_UNDEF,
        cloud_user=_UNDEF,
        google_entity_configs=_UNDEF,
        alexa_entity_configs=_UNDEF,
        alexa_report_state=_UNDEF,
        google_report_state=_UNDEF,
        alexa_default_expose=_UNDEF,
        google_default_expose=_UNDEF,
    ):
        """Update user preferences."""
        prefs = {**self._prefs}

        for key, value in (
            (PREF_ENABLE_GOOGLE, google_enabled),
            (PREF_ENABLE_ALEXA, alexa_enabled),
            (PREF_ENABLE_REMOTE, remote_enabled),
            (PREF_GOOGLE_SECURE_DEVICES_PIN, google_secure_devices_pin),
            (PREF_CLOUDHOOKS, cloudhooks),
            (PREF_CLOUD_USER, cloud_user),
            (PREF_GOOGLE_ENTITY_CONFIGS, google_entity_configs),
            (PREF_ALEXA_ENTITY_CONFIGS, alexa_entity_configs),
            (PREF_ALEXA_REPORT_STATE, alexa_report_state),
            (PREF_GOOGLE_REPORT_STATE, google_report_state),
            (PREF_ALEXA_DEFAULT_EXPOSE, alexa_default_expose),
            (PREF_GOOGLE_DEFAULT_EXPOSE, google_default_expose),
        ):
            if value is not _UNDEF:
                prefs[key] = value

        if remote_enabled is True and self._has_local_trusted_network:
            prefs[PREF_ENABLE_REMOTE] = False
            raise InvalidTrustedNetworks

        if remote_enabled is True and self._has_local_trusted_proxies:
            prefs[PREF_ENABLE_REMOTE] = False
            raise InvalidTrustedProxies

        await self._save_prefs(prefs)

    async def async_update_google_entity_config(
        self,
        *,
        entity_id,
        override_name=_UNDEF,
        disable_2fa=_UNDEF,
        aliases=_UNDEF,
        should_expose=_UNDEF,
    ):
        """Update config for a Google entity."""
        entities = self.google_entity_configs
        entity = entities.get(entity_id, {})

        changes = {}
        for key, value in (
            (PREF_OVERRIDE_NAME, override_name),
            (PREF_DISABLE_2FA, disable_2fa),
            (PREF_ALIASES, aliases),
            (PREF_SHOULD_EXPOSE, should_expose),
        ):
            if value is not _UNDEF:
                changes[key] = value

        if not changes:
            return

        updated_entity = {**entity, **changes}

        updated_entities = {**entities, entity_id: updated_entity}
        await self.async_update(google_entity_configs=updated_entities)

    async def async_update_alexa_entity_config(
        self, *, entity_id, should_expose=_UNDEF
    ):
        """Update config for an Alexa entity."""
        entities = self.alexa_entity_configs
        entity = entities.get(entity_id, {})

        changes = {}
        for key, value in ((PREF_SHOULD_EXPOSE, should_expose),):
            if value is not _UNDEF:
                changes[key] = value

        if not changes:
            return

        updated_entity = {**entity, **changes}

        updated_entities = {**entities, entity_id: updated_entity}
        await self.async_update(alexa_entity_configs=updated_entities)

    async def async_set_username(self, username):
        """Set the username that is logged in."""
        # Logging out.
        if username is None:
            user = await self._load_cloud_user()

            if user is not None:
                await self._hass.auth.async_remove_user(user)
                await self._save_prefs({**self._prefs, PREF_CLOUD_USER: None})
            return

        cur_username = self._prefs.get(PREF_USERNAME)

        if cur_username == username:
            return

        if cur_username is None:
            await self._save_prefs({**self._prefs, PREF_USERNAME: username})
        else:
            await self._save_prefs(self._empty_config(username))

    def as_dict(self):
        """Return dictionary version."""
        return {
            PREF_ALEXA_DEFAULT_EXPOSE: self.alexa_default_expose,
            PREF_ALEXA_ENTITY_CONFIGS: self.alexa_entity_configs,
            PREF_ALEXA_REPORT_STATE: self.alexa_report_state,
            PREF_CLOUDHOOKS: self.cloudhooks,
            PREF_ENABLE_ALEXA: self.alexa_enabled,
            PREF_ENABLE_GOOGLE: self.google_enabled,
            PREF_ENABLE_REMOTE: self.remote_enabled,
            PREF_GOOGLE_DEFAULT_EXPOSE: self.google_default_expose,
            PREF_GOOGLE_ENTITY_CONFIGS: self.google_entity_configs,
            PREF_GOOGLE_REPORT_STATE: self.google_report_state,
            PREF_GOOGLE_SECURE_DEVICES_PIN: self.google_secure_devices_pin,
        }

    @property
    def remote_enabled(self):
        """Return if remote is enabled on start."""
        enabled = self._prefs.get(PREF_ENABLE_REMOTE, False)

        if not enabled:
            return False

        if self._has_local_trusted_network or self._has_local_trusted_proxies:
            return False

        return True

    @property
    def alexa_enabled(self):
        """Return if Alexa is enabled."""
        return self._prefs[PREF_ENABLE_ALEXA]

    @property
    def alexa_report_state(self):
        """Return if Alexa report state is enabled."""
        return self._prefs.get(PREF_ALEXA_REPORT_STATE, DEFAULT_ALEXA_REPORT_STATE)

    @property
    def alexa_default_expose(self) -> Optional[List[str]]:
        """Return array of entity domains that are exposed by default to Alexa.

        Can return None, in which case for backwards should be interpreted as allow all domains.
        """
        return self._prefs.get(PREF_ALEXA_DEFAULT_EXPOSE)

    @property
    def alexa_entity_configs(self):
        """Return Alexa Entity configurations."""
        return self._prefs.get(PREF_ALEXA_ENTITY_CONFIGS, {})

    @property
    def google_enabled(self):
        """Return if Google is enabled."""
        return self._prefs[PREF_ENABLE_GOOGLE]

    @property
    def google_report_state(self):
        """Return if Google report state is enabled."""
        return self._prefs.get(PREF_GOOGLE_REPORT_STATE, DEFAULT_GOOGLE_REPORT_STATE)

    @property
    def google_secure_devices_pin(self):
        """Return if Google is allowed to unlock locks."""
        return self._prefs.get(PREF_GOOGLE_SECURE_DEVICES_PIN)

    @property
    def google_entity_configs(self):
        """Return Google Entity configurations."""
        return self._prefs.get(PREF_GOOGLE_ENTITY_CONFIGS, {})

    @property
    def google_local_webhook_id(self):
        """Return Google webhook ID to receive local messages."""
        return self._prefs[PREF_GOOGLE_LOCAL_WEBHOOK_ID]

    @property
    def google_default_expose(self) -> Optional[List[str]]:
        """Return array of entity domains that are exposed by default to Google.

        Can return None, in which case for backwards should be interpreted as allow all domains.
        """
        return self._prefs.get(PREF_GOOGLE_DEFAULT_EXPOSE)

    @property
    def cloudhooks(self):
        """Return the published cloud webhooks."""
        return self._prefs.get(PREF_CLOUDHOOKS, {})

    async def get_cloud_user(self) -> str:
        """Return ID from Home Assistant Cloud system user."""
        user = await self._load_cloud_user()

        if user:
            return user.id

        user = await self._hass.auth.async_create_system_user(
            "Home Assistant Cloud", [GROUP_ID_ADMIN]
        )
        await self.async_update(cloud_user=user.id)
        return user.id

    async def _load_cloud_user(self) -> Optional[User]:
        """Load cloud user if available."""
        user_id = self._prefs.get(PREF_CLOUD_USER)

        if user_id is None:
            return None

        # Fetch the user. It can happen that the user no longer exists if
        # an image was restored without restoring the cloud prefs.
        return await self._hass.auth.async_get_user(user_id)

    @property
    def _has_local_trusted_network(self) -> bool:
        """Return if we allow localhost to bypass auth."""
        local4 = ip_address("127.0.0.1")
        local6 = ip_address("::1")

        for prv in self._hass.auth.auth_providers:
            if prv.type != "trusted_networks":
                continue

            for network in prv.trusted_networks:
                if local4 in network or local6 in network:
                    return True

        return False

    @property
    def _has_local_trusted_proxies(self) -> bool:
        """Return if we allow localhost to be a proxy and use its data."""
        if not hasattr(self._hass, "http"):
            return False

        local4 = ip_address("127.0.0.1")
        local6 = ip_address("::1")

        if any(
            local4 in nwk or local6 in nwk for nwk in self._hass.http.trusted_proxies
        ):
            return True

        return False

    async def _save_prefs(self, prefs):
        """Save preferences to disk."""
        self._prefs = prefs
        await self._store.async_save(self._prefs)

        for listener in self._listeners:
            self._hass.async_create_task(async_create_catching_coro(listener(self)))

    @callback
    def _empty_config(self, username):
        """Return an empty config."""
        return {
            PREF_ALEXA_DEFAULT_EXPOSE: DEFAULT_EXPOSED_DOMAINS,
            PREF_ALEXA_ENTITY_CONFIGS: {},
            PREF_CLOUD_USER: None,
            PREF_CLOUDHOOKS: {},
            PREF_ENABLE_ALEXA: True,
            PREF_ENABLE_GOOGLE: True,
            PREF_ENABLE_REMOTE: False,
            PREF_GOOGLE_DEFAULT_EXPOSE: DEFAULT_EXPOSED_DOMAINS,
            PREF_GOOGLE_ENTITY_CONFIGS: {},
            PREF_GOOGLE_LOCAL_WEBHOOK_ID: self._hass.components.webhook.async_generate_id(),
            PREF_GOOGLE_SECURE_DEVICES_PIN: None,
            PREF_USERNAME: username,
        }

"""Preference management for cloud."""
from ipaddress import ip_address
from typing import List, Optional

from homeassistant.auth.const import GROUP_ID_ADMIN
from homeassistant.auth.models import User
from homeassistant.core import callback
from homeassistant.util.logging import async_create_catching_coro

from .const import (
    DEFAULT_ALEXA_REPORT_STATE,
    DEFAULT_EXPOSED_DOMAINS,
    DEFAULT_GOOGLE_REPORT_STATE,
    DOMAIN,
    PREF_ALEXA_DEFAULT_EXPOSE,
    PREF_ALEXA_ENTITY_CONFIGS,
    PREF_ALEXA_REPORT_STATE,
    PREF_ALIASES,
    PREF_CLOUD_USER,
    PREF_CLOUDHOOKS,
    PREF_DISABLE_2FA,
    PREF_ENABLE_ALEXA,
    PREF_ENABLE_GOOGLE,
    PREF_ENABLE_REMOTE,
    PREF_GOOGLE_DEFAULT_EXPOSE,
    PREF_GOOGLE_ENTITY_CONFIGS,
    PREF_GOOGLE_LOCAL_WEBHOOK_ID,
    PREF_GOOGLE_REPORT_STATE,
    PREF_GOOGLE_SECURE_DEVICES_PIN,
    PREF_OVERRIDE_NAME,
    PREF_SHOULD_EXPOSE,
    PREF_USERNAME,
    InvalidTrustedNetworks,
    InvalidTrustedProxies,
)

STORAGE_KEY = DOMAIN
STORAGE_VERSION = 1
_UNDEF = object()


class CloudPreferences:
    """Handle cloud preferences."""

    def __init__(self, hass):
        """Initialize cloud prefs."""
        self._hass = hass
        self._store = hass.helpers.storage.Store(STORAGE_VERSION, STORAGE_KEY)
        self._prefs = None
        self._listeners = []

    async def async_initialize(self):
        """Finish initializing the preferences."""
        prefs = await self._store.async_load()

        if prefs is None:
            prefs = self._empty_config("")

        self._prefs = prefs

        if PREF_GOOGLE_LOCAL_WEBHOOK_ID not in self._prefs:
            await self._save_prefs(
                {
                    **self._prefs,
                    PREF_GOOGLE_LOCAL_WEBHOOK_ID: self._hass.components.webhook.async_generate_id(),
                }
            )

    @callback
    def async_listen_updates(self, listener):
        """Listen for updates to the preferences."""
        self._listeners.append(listener)

    async def async_update(
        self,
        *,
        google_enabled=_UNDEF,
        alexa_enabled=_UNDEF,
        remote_enabled=_UNDEF,
        google_secure_devices_pin=_UNDEF,
        cloudhooks=_UNDEF,
        cloud_user=_UNDEF,
        google_entity_configs=_UNDEF,
        alexa_entity_configs=_UNDEF,
        alexa_report_state=_UNDEF,
        google_report_state=_UNDEF,
        alexa_default_expose=_UNDEF,
        google_default_expose=_UNDEF,
    ):
        """Update user preferences."""
        prefs = {**self._prefs}

        for key, value in (
            (PREF_ENABLE_GOOGLE, google_enabled),
            (PREF_ENABLE_ALEXA, alexa_enabled),
            (PREF_ENABLE_REMOTE, remote_enabled),
            (PREF_GOOGLE_SECURE_DEVICES_PIN, google_secure_devices_pin),
            (PREF_CLOUDHOOKS, cloudhooks),
            (PREF_CLOUD_USER, cloud_user),
            (PREF_GOOGLE_ENTITY_CONFIGS, google_entity_configs),
            (PREF_ALEXA_ENTITY_CONFIGS, alexa_entity_configs),
            (PREF_ALEXA_REPORT_STATE, alexa_report_state),
            (PREF_GOOGLE_REPORT_STATE, google_report_state),
            (PREF_ALEXA_DEFAULT_EXPOSE, alexa_default_expose),
            (PREF_GOOGLE_DEFAULT_EXPOSE, google_default_expose),
        ):
            if value is not _UNDEF:
                prefs[key] = value

        if remote_enabled is True and self._has_local_trusted_network:
            prefs[PREF_ENABLE_REMOTE] = False
            raise InvalidTrustedNetworks

        if remote_enabled is True and self._has_local_trusted_proxies:
            prefs[PREF_ENABLE_REMOTE] = False
            raise InvalidTrustedProxies

        await self._save_prefs(prefs)

    async def async_update_google_entity_config(
        self,
        *,
        entity_id,
        override_name=_UNDEF,
        disable_2fa=_UNDEF,
        aliases=_UNDEF,
        should_expose=_UNDEF,
    ):
        """Update config for a Google entity."""
        entities = self.google_entity_configs
        entity = entities.get(entity_id, {})

        changes = {}
        for key, value in (
            (PREF_OVERRIDE_NAME, override_name),
            (PREF_DISABLE_2FA, disable_2fa),
            (PREF_ALIASES, aliases),
            (PREF_SHOULD_EXPOSE, should_expose),
        ):
            if value is not _UNDEF:
                changes[key] = value

        if not changes:
            return

        updated_entity = {**entity, **changes}

        updated_entities = {**entities, entity_id: updated_entity}
        await self.async_update(google_entity_configs=updated_entities)

    async def async_update_alexa_entity_config(
        self, *, entity_id, should_expose=_UNDEF
    ):
        """Update config for an Alexa entity."""
        entities = self.alexa_entity_configs
        entity = entities.get(entity_id, {})

        changes = {}
        for key, value in ((PREF_SHOULD_EXPOSE, should_expose),):
            if value is not _UNDEF:
                changes[key] = value

        if not changes:
            return

        updated_entity = {**entity, **changes}

        updated_entities = {**entities, entity_id: updated_entity}
        await self.async_update(alexa_entity_configs=updated_entities)

    async def async_set_username(self, username):
        """Set the username that is logged in."""
        # Logging out.
        if username is None:
            user = await self._load_cloud_user()

            if user is not None:
                await self._hass.auth.async_remove_user(user)
                await self._save_prefs({**self._prefs, PREF_CLOUD_USER: None})
            return

        cur_username = self._prefs.get(PREF_USERNAME)

        if cur_username == username:
            return

        if cur_username is None:
            await self._save_prefs({**self._prefs, PREF_USERNAME: username})
        else:
            await self._save_prefs(self._empty_config(username))

    def as_dict(self):
        """Return dictionary version."""
        return {
            PREF_ALEXA_DEFAULT_EXPOSE: self.alexa_default_expose,
            PREF_ALEXA_ENTITY_CONFIGS: self.alexa_entity_configs,
            PREF_ALEXA_REPORT_STATE: self.alexa_report_state,
            PREF_CLOUDHOOKS: self.cloudhooks,
            PREF_ENABLE_ALEXA: self.alexa_enabled,
            PREF_ENABLE_GOOGLE: self.google_enabled,
            PREF_ENABLE_REMOTE: self.remote_enabled,
            PREF_GOOGLE_DEFAULT_EXPOSE: self.google_default_expose,
            PREF_GOOGLE_ENTITY_CONFIGS: self.google_entity_configs,
            PREF_GOOGLE_REPORT_STATE: self.google_report_state,
            PREF_GOOGLE_SECURE_DEVICES_PIN: self.google_secure_devices_pin,
        }

    @property
    def remote_enabled(self):
        """Return if remote is enabled on start."""
        enabled = self._prefs.get(PREF_ENABLE_REMOTE, False)

        if not enabled:
            return False

        if self._has_local_trusted_network or self._has_local_trusted_proxies:
            return False

        return True

    @property
    def alexa_enabled(self):
        """Return if Alexa is enabled."""
        return self._prefs[PREF_ENABLE_ALEXA]

    @property
    def alexa_report_state(self):
        """Return if Alexa report state is enabled."""
        return self._prefs.get(PREF_ALEXA_REPORT_STATE, DEFAULT_ALEXA_REPORT_STATE)

    @property
    def alexa_default_expose(self) -> Optional[List[str]]:
        """Return array of entity domains that are exposed by default to Alexa.

        Can return None, in which case for backwards should be interpreted as allow all domains.
        """
        return self._prefs.get(PREF_ALEXA_DEFAULT_EXPOSE)

    @property
    def alexa_entity_configs(self):
        """Return Alexa Entity configurations."""
        return self._prefs.get(PREF_ALEXA_ENTITY_CONFIGS, {})

    @property
    def google_enabled(self):
        """Return if Google is enabled."""
        return self._prefs[PREF_ENABLE_GOOGLE]

    @property
    def google_report_state(self):
        """Return if Google report state is enabled."""
        return self._prefs.get(PREF_GOOGLE_REPORT_STATE, DEFAULT_GOOGLE_REPORT_STATE)

    @property
    def google_secure_devices_pin(self):
        """Return if Google is allowed to unlock locks."""
        return self._prefs.get(PREF_GOOGLE_SECURE_DEVICES_PIN)

    @property
    def google_entity_configs(self):
        """Return Google Entity configurations."""
        return self._prefs.get(PREF_GOOGLE_ENTITY_CONFIGS, {})

    @property
    def google_local_webhook_id(self):
        """Return Google webhook ID to receive local messages."""
        return self._prefs[PREF_GOOGLE_LOCAL_WEBHOOK_ID]

    @property
    def google_default_expose(self) -> Optional[List[str]]:
        """Return array of entity domains that are exposed by default to Google.

        Can return None, in which case for backwards should be interpreted as allow all domains.
        """
        return self._prefs.get(PREF_GOOGLE_DEFAULT_EXPOSE)

    @property
    def cloudhooks(self):
        """Return the published cloud webhooks."""
        return self._prefs.get(PREF_CLOUDHOOKS, {})

    async def get_cloud_user(self) -> str:
        """Return ID from Home Assistant Cloud system user."""
        user = await self._load_cloud_user()

        if user:
            return user.id

        user = await self._hass.auth.async_create_system_user(
            "Home Assistant Cloud", [GROUP_ID_ADMIN]
        )
        await self.async_update(cloud_user=user.id)
        return user.id

    async def _load_cloud_user(self) -> Optional[User]:
        """Load cloud user if available."""
        user_id = self._prefs.get(PREF_CLOUD_USER)

        if user_id is None:
            return None

        # Fetch the user. It can happen that the user no longer exists if
        # an image was restored without restoring the cloud prefs.
        return await self._hass.auth.async_get_user(user_id)

    @property
    def _has_local_trusted_network(self) -> bool:
        """Return if we allow localhost to bypass auth."""
        local4 = ip_address("127.0.0.1")
        local6 = ip_address("::1")

        for prv in self._hass.auth.auth_providers:
            if prv.type != "trusted_networks":
                continue

            for network in prv.trusted_networks:
                if local4 in network or local6 in network:
                    return True

        return False

    @property
    def _has_local_trusted_proxies(self) -> bool:
        """Return if we allow localhost to be a proxy and use its data."""
        if not hasattr(self._hass, "http"):
            return False

        local4 = ip_address("127.0.0.1")
        local6 = ip_address("::1")

        if any(
            local4 in nwk or local6 in nwk for nwk in self._hass.http.trusted_proxies
        ):
            return True

        return False

    async def _save_prefs(self, prefs):
        """Save preferences to disk."""
        self._prefs = prefs
        await self._store.async_save(self._prefs)

        for listener in self._listeners:
            self._hass.async_create_task(async_create_catching_coro(listener(self)))

    @callback
    def _empty_config(self, username):
        """Return an empty config."""
        return {
            PREF_ALEXA_DEFAULT_EXPOSE: DEFAULT_EXPOSED_DOMAINS,
            PREF_ALEXA_ENTITY_CONFIGS: {},
            PREF_CLOUD_USER: None,
            PREF_CLOUDHOOKS: {},
            PREF_ENABLE_ALEXA: True,
            PREF_ENABLE_GOOGLE: True,
            PREF_ENABLE_REMOTE: False,
            PREF_GOOGLE_DEFAULT_EXPOSE: DEFAULT_EXPOSED_DOMAINS,
            PREF_GOOGLE_ENTITY_CONFIGS: {},
            PREF_GOOGLE_LOCAL_WEBHOOK_ID: self._hass.components.webhook.async_generate_id(),
            PREF_GOOGLE_SECURE_DEVICES_PIN: None,
            PREF_USERNAME: username,
        }

Preference management for cloud. Handle cloud preferences. Initialize cloud prefs. Finish initializing the preferences. Listen for updates to the preferences. Update user preferences. Update config for a Google entity. Update config for an Alexa entity. Set the username that is logged in. # Logging out. Return dictionary version. Return if remote is enabled on start. Return if Alexa is enabled. Return if Alexa report state is enabled. Return array of entity domains that are exposed by default to Alexa.          Can return None, in which case for backwards should be interpreted as allow all domains. Return Alexa Entity configurations. Return if Google is enabled. Return if Google report state is enabled. Return if Google is allowed to unlock locks. Return Google Entity configurations. Return Google webhook ID to receive local messages. Return array of entity domains that are exposed by default to Google.          Can return None, in which case for backwards should be interpreted as allow all domains. Return the published cloud webhooks. Return ID from Home Assistant Cloud system user. Load cloud user if available. # Fetch the user. It can happen that the user no longer exists if # an image was restored without restoring the cloud prefs. Return if we allow localhost to bypass auth. Return if we allow localhost to be a proxy and use its data. Save preferences to disk. Return an empty config.