"""The surepetcare integration."""
from __future__ import annotations

from datetime import timedelta
import logging
from typing import Any

from surepy import Surepy
from surepy.enums import LockState
from surepy.exceptions import SurePetcareAuthenticationError, SurePetcareError
import voluptuous as vol

from homeassistant.const import CONF_PASSWORD, CONF_SCAN_INTERVAL, CONF_USERNAME
from homeassistant.core import HomeAssistant
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.helpers.event import async_track_time_interval

from .const import (
    ATTR_FLAP_ID,
    ATTR_LOCK_STATE,
    CONF_FEEDERS,
    CONF_FLAPS,
    CONF_PETS,
    DOMAIN,
    SERVICE_SET_LOCK_STATE,
    SPC,
    SURE_API_TIMEOUT,
    TOPIC_UPDATE,
)

_LOGGER = logging.getLogger(__name__)

PLATFORMS = ["binary_sensor", "sensor"]
SCAN_INTERVAL = timedelta(minutes=3)

CONFIG_SCHEMA = vol.Schema(
    {
        DOMAIN: vol.Schema(
            vol.All(
                {
                    vol.Required(CONF_USERNAME): cv.string,
                    vol.Required(CONF_PASSWORD): cv.string,
                    vol.Optional(CONF_FEEDERS): vol.All(
                        cv.ensure_list, [cv.positive_int]
                    ),
                    vol.Optional(CONF_FLAPS): vol.All(
                        cv.ensure_list, [cv.positive_int]
                    ),
                    vol.Optional(CONF_PETS): vol.All(cv.ensure_list, [cv.positive_int]),
                    vol.Optional(CONF_SCAN_INTERVAL): cv.time_period,
                },
                cv.deprecated(CONF_FEEDERS),
                cv.deprecated(CONF_FLAPS),
                cv.deprecated(CONF_PETS),
                cv.deprecated(CONF_SCAN_INTERVAL),
            )
        )
    },
    extra=vol.ALLOW_EXTRA,
)


async def async_setup(hass: HomeAssistant, config: dict) -> bool:
    """Set up the Sure Petcare integration."""
    conf = config[DOMAIN]
    hass.data.setdefault(DOMAIN, {})

    try:
        surepy = Surepy(
            conf[CONF_USERNAME],
            conf[CONF_PASSWORD],
            auth_token=None,
            api_timeout=SURE_API_TIMEOUT,
            session=async_get_clientsession(hass),
        )
    except SurePetcareAuthenticationError:
        _LOGGER.error("Unable to connect to surepetcare.io: Wrong credentials!")
        return False
    except SurePetcareError as error:
        _LOGGER.error("Unable to connect to surepetcare.io: Wrong %s!", error)
        return False

    spc = SurePetcareAPI(hass, surepy)
    hass.data[DOMAIN][SPC] = spc

    await spc.async_update()

    async_track_time_interval(hass, spc.async_update, SCAN_INTERVAL)

    # load platforms
    hass.async_create_task(
        hass.helpers.discovery.async_load_platform("binary_sensor", DOMAIN, {}, config)
    )
    hass.async_create_task(
        hass.helpers.discovery.async_load_platform("sensor", DOMAIN, {}, config)
    )

    async def handle_set_lock_state(call):
        """Call when setting the lock state."""
        await spc.set_lock_state(call.data[ATTR_FLAP_ID], call.data[ATTR_LOCK_STATE])
        await spc.async_update()

    lock_state_service_schema = vol.Schema(
        {
            vol.Required(ATTR_FLAP_ID): vol.All(
                cv.positive_int, vol.In(spc.states.keys())
            ),
            vol.Required(ATTR_LOCK_STATE): vol.All(
                cv.string,
                vol.Lower,
                vol.In(
                    [
                        # https://github.com/PyCQA/pylint/issues/2062
                        # pylint: disable=no-member
                        LockState.UNLOCKED.name.lower(),
                        LockState.LOCKED_IN.name.lower(),
                        LockState.LOCKED_OUT.name.lower(),
                        LockState.LOCKED_ALL.name.lower(),
                    ]
                ),
            ),
        }
    )

    hass.services.async_register(
        DOMAIN,
        SERVICE_SET_LOCK_STATE,
        handle_set_lock_state,
        schema=lock_state_service_schema,
    )

    return True


class SurePetcareAPI:
    """Define a generic Sure Petcare object."""

    def __init__(self, hass: HomeAssistant, surepy: Surepy) -> None:
        """Initialize the Sure Petcare object."""
        self.hass = hass
        self.surepy = surepy
        self.states = {}

    async def async_update(self, _: Any = None) -> None:
        """Get the latest data from Sure Petcare."""

        try:
            self.states = await self.surepy.get_entities()
        except SurePetcareError as error:
            _LOGGER.error("Unable to fetch data: %s", error)

        async_dispatcher_send(self.hass, TOPIC_UPDATE)

    async def set_lock_state(self, flap_id: int, state: str) -> None:
        """Update the lock state of a flap."""

        # https://github.com/PyCQA/pylint/issues/2062
        # pylint: disable=no-member
        if state == LockState.UNLOCKED.name.lower():
            await self.surepy.unlock(flap_id)
        elif state == LockState.LOCKED_IN.name.lower():
            await self.surepy.lock_in(flap_id)
        elif state == LockState.LOCKED_OUT.name.lower():
            await self.surepy.lock_out(flap_id)
        elif state == LockState.LOCKED_ALL.name.lower():
            await self.surepy.lock(flap_id)
