"""Support for Blink Home Camera System."""
from datetime import timedelta
import logging

from blinkpy import blinkpy
import voluptuous as vol

from homeassistant.const import (
    CONF_BINARY_SENSORS,
    CONF_FILENAME,
    CONF_MODE,
    CONF_MONITORED_CONDITIONS,
    CONF_NAME,
    CONF_OFFSET,
    CONF_PASSWORD,
    CONF_SCAN_INTERVAL,
    CONF_SENSORS,
    CONF_USERNAME,
    TEMP_FAHRENHEIT,
)
from homeassistant.helpers import config_validation as cv, discovery

_LOGGER = logging.getLogger(__name__)

DOMAIN = "blink"
BLINK_DATA = "blink"

CONF_CAMERA = "camera"
CONF_ALARM_CONTROL_PANEL = "alarm_control_panel"

DEFAULT_BRAND = "Blink"
DEFAULT_ATTRIBUTION = "Data provided by immedia-semi.com"
SIGNAL_UPDATE_BLINK = "blink_update"

DEFAULT_SCAN_INTERVAL = timedelta(seconds=300)

TYPE_CAMERA_ARMED = "motion_enabled"
TYPE_MOTION_DETECTED = "motion_detected"
TYPE_TEMPERATURE = "temperature"
TYPE_BATTERY = "battery"
TYPE_WIFI_STRENGTH = "wifi_strength"

SERVICE_REFRESH = "blink_update"
SERVICE_TRIGGER = "trigger_camera"
SERVICE_SAVE_VIDEO = "save_video"

BINARY_SENSORS = {
    TYPE_CAMERA_ARMED: ["Camera Armed", "mdi:verified"],
    TYPE_MOTION_DETECTED: ["Motion Detected", "mdi:run-fast"],
}

SENSORS = {
    TYPE_TEMPERATURE: ["Temperature", TEMP_FAHRENHEIT, "mdi:thermometer"],
    TYPE_BATTERY: ["Battery", "", "mdi:battery-80"],
    TYPE_WIFI_STRENGTH: ["Wifi Signal", "dBm", "mdi:wifi-strength-2"],
}

BINARY_SENSOR_SCHEMA = vol.Schema(
    {
        vol.Optional(CONF_MONITORED_CONDITIONS, default=list(BINARY_SENSORS)): vol.All(
            cv.ensure_list, [vol.In(BINARY_SENSORS)]
        )
    }
)

SENSOR_SCHEMA = vol.Schema(
    {
        vol.Optional(CONF_MONITORED_CONDITIONS, default=list(SENSORS)): vol.All(
            cv.ensure_list, [vol.In(SENSORS)]
        )
    }
)

SERVICE_TRIGGER_SCHEMA = vol.Schema({vol.Required(CONF_NAME): cv.string})

SERVICE_SAVE_VIDEO_SCHEMA = vol.Schema(
    {vol.Required(CONF_NAME): cv.string, vol.Required(CONF_FILENAME): cv.string}
)

CONFIG_SCHEMA = vol.Schema(
    {
        DOMAIN: vol.Schema(
            {
                vol.Required(CONF_USERNAME): cv.string,
                vol.Required(CONF_PASSWORD): cv.string,
                vol.Optional(
                    CONF_SCAN_INTERVAL, default=DEFAULT_SCAN_INTERVAL
                ): cv.time_period,
                vol.Optional(CONF_BINARY_SENSORS, default={}): BINARY_SENSOR_SCHEMA,
                vol.Optional(CONF_SENSORS, default={}): SENSOR_SCHEMA,
                vol.Optional(CONF_OFFSET, default=1): int,
                vol.Optional(CONF_MODE, default=""): cv.string,
            }
        )
    },
    extra=vol.ALLOW_EXTRA,
)


def setup(hass, config):
    """Set up Blink System."""

    conf = config[BLINK_DATA]
    username = conf[CONF_USERNAME]
    password = conf[CONF_PASSWORD]
    scan_interval = conf[CONF_SCAN_INTERVAL]
    is_legacy = bool(conf[CONF_MODE] == "legacy")
    motion_interval = conf[CONF_OFFSET]
    hass.data[BLINK_DATA] = blinkpy.Blink(
        username=username,
        password=password,
        motion_interval=motion_interval,
        legacy_subdomain=is_legacy,
    )
    hass.data[BLINK_DATA].refresh_rate = scan_interval.total_seconds()
    hass.data[BLINK_DATA].start()

    platforms = [
        ("alarm_control_panel", {}),
        ("binary_sensor", conf[CONF_BINARY_SENSORS]),
        ("camera", {}),
        ("sensor", conf[CONF_SENSORS]),
    ]

    for component, schema in platforms:
        discovery.load_platform(hass, component, DOMAIN, schema, config)

    def trigger_camera(call):
        """Trigger a camera."""
        cameras = hass.data[BLINK_DATA].cameras
        name = call.data[CONF_NAME]
        if name in cameras:
            cameras[name].snap_picture()
        hass.data[BLINK_DATA].refresh(force_cache=True)

    def blink_refresh(event_time):
        """Call blink to refresh info."""
        hass.data[BLINK_DATA].refresh(force_cache=True)

    async def async_save_video(call):
        """Call save video service handler."""
        await async_handle_save_video_service(hass, call)

    hass.services.register(DOMAIN, SERVICE_REFRESH, blink_refresh)
    hass.services.register(
        DOMAIN, SERVICE_TRIGGER, trigger_camera, schema=SERVICE_TRIGGER_SCHEMA
    )
    hass.services.register(
        DOMAIN, SERVICE_SAVE_VIDEO, async_save_video, schema=SERVICE_SAVE_VIDEO_SCHEMA
    )
    return True


async def async_handle_save_video_service(hass, call):
    """Handle save video service calls."""
    camera_name = call.data[CONF_NAME]
    video_path = call.data[CONF_FILENAME]
    if not hass.config.is_allowed_path(video_path):
        _LOGGER.error("Can't write %s, no access to path!", video_path)
        return

    def _write_video(camera_name, video_path):
        """Call video write."""
        all_cameras = hass.data[BLINK_DATA].cameras
        if camera_name in all_cameras:
            all_cameras[camera_name].video_to_file(video_path)

    try:
        await hass.async_add_executor_job(_write_video, camera_name, video_path)
    except OSError as err:
        _LOGGER.error("Can't write image to file: %s", err)
