"""Support for Mopar vehicles."""
import logging
from datetime import timedelta

import voluptuous as vol

from homeassistant.components.lock import DOMAIN as LOCK
from homeassistant.components.sensor import DOMAIN as SENSOR
from homeassistant.components.switch import DOMAIN as SWITCH
from homeassistant.const import (
    CONF_USERNAME,
    CONF_PASSWORD,
    CONF_PIN,
    CONF_SCAN_INTERVAL,
)
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.discovery import load_platform
from homeassistant.helpers.dispatcher import dispatcher_send
from homeassistant.helpers.event import track_time_interval

DOMAIN = "mopar"
DATA_UPDATED = "{}_data_updated".format(DOMAIN)

_LOGGER = logging.getLogger(__name__)

COOKIE_FILE = "mopar_cookies.pickle"
SUCCESS_RESPONSE = "completed"

SUPPORTED_PLATFORMS = [LOCK, SENSOR, SWITCH]

DEFAULT_INTERVAL = timedelta(days=7)

CONFIG_SCHEMA = vol.Schema(
    {
        DOMAIN: vol.Schema(
            {
                vol.Required(CONF_USERNAME): cv.string,
                vol.Required(CONF_PASSWORD): cv.string,
                vol.Required(CONF_PIN): cv.positive_int,
                vol.Optional(CONF_SCAN_INTERVAL, default=DEFAULT_INTERVAL): vol.All(
                    cv.time_period, cv.positive_timedelta
                ),
            }
        )
    },
    extra=vol.ALLOW_EXTRA,
)

SERVICE_HORN = "sound_horn"
ATTR_VEHICLE_INDEX = "vehicle_index"
SERVICE_HORN_SCHEMA = vol.Schema({vol.Required(ATTR_VEHICLE_INDEX): cv.positive_int})


def setup(hass, config):
    """Set up the Mopar component."""
    import motorparts

    conf = config[DOMAIN]
    cookie = hass.config.path(COOKIE_FILE)
    try:
        session = motorparts.get_session(
            conf[CONF_USERNAME], conf[CONF_PASSWORD], conf[CONF_PIN], cookie_path=cookie
        )
    except motorparts.MoparError:
        _LOGGER.error("Failed to login")
        return False

    data = hass.data[DOMAIN] = MoparData(hass, session)
    data.update(now=None)

    track_time_interval(hass, data.update, conf[CONF_SCAN_INTERVAL])

    def handle_horn(call):
        """Enable the horn on the Mopar vehicle."""
        data.actuate("horn", call.data[ATTR_VEHICLE_INDEX])

    hass.services.register(
        DOMAIN, SERVICE_HORN, handle_horn, schema=SERVICE_HORN_SCHEMA
    )

    for platform in SUPPORTED_PLATFORMS:
        load_platform(hass, platform, DOMAIN, {}, config)

    return True


class MoparData:
    """
    Container for Mopar vehicle data.

    Prevents session expiry re-login race condition.
    """

    def __init__(self, hass, session):
        """Initialize data."""
        self._hass = hass
        self._session = session
        self.vehicles = []
        self.vhrs = {}
        self.tow_guides = {}

    def update(self, now, **kwargs):
        """Update data."""
        import motorparts

        _LOGGER.debug("Updating vehicle data")
        try:
            self.vehicles = motorparts.get_summary(self._session)["vehicles"]
        except motorparts.MoparError:
            _LOGGER.exception("Failed to get summary")
            return

        for index, _ in enumerate(self.vehicles):
            try:
                self.vhrs[index] = motorparts.get_report(self._session, index)
                self.tow_guides[index] = motorparts.get_tow_guide(self._session, index)
            except motorparts.MoparError:
                _LOGGER.warning("Failed to update for vehicle index %s", index)
                return

        dispatcher_send(self._hass, DATA_UPDATED)

    @property
    def attribution(self):
        """Get the attribution string from Mopar."""
        import motorparts

        return motorparts.ATTRIBUTION

    def get_vehicle_name(self, index):
        """Get the name corresponding with this vehicle."""
        vehicle = self.vehicles[index]
        if not vehicle:
            return None
        return "{} {} {}".format(vehicle["year"], vehicle["make"], vehicle["model"])

    def actuate(self, command, index):
        """Run a command on the specified Mopar vehicle."""
        import motorparts

        try:
            response = getattr(motorparts, command)(self._session, index)
        except motorparts.MoparError as error:
            _LOGGER.error(error)
            return False

        return response == SUCCESS_RESPONSE
