"""The tests for the Yahoo weather sensor component."""
import json

import unittest
from unittest.mock import patch

from homeassistant.setup import setup_component

from tests.common import get_test_home_assistant, load_fixture, MockDependency

VALID_CONFIG_MINIMAL = {
    "sensor": {"platform": "yweather", "monitored_conditions": ["weather"]}
}

VALID_CONFIG_ALL = {
    "sensor": {
        "platform": "yweather",
        "monitored_conditions": [
            "weather",
            "weather_current",
            "temperature",
            "temp_min",
            "temp_max",
            "wind_speed",
            "pressure",
            "visibility",
            "humidity",
        ],
    }
}

BAD_CONF_RAW = {
    "sensor": {
        "platform": "yweather",
        "woeid": "12345",
        "monitored_conditions": ["weather"],
    }
}

BAD_CONF_DATA = {
    "sensor": {
        "platform": "yweather",
        "woeid": "111",
        "monitored_conditions": ["weather"],
    }
}


def _yql_queryMock(yql):  # pylint: disable=invalid-name
    """Mock yahoo query language query."""
    return (
        '{"query": {"count": 1, "created": "2017-11-17T13:40:47Z", '
        '"lang": "en-US", "results": {"place": {"woeid": "23511632"}}}}'
    )


def get_woeidMock(lat, lon):  # pylint: disable=invalid-name
    """Mock get woeid Where On Earth Identifiers."""
    return "23511632"


def get_woeidNoneMock(lat, lon):  # pylint: disable=invalid-name
    """Mock get woeid Where On Earth Identifiers."""
    return None


class YahooWeatherMock:
    """Mock class for the YahooWeather object."""

    def __init__(self, woeid, temp_unit):
        """Initialize Telnet object."""
        self.woeid = woeid
        self.temp_unit = temp_unit
        self._data = json.loads(load_fixture("yahooweather.json"))

    # pylint: disable=no-self-use
    def updateWeather(self):  # pylint: disable=invalid-name
        """Return sample values."""
        return True

    @property
    def RawData(self):  # pylint: disable=invalid-name
        """Raw Data."""
        if self.woeid == "12345":
            return json.loads("[]")
        return self._data

    @property
    def Units(self):  # pylint: disable=invalid-name
        """Return dict with units."""
        return self._data["query"]["results"]["channel"]["units"]

    @property
    def Now(self):  # pylint: disable=invalid-name
        """Return current weather data."""
        if self.woeid == "111":
            raise ValueError
        return self._data["query"]["results"]["channel"]["item"]["condition"]

    @property
    def Atmosphere(self):  # pylint: disable=invalid-name
        """Atmosphere weather data."""
        return self._data["query"]["results"]["channel"]["atmosphere"]

    @property
    def Wind(self):  # pylint: disable=invalid-name
        """Wind weather data."""
        return self._data["query"]["results"]["channel"]["wind"]

    @property
    def Forecast(self):  # pylint: disable=invalid-name
        """Forecast data 0-5 Days."""
        return self._data["query"]["results"]["channel"]["item"]["forecast"]

    def getWeatherImage(self, code):  # pylint: disable=invalid-name
        """Create a link to weather image from yahoo code."""
        return "https://l.yimg.com/a/i/us/we/52/{}.gif".format(code)


class TestWeather(unittest.TestCase):
    """Test the Yahoo weather component."""

    def setUp(self):
        """Set up things to be run when tests are started."""
        self.hass = get_test_home_assistant()

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

    @MockDependency("yahooweather")
    @patch("yahooweather._yql_query", new=_yql_queryMock)
    @patch("yahooweather.get_woeid", new=get_woeidMock)
    @patch("yahooweather.YahooWeather", new=YahooWeatherMock)
    def test_setup_minimal(self, mock_yahooweather):
        """Test for minimal weather sensor config."""
        assert setup_component(self.hass, "sensor", VALID_CONFIG_MINIMAL)

        state = self.hass.states.get("sensor.yweather_condition")
        assert state is not None

        assert state.state == "Mostly Cloudy"
        assert state.attributes.get("friendly_name") == "Yweather Condition"

    @MockDependency("yahooweather")
    @patch("yahooweather._yql_query", new=_yql_queryMock)
    @patch("yahooweather.get_woeid", new=get_woeidMock)
    @patch("yahooweather.YahooWeather", new=YahooWeatherMock)
    def test_setup_all(self, mock_yahooweather):
        """Test for all weather data attributes."""
        assert setup_component(self.hass, "sensor", VALID_CONFIG_ALL)

        state = self.hass.states.get("sensor.yweather_condition")
        assert state is not None
        assert state.state == "Mostly Cloudy"
        assert state.attributes.get("condition_code") == "28"
        assert state.attributes.get("friendly_name") == "Yweather Condition"

        state = self.hass.states.get("sensor.yweather_current")
        assert state is not None
        assert state.state == "Cloudy"
        assert state.attributes.get("friendly_name") == "Yweather Current"

        state = self.hass.states.get("sensor.yweather_temperature")
        assert state is not None
        assert state.state == "18"
        assert state.attributes.get("friendly_name") == "Yweather Temperature"

        state = self.hass.states.get("sensor.yweather_temperature_max")
        assert state is not None
        assert state.state == "23"
        assert state.attributes.get("friendly_name") == "Yweather Temperature max"

        state = self.hass.states.get("sensor.yweather_temperature_min")
        assert state is not None
        assert state.state == "16"
        assert state.attributes.get("friendly_name") == "Yweather Temperature min"

        state = self.hass.states.get("sensor.yweather_wind_speed")
        assert state is not None
        assert state.state == "3.94"
        assert state.attributes.get("friendly_name") == "Yweather Wind speed"

        state = self.hass.states.get("sensor.yweather_pressure")
        assert state is not None
        assert state.state == "1000.0"
        assert state.attributes.get("friendly_name") == "Yweather Pressure"

        state = self.hass.states.get("sensor.yweather_visibility")
        assert state is not None
        assert state.state == "14.23"
        assert state.attributes.get("friendly_name") == "Yweather Visibility"

        state = self.hass.states.get("sensor.yweather_humidity")
        assert state is not None
        assert state.state == "71"
        assert state.attributes.get("friendly_name") == "Yweather Humidity"

    @MockDependency("yahooweather")
    @patch("yahooweather._yql_query", new=_yql_queryMock)
    @patch("yahooweather.get_woeid", new=get_woeidNoneMock)
    @patch("yahooweather.YahooWeather", new=YahooWeatherMock)
    def test_setup_bad_woied(self, mock_yahooweather):
        """Test for bad woeid."""
        assert setup_component(self.hass, "sensor", VALID_CONFIG_MINIMAL)

        state = self.hass.states.get("sensor.yweather_condition")
        assert state is None

    @MockDependency("yahooweather")
    @patch("yahooweather._yql_query", new=_yql_queryMock)
    @patch("yahooweather.get_woeid", new=get_woeidMock)
    @patch("yahooweather.YahooWeather", new=YahooWeatherMock)
    def test_setup_bad_raw(self, mock_yahooweather):
        """Test for bad RawData."""
        assert setup_component(self.hass, "sensor", BAD_CONF_RAW)

        state = self.hass.states.get("sensor.yweather_condition")
        assert state is not None

    @MockDependency("yahooweather")
    @patch("yahooweather._yql_query", new=_yql_queryMock)
    @patch("yahooweather.get_woeid", new=get_woeidMock)
    @patch("yahooweather.YahooWeather", new=YahooWeatherMock)
    def test_setup_bad_data(self, mock_yahooweather):
        """Test for bad data."""
        assert setup_component(self.hass, "sensor", BAD_CONF_DATA)

        state = self.hass.states.get("sensor.yweather_condition")
        assert state is None
