"""The tests for the Radarr platform."""
import unittest

import pytest

import homeassistant.components.radarr.sensor as radarr
from homeassistant.const import DATA_GIGABYTES

from tests.async_mock import patch
from tests.common import get_test_home_assistant


def mocked_exception(*args, **kwargs):
    """Mock exception thrown by requests.get."""
    raise OSError


def mocked_requests_get(*args, **kwargs):
    """Mock requests.get invocations."""

    class MockResponse:
        """Class to represent a mocked response."""

        def __init__(self, json_data, status_code):
            """Initialize the mock response class."""
            self.json_data = json_data
            self.status_code = status_code

        def json(self):
            """Return the json of the response."""
            return self.json_data

    url = str(args[0])
    if "api/calendar" in url:
        return MockResponse(
            [
                {
                    "title": "Resident Evil",
                    "sortTitle": "resident evil final chapter",
                    "sizeOnDisk": 0,
                    "status": "announced",
                    "overview": "Alice, Jill, Claire, Chris, Leon, Ada, and...",
                    "inCinemas": "2017-01-25T00:00:00Z",
                    "physicalRelease": "2017-01-27T00:00:00Z",
                    "images": [
                        {
                            "coverType": "poster",
                            "url": (
                                "/radarr/MediaCover/12/poster.jpg"
                                "?lastWrite=636208663600000000"
                            ),
                        },
                        {
                            "coverType": "banner",
                            "url": (
                                "/radarr/MediaCover/12/banner.jpg"
                                "?lastWrite=636208663600000000"
                            ),
                        },
                    ],
                    "website": "",
                    "downloaded": "false",
                    "year": 2017,
                    "hasFile": "false",
                    "youTubeTrailerId": "B5yxr7lmxhg",
                    "studio": "Impact Pictures",
                    "path": "/path/to/Resident Evil The Final Chapter (2017)",
                    "profileId": 3,
                    "monitored": "false",
                    "runtime": 106,
                    "lastInfoSync": "2017-01-24T14:52:40.315434Z",
                    "cleanTitle": "residentevilfinalchapter",
                    "imdbId": "tt2592614",
                    "tmdbId": 173897,
                    "titleSlug": "resident-evil-the-final-chapter-2017",
                    "genres": ["Action", "Horror", "Science Fiction"],
                    "tags": [],
                    "added": "2017-01-24T14:52:39.989964Z",
                    "ratings": {"votes": 363, "value": 4.3},
                    "alternativeTitles": ["Resident Evil: Rising"],
                    "qualityProfileId": 3,
                    "id": 12,
                }
            ],
            200,
        )
    if "api/command" in url:
        return MockResponse(
            [
                {
                    "name": "RescanMovie",
                    "startedOn": "0001-01-01T00:00:00Z",
                    "stateChangeTime": "2014-02-05T05:09:09.2366139Z",
                    "sendUpdatesToClient": "true",
                    "state": "pending",
                    "id": 24,
                }
            ],
            200,
        )
    if "api/movie" in url:
        return MockResponse(
            [
                {
                    "title": "Assassin's Creed",
                    "sortTitle": "assassins creed",
                    "sizeOnDisk": 0,
                    "status": "released",
                    "overview": "Lynch discovers he is a descendant of...",
                    "inCinemas": "2016-12-21T00:00:00Z",
                    "images": [
                        {
                            "coverType": "poster",
                            "url": (
                                "/radarr/MediaCover/1/poster.jpg"
                                "?lastWrite=636200219330000000"
                            ),
                        },
                        {
                            "coverType": "banner",
                            "url": (
                                "/radarr/MediaCover/1/banner.jpg"
                                "?lastWrite=636200219340000000"
                            ),
                        },
                    ],
                    "website": "https://www.ubisoft.com/en-US/",
                    "downloaded": "false",
                    "year": 2016,
                    "hasFile": "false",
                    "youTubeTrailerId": "pgALJgMjXN4",
                    "studio": "20th Century Fox",
                    "path": "/path/to/Assassin's Creed (2016)",
                    "profileId": 6,
                    "monitored": "true",
                    "runtime": 115,
                    "lastInfoSync": "2017-01-23T22:05:32.365337Z",
                    "cleanTitle": "assassinscreed",
                    "imdbId": "tt2094766",
                    "tmdbId": 121856,
                    "titleSlug": "assassins-creed-121856",
                    "genres": ["Action", "Adventure", "Fantasy", "Science Fiction"],
                    "tags": [],
                    "added": "2017-01-14T20:18:52.938244Z",
                    "ratings": {"votes": 711, "value": 5.2},
                    "alternativeTitles": ["Assassin's Creed: The IMAX Experience"],
                    "qualityProfileId": 6,
                    "id": 1,
                }
            ],
            200,
        )
    if "api/diskspace" in url:
        return MockResponse(
            [
                {
                    "path": "/data",
                    "label": "",
                    "freeSpace": 282500067328,
                    "totalSpace": 499738734592,
                }
            ],
            200,
        )
    if "api/system/status" in url:
        return MockResponse(
            {
                "version": "0.2.0.210",
                "buildTime": "2017-01-22T23:12:49Z",
                "isDebug": "false",
                "isProduction": "true",
                "isAdmin": "false",
                "isUserInteractive": "false",
                "startupPath": "/path/to/radarr",
                "appData": "/path/to/radarr/data",
                "osVersion": "4.8.13.1",
                "isMonoRuntime": "true",
                "isMono": "true",
                "isLinux": "true",
                "isOsx": "false",
                "isWindows": "false",
                "branch": "develop",
                "authentication": "forms",
                "sqliteVersion": "3.16.2",
                "urlBase": "",
                "runtimeVersion": (
                    "4.6.1 (Stable 4.6.1.3/abb06f1 Mon Oct  3 07:57:59 UTC 2016)"
                ),
            },
            200,
        )
    return MockResponse({"error": "Unauthorized"}, 401)


class TestRadarrSetup(unittest.TestCase):
    """Test the Radarr platform."""

    # pylint: disable=invalid-name
    DEVICES = []

    def add_entities(self, devices, update):
        """Mock add devices."""
        for device in devices:
            self.DEVICES.append(device)

    def setUp(self):
        """Initialize values for this testcase class."""
        self.DEVICES = []
        self.hass = get_test_home_assistant()
        self.hass.config.time_zone = "America/Los_Angeles"
        self.addCleanup(self.tear_down_cleanup)

    def tear_down_cleanup(self):
        """Stop everything that was started."""
        self.hass.stop()

    @patch("requests.get", side_effect=mocked_requests_get)
    def test_diskspace_no_paths(self, req_mock):
        """Test getting all disk space."""
        config = {
            "platform": "radarr",
            "api_key": "foo",
            "days": "2",
            "unit": DATA_GIGABYTES,
            "include_paths": [],
            "monitored_conditions": ["diskspace"],
        }
        radarr.setup_platform(self.hass, config, self.add_entities, None)
        for device in self.DEVICES:
            device.update()
            assert "263.10" == device.state
            assert "mdi:harddisk" == device.icon
            assert DATA_GIGABYTES == device.unit_of_measurement
            assert "Radarr Disk Space" == device.name
            assert "263.10/465.42GB (56.53%)" == device.device_state_attributes["/data"]

    @patch("requests.get", side_effect=mocked_requests_get)
    def test_diskspace_paths(self, req_mock):
        """Test getting diskspace for included paths."""
        config = {
            "platform": "radarr",
            "api_key": "foo",
            "days": "2",
            "unit": DATA_GIGABYTES,
            "include_paths": ["/data"],
            "monitored_conditions": ["diskspace"],
        }
        radarr.setup_platform(self.hass, config, self.add_entities, None)
        for device in self.DEVICES:
            device.update()
            assert "263.10" == device.state
            assert "mdi:harddisk" == device.icon
            assert DATA_GIGABYTES == device.unit_of_measurement
            assert "Radarr Disk Space" == device.name
            assert "263.10/465.42GB (56.53%)" == device.device_state_attributes["/data"]

    @patch("requests.get", side_effect=mocked_requests_get)
    def test_commands(self, req_mock):
        """Test getting running commands."""
        config = {
            "platform": "radarr",
            "api_key": "foo",
            "days": "2",
            "unit": DATA_GIGABYTES,
            "include_paths": ["/data"],
            "monitored_conditions": ["commands"],
        }
        radarr.setup_platform(self.hass, config, self.add_entities, None)
        for device in self.DEVICES:
            device.update()
            assert 1 == device.state
            assert "mdi:code-braces" == device.icon
            assert "Commands" == device.unit_of_measurement
            assert "Radarr Commands" == device.name
            assert "pending" == device.device_state_attributes["RescanMovie"]

    @patch("requests.get", side_effect=mocked_requests_get)
    def test_movies(self, req_mock):
        """Test getting the number of movies."""
        config = {
            "platform": "radarr",
            "api_key": "foo",
            "days": "2",
            "unit": DATA_GIGABYTES,
            "include_paths": ["/data"],
            "monitored_conditions": ["movies"],
        }
        radarr.setup_platform(self.hass, config, self.add_entities, None)
        for device in self.DEVICES:
            device.update()
            assert 1 == device.state
            assert "mdi:television" == device.icon
            assert "Movies" == device.unit_of_measurement
            assert "Radarr Movies" == device.name
            assert "false" == device.device_state_attributes["Assassin's Creed (2016)"]

    @patch("requests.get", side_effect=mocked_requests_get)
    def test_upcoming_multiple_days(self, req_mock):
        """Test the upcoming movies for multiple days."""
        config = {
            "platform": "radarr",
            "api_key": "foo",
            "days": "2",
            "unit": DATA_GIGABYTES,
            "include_paths": ["/data"],
            "monitored_conditions": ["upcoming"],
        }
        radarr.setup_platform(self.hass, config, self.add_entities, None)
        for device in self.DEVICES:
            device.update()
            assert 1 == device.state
            assert "mdi:television" == device.icon
            assert "Movies" == device.unit_of_measurement
            assert "Radarr Upcoming" == device.name
            assert (
                "2017-01-27T00:00:00Z"
                == device.device_state_attributes["Resident Evil (2017)"]
            )

    @pytest.mark.skip
    @patch("requests.get", side_effect=mocked_requests_get)
    def test_upcoming_today(self, req_mock):
        """Test filtering for a single day.

        Radarr needs to respond with at least 2 days.
        """
        config = {
            "platform": "radarr",
            "api_key": "foo",
            "days": "1",
            "unit": DATA_GIGABYTES,
            "include_paths": ["/data"],
            "monitored_conditions": ["upcoming"],
        }
        radarr.setup_platform(self.hass, config, self.add_entities, None)
        for device in self.DEVICES:
            device.update()
            assert 1 == device.state
            assert "mdi:television" == device.icon
            assert "Movies" == device.unit_of_measurement
            assert "Radarr Upcoming" == device.name
            assert (
                "2017-01-27T00:00:00Z"
                == device.device_state_attributes["Resident Evil (2017)"]
            )

    @patch("requests.get", side_effect=mocked_requests_get)
    def test_system_status(self, req_mock):
        """Test the getting of the system status."""
        config = {
            "platform": "radarr",
            "api_key": "foo",
            "days": "2",
            "unit": DATA_GIGABYTES,
            "include_paths": ["/data"],
            "monitored_conditions": ["status"],
        }
        radarr.setup_platform(self.hass, config, self.add_entities, None)
        for device in self.DEVICES:
            device.update()
            assert "0.2.0.210" == device.state
            assert "mdi:information" == device.icon
            assert "Radarr Status" == device.name
            assert "4.8.13.1" == device.device_state_attributes["osVersion"]

    @pytest.mark.skip
    @patch("requests.get", side_effect=mocked_requests_get)
    def test_ssl(self, req_mock):
        """Test SSL being enabled."""
        config = {
            "platform": "radarr",
            "api_key": "foo",
            "days": "1",
            "unit": DATA_GIGABYTES,
            "include_paths": ["/data"],
            "monitored_conditions": ["upcoming"],
            "ssl": "true",
        }
        radarr.setup_platform(self.hass, config, self.add_entities, None)
        for device in self.DEVICES:
            device.update()
            assert 1 == device.state
            assert "s" == device.ssl
            assert "mdi:television" == device.icon
            assert "Movies" == device.unit_of_measurement
            assert "Radarr Upcoming" == device.name
            assert (
                "2017-01-27T00:00:00Z"
                == device.device_state_attributes["Resident Evil (2017)"]
            )

    @patch("requests.get", side_effect=mocked_exception)
    def test_exception_handling(self, req_mock):
        """Test exception being handled."""
        config = {
            "platform": "radarr",
            "api_key": "foo",
            "days": "1",
            "unit": DATA_GIGABYTES,
            "include_paths": ["/data"],
            "monitored_conditions": ["upcoming"],
        }
        radarr.setup_platform(self.hass, config, self.add_entities, None)
        for device in self.DEVICES:
            device.update()
            assert device.state is None
