"""
Support for the Automatic platform.

For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.automatic/
"""
import asyncio
from datetime import timedelta
import json
import logging
import os

from aiohttp import web
import voluptuous as vol

from homeassistant.components.device_tracker import (
    ATTR_ATTRIBUTES, ATTR_DEV_ID, ATTR_GPS, ATTR_GPS_ACCURACY, ATTR_HOST_NAME,
    ATTR_MAC, PLATFORM_SCHEMA)
from homeassistant.components.http import HomeAssistantView
from homeassistant.const import EVENT_HOMEASSISTANT_STOP
from homeassistant.core import callback
from homeassistant.helpers.aiohttp_client import async_get_clientsession
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.event import async_track_time_interval

REQUIREMENTS = ['aioautomatic==0.6.5']

_LOGGER = logging.getLogger(__name__)

ATTR_FUEL_LEVEL = 'fuel_level'
AUTOMATIC_CONFIG_FILE = '.automatic/session-{}.json'

CONF_CLIENT_ID = 'client_id'
CONF_CURRENT_LOCATION = 'current_location'
CONF_DEVICES = 'devices'
CONF_SECRET = 'secret'

DATA_CONFIGURING = 'automatic_configurator_clients'
DATA_REFRESH_TOKEN = 'refresh_token'
DEFAULT_SCOPE = ['location', 'trip', 'vehicle:events', 'vehicle:profile']
DEFAULT_TIMEOUT = 5
DEPENDENCIES = ['http']

EVENT_AUTOMATIC_UPDATE = 'automatic_update'

FULL_SCOPE = DEFAULT_SCOPE + ['current_location']

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
    vol.Required(CONF_CLIENT_ID): cv.string,
    vol.Required(CONF_SECRET): cv.string,
    vol.Optional(CONF_CURRENT_LOCATION, default=False): cv.boolean,
    vol.Optional(CONF_DEVICES): vol.All(cv.ensure_list, [cv.string]),
})


def _get_refresh_token_from_file(hass, filename):
    """Attempt to load session data from file."""
    path = hass.config.path(filename)

    if not os.path.isfile(path):
        return None

    try:
        with open(path) as data_file:
            data = json.load(data_file)
            if data is None:
                return None

            return data.get(DATA_REFRESH_TOKEN)
    except ValueError:
        return None


def _write_refresh_token_to_file(hass, filename, refresh_token):
    """Attempt to store session data to file."""
    path = hass.config.path(filename)

    os.makedirs(os.path.dirname(path), exist_ok=True)
    with open(path, 'w+') as data_file:
        json.dump({
            DATA_REFRESH_TOKEN: refresh_token
        }, data_file)


@asyncio.coroutine
def async_setup_scanner(hass, config, async_see, discovery_info=None):
    """Validate the configuration and return an Automatic scanner."""
    import aioautomatic

    hass.http.register_view(AutomaticAuthCallbackView())

    scope = FULL_SCOPE if config.get(CONF_CURRENT_LOCATION) else DEFAULT_SCOPE

    client = aioautomatic.Client(
        client_id=config[CONF_CLIENT_ID],
        client_secret=config[CONF_SECRET],
        client_session=async_get_clientsession(hass),
        request_kwargs={'timeout': DEFAULT_TIMEOUT})

    filename = AUTOMATIC_CONFIG_FILE.format(config[CONF_CLIENT_ID])
    refresh_token = yield from hass.async_add_job(
        _get_refresh_token_from_file, hass, filename)

    @asyncio.coroutine
    def initialize_data(session):
        """Initialize the AutomaticData object from the created session."""
        hass.async_add_job(
            _write_refresh_token_to_file, hass, filename,
            session.refresh_token)
        data = AutomaticData(
            hass, client, session, config.get(CONF_DEVICES), async_see)

        # Load the initial vehicle data
        vehicles = yield from session.get_vehicles()
        for vehicle in vehicles:
            hass.async_create_task(data.load_vehicle(vehicle))

        # Create a task instead of adding a tracking job, since this task will
        # run until the websocket connection is closed.
        hass.loop.create_task(data.ws_connect())

    if refresh_token is not None:
        try:
            session = yield from client.create_session_from_refresh_token(
                refresh_token)
            yield from initialize_data(session)
            return True
        except aioautomatic.exceptions.AutomaticError as err:
            _LOGGER.error(str(err))

    configurator = hass.components.configurator
    request_id = configurator.async_request_config(
        "Automatic", description=(
            "Authorization required for Automatic device tracker."),
        link_name="Click here to authorize Home Assistant.",
        link_url=client.generate_oauth_url(scope),
        entity_picture="/static/images/logo_automatic.png",
    )

    @asyncio.coroutine
    def initialize_callback(code, state):
        """Call after OAuth2 response is returned."""
        try:
            session = yield from client.create_session_from_oauth_code(
                code, state)
            yield from initialize_data(session)
            configurator.async_request_done(request_id)
        except aioautomatic.exceptions.AutomaticError as err:
            _LOGGER.error(str(err))
            configurator.async_notify_errors(request_id, str(err))