"""Camera platform that has a Raspberry Pi camera."""
import os
import subprocess
import logging
import shutil
from tempfile import NamedTemporaryFile

import voluptuous as vol

from homeassistant.components.camera import Camera, PLATFORM_SCHEMA
from homeassistant.const import CONF_NAME, CONF_FILE_PATH, EVENT_HOMEASSISTANT_STOP
from homeassistant.helpers import config_validation as cv

_LOGGER = logging.getLogger(__name__)

CONF_HORIZONTAL_FLIP = "horizontal_flip"
CONF_IMAGE_HEIGHT = "image_height"
CONF_IMAGE_QUALITY = "image_quality"
CONF_IMAGE_ROTATION = "image_rotation"
CONF_IMAGE_WIDTH = "image_width"
CONF_TIMELAPSE = "timelapse"
CONF_VERTICAL_FLIP = "vertical_flip"

DEFAULT_HORIZONTAL_FLIP = 0
DEFAULT_IMAGE_HEIGHT = 480
DEFAULT_IMAGE_QUALITY = 7
DEFAULT_IMAGE_ROTATION = 0
DEFAULT_IMAGE_WIDTH = 640
DEFAULT_NAME = "Raspberry Pi Camera"
DEFAULT_TIMELAPSE = 1000
DEFAULT_VERTICAL_FLIP = 0

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
    {
        vol.Optional(CONF_FILE_PATH): cv.isfile,
        vol.Optional(CONF_HORIZONTAL_FLIP, default=DEFAULT_HORIZONTAL_FLIP): vol.All(
            vol.Coerce(int), vol.Range(min=0, max=1)
        ),
        vol.Optional(CONF_IMAGE_HEIGHT, default=DEFAULT_IMAGE_HEIGHT): vol.Coerce(int),
        vol.Optional(CONF_IMAGE_QUALITY, default=DEFAULT_IMAGE_QUALITY): vol.All(
            vol.Coerce(int), vol.Range(min=0, max=100)
        ),
        vol.Optional(CONF_IMAGE_ROTATION, default=DEFAULT_IMAGE_ROTATION): vol.All(
            vol.Coerce(int), vol.Range(min=0, max=359)
        ),
        vol.Optional(CONF_IMAGE_WIDTH, default=DEFAULT_IMAGE_WIDTH): vol.Coerce(int),
        vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
        vol.Optional(CONF_TIMELAPSE, default=1000): vol.Coerce(int),
        vol.Optional(CONF_VERTICAL_FLIP, default=DEFAULT_VERTICAL_FLIP): vol.All(
            vol.Coerce(int), vol.Range(min=0, max=1)
        ),
    }
)


def kill_raspistill(*args):
    """Kill any previously running raspistill process.."""
    subprocess.Popen(
        ["killall", "raspistill"], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT
    )


def setup_platform(hass, config, add_entities, discovery_info=None):
    """Set up the Raspberry Camera."""
    if shutil.which("raspistill") is None:
        _LOGGER.error("'raspistill' was not found")
        return False

    setup_config = {
        CONF_NAME: config.get(CONF_NAME),
        CONF_IMAGE_WIDTH: config.get(CONF_IMAGE_WIDTH),
        CONF_IMAGE_HEIGHT: config.get(CONF_IMAGE_HEIGHT),
        CONF_IMAGE_QUALITY: config.get(CONF_IMAGE_QUALITY),
        CONF_IMAGE_ROTATION: config.get(CONF_IMAGE_ROTATION),
        CONF_TIMELAPSE: config.get(CONF_TIMELAPSE),
        CONF_HORIZONTAL_FLIP: config.get(CONF_HORIZONTAL_FLIP),
        CONF_VERTICAL_FLIP: config.get(CONF_VERTICAL_FLIP),
        CONF_FILE_PATH: config.get(CONF_FILE_PATH),
    }

    hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, kill_raspistill)

    file_path = setup_config[CONF_FILE_PATH]

    def delete_temp_file(*args):
        """Delete the temporary file to prevent saving multiple temp images.

        Only used when no path is defined
        """
        os.remove(file_path)

    # If no file path is defined, use a temporary file
    if file_path is None:
        temp_file = NamedTemporaryFile(suffix=".jpg", delete=False)
        temp_file.close()
        file_path = temp_file.name
        setup_config[CONF_FILE_PATH] = file_path
        hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, delete_temp_file)

    # Check whether the file path has been whitelisted
    elif not hass.config.is_allowed_path(file_path):
        _LOGGER.error("'%s' is not a whitelisted directory", file_path)
        return False

    add_entities([RaspberryCamera(setup_config)])


class RaspberryCamera(Camera):
    """Representation of a Raspberry Pi camera."""

    def __init__(self, device_info):
        """Initialize Raspberry Pi camera component."""
        super().__init__()

        self._name = device_info[CONF_NAME]
        self._config = device_info

        # Kill if there's raspistill instance
        kill_raspistill()

        cmd_args = [
            "raspistill",
            "--nopreview",
            "-o",
            device_info[CONF_FILE_PATH],
            "-t",
            "0",
            "-w",
            str(device_info[CONF_IMAGE_WIDTH]),
            "-h",
            str(device_info[CONF_IMAGE_HEIGHT]),
            "-tl",
            str(device_info[CONF_TIMELAPSE]),
            "-q",
            str(device_info[CONF_IMAGE_QUALITY]),
            "-rot",
            str(device_info[CONF_IMAGE_ROTATION]),
        ]
        if device_info[CONF_HORIZONTAL_FLIP]:
            cmd_args.append("-hf")

        if device_info[CONF_VERTICAL_FLIP]:
            cmd_args.append("-vf")

        subprocess.Popen(cmd_args, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)

    def camera_image(self):
        """Return raspistill image response."""
        with open(self._config[CONF_FILE_PATH], "rb") as file:
            return file.read()

    @property
    def name(self):
        """Return the name of this camera."""
        return self._name
