"""Test check_config helper."""
import logging
from unittest.mock import Mock, patch

from homeassistant.config import YAML_CONFIG_FILE
from homeassistant.helpers.check_config import (
    CheckConfigError,
    async_check_ha_config_file,
)
from homeassistant.requirements import RequirementsNotFound

from tests.common import mock_platform, patch_yaml_files

_LOGGER = logging.getLogger(__name__)

BASE_CONFIG = (
    "homeassistant:\n"
    "  name: Home\n"
    "  latitude: -26.107361\n"
    "  longitude: 28.054500\n"
    "  elevation: 1600\n"
    "  unit_system: metric\n"
    "  time_zone: GMT\n"
    "\n\n"
)

BAD_CORE_CONFIG = "homeassistant:\n  unit_system: bad\n\n\n"


def log_ha_config(conf):
    """Log the returned config."""
    cnt = 0
    _LOGGER.debug("CONFIG - %s lines - %s errors", len(conf), len(conf.errors))
    for key, val in conf.items():
        _LOGGER.debug("#%s - %s: %s", cnt, key, val)
        cnt += 1
    for cnt, err in enumerate(conf.errors):
        _LOGGER.debug("error[%s] = %s", cnt, err)


async def test_bad_core_config(hass):
    """Test a bad core config setup."""
    files = {YAML_CONFIG_FILE: BAD_CORE_CONFIG}
    with patch("os.path.isfile", return_value=True), patch_yaml_files(files):
        res = await async_check_ha_config_file(hass)
        log_ha_config(res)

        assert isinstance(res.errors[0].message, str)
        assert res.errors[0].domain == "homeassistant"
        assert res.errors[0].config == {"unit_system": "bad"}

        # Only 1 error expected
        res.errors.pop(0)
        assert not res.errors


async def test_config_platform_valid(hass):
    """Test a valid platform setup."""
    files = {YAML_CONFIG_FILE: BASE_CONFIG + "light:\n  platform: demo"}
    with patch("os.path.isfile", return_value=True), patch_yaml_files(files):
        res = await async_check_ha_config_file(hass)
        log_ha_config(res)

        assert res.keys() == {"homeassistant", "light"}
        assert res["light"] == [{"platform": "demo"}]
        assert not res.errors


async def test_component_platform_not_found(hass):
    """Test errors if component or platform not found."""
    # Make sure they don't exist
    files = {YAML_CONFIG_FILE: BASE_CONFIG + "beer:"}
    with patch("os.path.isfile", return_value=True), patch_yaml_files(files):
        res = await async_check_ha_config_file(hass)
        log_ha_config(res)

        assert res.keys() == {"homeassistant"}
        assert res.errors[0] == CheckConfigError(
            "Integration error: beer - Integration 'beer' not found.", None, None
        )

        # Only 1 error expected
        res.errors.pop(0)
        assert not res.errors


async def test_component_requirement_not_found(hass):
    """Test errors if component with a requirement not found not found."""
    # Make sure they don't exist
    files = {YAML_CONFIG_FILE: BASE_CONFIG + "test_custom_component:"}
    with patch(
        "homeassistant.helpers.check_config.async_get_integration_with_requirements",
        side_effect=RequirementsNotFound("test_custom_component", ["any"]),
    ), patch("os.path.isfile", return_value=True), patch_yaml_files(files):
        res = await async_check_ha_config_file(hass)
        log_ha_config(res)

        assert res.keys() == {"homeassistant"}
        assert res.errors[0] == CheckConfigError(
            "Integration error: test_custom_component - Requirements for test_custom_component not found: ['any'].",
            None,
            None,
        )

        # Only 1 error expected
        res.errors.pop(0)
        assert not res.errors


async def test_component_not_found_safe_mode(hass):
    """Test no errors if component not found in safe mode."""
    # Make sure they don't exist
    files = {YAML_CONFIG_FILE: BASE_CONFIG + "beer:"}
    hass.config.safe_mode = True
    with patch("os.path.isfile", return_value=True), patch_yaml_files(files):
        res = await async_check_ha_config_file(hass)
        log_ha_config(res)

        assert res.keys() == {"homeassistant"}
        assert not res.errors


async def test_component_platform_not_found_2(hass):
    """Test errors if component or platform not found."""
    # Make sure they don't exist
    files = {YAML_CONFIG_FILE: BASE_CONFIG + "light:\n  platform: beer"}
    with patch("os.path.isfile", return_value=True), patch_yaml_files(files):
        res = await async_check_ha_config_file(hass)
        log_ha_config(res)

        assert res.keys() == {"homeassistant", "light"}
        assert res["light"] == []

        assert res.errors[0] == CheckConfigError(
            "Platform error light.beer - Integration 'beer' not found.", None, None
        )

        # Only 1 error expected
        res.errors.pop(0)
        assert not res.errors


async def test_platform_not_found_safe_mode(hass):
    """Test no errors if platform not found in safe_mode."""
    # Make sure they don't exist
    files = {YAML_CONFIG_FILE: BASE_CONFIG + "light:\n  platform: beer"}
    hass.config.safe_mode = True
    with patch("os.path.isfile", return_value=True), patch_yaml_files(files):
        res = await async_check_ha_config_file(hass)
        log_ha_config(res)

        assert res.keys() == {"homeassistant", "light"}
        assert res["light"] == []

        assert not res.errors


async def test_package_invalid(hass):
    """Test a valid platform setup."""
    files = {
        YAML_CONFIG_FILE: BASE_CONFIG + ("  packages:\n    p1:\n" '      group: ["a"]')
    }
    with patch("os.path.isfile", return_value=True), patch_yaml_files(files):
        res = await async_check_ha_config_file(hass)
        log_ha_config(res)

        assert res.errors[0].domain == "homeassistant.packages.p1.group"
        assert res.errors[0].config == {"group": ["a"]}
        # Only 1 error expected
        res.errors.pop(0)
        assert not res.errors

        assert res.keys() == {"homeassistant"}


async def test_bootstrap_error(hass):
    """Test a valid platform setup."""
    files = {YAML_CONFIG_FILE: BASE_CONFIG + "automation: !include no.yaml"}
    with patch("os.path.isfile", return_value=True), patch_yaml_files(files):
        res = await async_check_ha_config_file(hass)
        log_ha_config(res)

        assert res.errors[0].domain is None

        # Only 1 error expected
        res.errors.pop(0)
        assert not res.errors


async def test_automation_config_platform(hass):
    """Test automation async config."""
    files = {
        YAML_CONFIG_FILE: BASE_CONFIG
        + """
automation:
  use_blueprint:
    path: test_event_service.yaml
    input:
      trigger_event: blueprint_event
      service_to_call: test.automation
input_datetime:
""",
        hass.config.path(
            "blueprints/automation/test_event_service.yaml"
        ): """
blueprint:
  name: "Call service based on event"
  domain: automation
  input:
    trigger_event:
    service_to_call:
trigger:
  platform: event
  event_type: !input trigger_event
action:
  service: !input service_to_call
""",
    }
    with patch("os.path.isfile", return_value=True), patch_yaml_files(files):
        res = await async_check_ha_config_file(hass)
        assert len(res.get("automation", [])) == 1
        assert len(res.errors) == 0
        assert "input_datetime" in res


async def test_config_platform_raise(hass):
    """Test bad config validation platform."""
    mock_platform(
        hass,
        "bla.config",
        Mock(async_validate_config=Mock(side_effect=Exception("Broken"))),
    )
    files = {
        YAML_CONFIG_FILE: BASE_CONFIG
        + """
bla:
  value: 1
""",
    }
    with patch("os.path.isfile", return_value=True), patch_yaml_files(files):
        res = await async_check_ha_config_file(hass)
        assert len(res.errors) == 1
        err = res.errors[0]
        assert err.domain == "bla"
        assert err.message == "Unexpected error calling config validator: Broken"
        assert err.config == {"value": 1}