"""Support for Blink Home Camera System."""

from copy import deepcopy
import logging
from typing import Any

from blinkpy.auth import Auth
from blinkpy.blinkpy import Blink

from homeassistant.components import persistent_notification
from homeassistant.const import CONF_SCAN_INTERVAL
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.typing import ConfigType

from .const import DEFAULT_SCAN_INTERVAL, DOMAIN, PLATFORMS
from .coordinator import BlinkConfigEntry, BlinkUpdateCoordinator
from .services import async_setup_services

_LOGGER = logging.getLogger(__name__)


CONFIG_SCHEMA = cv.config_entry_only_config_schema(DOMAIN)


async def _reauth_flow_wrapper(
    hass: HomeAssistant, entry: BlinkConfigEntry, data: dict[str, Any]
) -> None:
    """Reauth flow wrapper."""
    entry.async_start_reauth(hass, data=data)
    persistent_notification.async_create(
        hass,
        (
            "Blink configuration migrated to a new version. Please go to the"
            " integrations page to re-configure (such as sending a new 2FA key)."
        ),
        "Blink Migration",
    )


async def async_migrate_entry(hass: HomeAssistant, entry: BlinkConfigEntry) -> bool:
    """Handle migration of a previous version config entry."""
    _LOGGER.debug("Migrating from version %s", entry.version)
    data = {**entry.data}
    if entry.version == 1:
        data.pop("login_response", None)
        await _reauth_flow_wrapper(hass, entry, data)
        return False
    if entry.version == 2:
        await _reauth_flow_wrapper(hass, entry, data)
        return False
    if entry.version == 3:
        # Migrate device_id to hardware_id for blinkpy 0.25.x OAuth2 compatibility
        if "device_id" in data:
            data["hardware_id"] = data.pop("device_id")
            hass.config_entries.async_update_entry(entry, data=data, version=4)
        return True
    return True


async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
    """Set up Blink."""

    async_setup_services(hass)

    return True


async def async_setup_entry(hass: HomeAssistant, entry: BlinkConfigEntry) -> bool:
    """Set up Blink via config entry."""
    _async_import_options_from_data_if_missing(hass, entry)
    session = async_get_clientsession(hass)
    blink = Blink(session=session)
    auth_data = deepcopy(dict(entry.data))
    blink.auth = Auth(
        auth_data,
        no_prompt=True,
        session=session,
        callback=lambda: _async_update_entry_data(hass, entry, blink),
    )
    blink.refresh_rate = entry.options.get(CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL)
    coordinator = BlinkUpdateCoordinator(hass, entry, blink)

    await coordinator.async_config_entry_first_refresh()

    entry.runtime_data = coordinator

    await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)

    return True


@callback
def _async_update_entry_data(
    hass: HomeAssistant, entry: BlinkConfigEntry, blink: Blink
) -> None:
    """Update the config entry data after token refresh."""
    hass.config_entries.async_update_entry(entry, data=blink.auth.login_attributes)


@callback
def _async_import_options_from_data_if_missing(
    hass: HomeAssistant, entry: BlinkConfigEntry
) -> None:
    options = dict(entry.options)
    if CONF_SCAN_INTERVAL not in entry.options:
        options[CONF_SCAN_INTERVAL] = entry.data.get(
            CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL
        )
        hass.config_entries.async_update_entry(entry, options=options)


async def async_unload_entry(hass: HomeAssistant, entry: BlinkConfigEntry) -> bool:
    """Unload Blink entry."""
    return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
