"""
Support for real-time departure information for public transport in Munich.

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

import voluptuous as vol

import homeassistant.helpers.config_validation as cv
from homeassistant.util import Throttle
from homeassistant.helpers.entity import Entity
from homeassistant.components.sensor import PLATFORM_SCHEMA
from homeassistant.const import STATE_UNKNOWN

REQUIREMENTS = ['PyMVGLive==1.1.3']

_LOGGER = logging.getLogger(__name__)

CONF_BUS = 'bus'
CONF_DEST = 'destination'
CONF_LINE = 'line'
CONF_OFFSET = 'offset'
CONF_SBAHN = 'sbahn'
CONF_STATION = 'station'
CONF_TRAM = 'tram'
CONF_UBAHN = 'ubahn'

ICON = 'mdi:bus'

MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=15)

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
    vol.Required(CONF_STATION): cv.string,
    vol.Optional(CONF_DEST, default=None): cv.string,
    vol.Optional(CONF_LINE, default=None): cv.string,
    vol.Optional(CONF_OFFSET, default=0): cv.positive_int,
    vol.Optional(CONF_UBAHN, default=True): cv.boolean,
    vol.Optional(CONF_TRAM, default=True): cv.boolean,
    vol.Optional(CONF_BUS, default=True): cv.boolean,
    vol.Optional(CONF_SBAHN, default=True): cv.boolean,
})


def setup_platform(hass, config, add_devices, discovery_info=None):
    """Set up the MVG Live Sensor."""
    station = config.get(CONF_STATION)
    destination = config.get(CONF_DEST)
    line = config.get(CONF_LINE)
    offset = config.get(CONF_OFFSET)
    ubahn = config.get(CONF_UBAHN)
    tram = config.get(CONF_TRAM)
    bus = config.get(CONF_BUS)
    sbahn = config.get(CONF_SBAHN)

    add_devices([MVGLiveSensor(
        station, destination, line, offset, ubahn, tram, bus, sbahn)], True)


class MVGLiveSensor(Entity):
    """Implementation of an MVG Live sensor."""

    def __init__(self, station, destination, line,
                 offset, ubahn, tram, bus, sbahn):
        """Initialize the sensor."""
        self._station = station
        self._destination = destination
        self._line = line
        self.data = MVGLiveData(station, destination, line,
                                offset, ubahn, tram, bus, sbahn)
        self._state = STATE_UNKNOWN

    @property
    def name(self):
        """Return the name of the sensor."""
        # e.g.
        # 'Hauptbahnhof (S1)'
        # 'Hauptbahnhof-Marienplatz'
        # 'Hauptbahnhof-Marienplatz (S1)'
        namestr = self._station
        if self._destination:
            namestr = '{}-{}'.format(namestr, self._destination)
        if self._line:
            namestr = '{} ({})'.format(namestr, self._line)
        return namestr

    @property
    def icon(self):
        """Return the icon for the frontend."""
        return ICON

    @property
    def state(self):
        """Return the departure time of the next train."""
        return self._state

    @property
    def state_attributes(self):
        """Return the state attributes."""
        return self.data.nextdeparture

    def update(self):
        """Get the latest data and update the state."""
        self.data.update()
        if not self.data.nextdeparture:
            self._state = '-'
        else:
            self._state = self.data.nextdeparture.get('time', '-')


class MVGLiveData(object):
    """Pull data from the mvg-live.de web page."""

    def __init__(self, station, destination, line,
                 offset, ubahn, tram, bus, sbahn):
        """Initialize the sensor."""
        import MVGLive
        self._station = station
        self._destination = destination
        self._line = line
        self._offset = offset
        self._ubahn = ubahn
        self._tram = tram
        self._bus = bus
        self._sbahn = sbahn
        self.mvg = MVGLive.MVGLive()
        self.nextdeparture = {}

    @Throttle(MIN_TIME_BETWEEN_UPDATES)
    def update(self):
        """Update the connection data."""
        try:
            _departures = self.mvg.getlivedata(
                station=self._station, ubahn=self._ubahn, tram=self._tram,
                bus=self._bus, sbahn=self._sbahn)
        except ValueError:
            self.nextdeparture = {}
            _LOGGER.warning("Returned data not understood.")
            return
        for _departure in _departures:
            # find the first departure meeting the criteria
            if not _departure['destination'].startswith(self._destination):
                continue
            elif _departure['time'] < self._offset:
                continue
            # now select the relevant data
            _nextdep = {}
            for k in ['destination', 'linename', 'time', 'direction',
                      'product']:
                _nextdep[k] = _departure.get(k, '')
            _nextdep['time'] = int(_nextdep['time'])
            self.nextdeparture = _nextdep
            break
