"""Test creating repairs from alerts."""
from __future__ import annotations

from datetime import timedelta
import json
from unittest.mock import ANY, patch

import pytest

from homeassistant.components.homeassistant_alerts import DOMAIN, UPDATE_INTERVAL
from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component
from homeassistant.util import dt as dt_util

from tests.common import assert_lists_same, async_fire_time_changed, load_fixture
from tests.test_util.aiohttp import AiohttpClientMocker


def stub_alert(aioclient_mock, filename):
    """Stub an alert."""
    aioclient_mock.get(
        f"https://alerts.home-assistant.io/alerts/{filename}",
        text=f"""---
title: Title for {filename}
---
Content for {filename}
""",
    )


@pytest.mark.parametrize(
    "ha_version, expected_alerts",
    (
        (
            "2022.7.0",
            [
                ("aladdin_connect.markdown", "aladdin_connect"),
                ("dark_sky.markdown", "darksky"),
                ("hikvision.markdown", "hikvision"),
                ("hikvision.markdown", "hikvisioncam"),
                ("hive_us.markdown", "hive"),
                ("homematicip_cloud.markdown", "homematicip_cloud"),
                ("logi_circle.markdown", "logi_circle"),
                ("neato.markdown", "neato"),
                ("nest.markdown", "nest"),
                ("senseme.markdown", "senseme"),
                ("sochain.markdown", "sochain"),
            ],
        ),
        (
            "2022.8.0",
            [
                ("dark_sky.markdown", "darksky"),
                ("hikvision.markdown", "hikvision"),
                ("hikvision.markdown", "hikvisioncam"),
                ("hive_us.markdown", "hive"),
                ("homematicip_cloud.markdown", "homematicip_cloud"),
                ("logi_circle.markdown", "logi_circle"),
                ("neato.markdown", "neato"),
                ("nest.markdown", "nest"),
                ("senseme.markdown", "senseme"),
                ("sochain.markdown", "sochain"),
            ],
        ),
        (
            "2021.10.0",
            [
                ("aladdin_connect.markdown", "aladdin_connect"),
                ("dark_sky.markdown", "darksky"),
                ("hikvision.markdown", "hikvision"),
                ("hikvision.markdown", "hikvisioncam"),
                ("homematicip_cloud.markdown", "homematicip_cloud"),
                ("logi_circle.markdown", "logi_circle"),
                ("neato.markdown", "neato"),
                ("nest.markdown", "nest"),
                ("senseme.markdown", "senseme"),
                ("sochain.markdown", "sochain"),
            ],
        ),
    ),
)
async def test_alerts(
    hass: HomeAssistant,
    hass_ws_client,
    aioclient_mock: AiohttpClientMocker,
    ha_version,
    expected_alerts,
) -> None:
    """Test creating issues based on alerts."""

    aioclient_mock.clear_requests()
    aioclient_mock.get(
        "https://alerts.home-assistant.io/alerts.json",
        text=load_fixture("alerts_1.json", "homeassistant_alerts"),
    )
    for alert in expected_alerts:
        stub_alert(aioclient_mock, alert[0])

    activated_components = (
        "aladdin_connect",
        "darksky",
        "hikvision",
        "hikvisioncam",
        "hive",
        "homematicip_cloud",
        "logi_circle",
        "neato",
        "nest",
        "senseme",
        "sochain",
    )
    for domain in activated_components:
        hass.config.components.add(domain)

    with patch(
        "homeassistant.components.homeassistant_alerts.__version__",
        ha_version,
    ):
        assert await async_setup_component(hass, DOMAIN, {})

    client = await hass_ws_client(hass)

    await client.send_json({"id": 1, "type": "repairs/list_issues"})
    msg = await client.receive_json()
    assert msg["success"]
    assert msg["result"] == {
        "issues": [
            {
                "breaks_in_ha_version": None,
                "created": ANY,
                "dismissed_version": None,
                "domain": "homeassistant_alerts",
                "ignored": False,
                "is_fixable": False,
                "issue_id": f"{alert}_{integration}",
                "learn_more_url": None,
                "severity": "warning",
                "translation_key": "alert",
                "translation_placeholders": {
                    "title": f"Title for {alert}",
                    "description": f"Content for {alert}",
                },
            }
            for alert, integration in expected_alerts
        ]
    }


@pytest.mark.parametrize(
    "ha_version, fixture, expected_alerts",
    (
        (
            "2022.7.0",
            "alerts_no_integrations.json",
            [
                ("dark_sky.markdown", "darksky"),
            ],
        ),
        (
            "2022.7.0",
            "alerts_no_package.json",
            [
                ("dark_sky.markdown", "darksky"),
                ("hikvision.markdown", "hikvision"),
            ],
        ),
    ),
)
async def test_bad_alerts(
    hass: HomeAssistant,
    hass_ws_client,
    aioclient_mock: AiohttpClientMocker,
    ha_version,
    fixture,
    expected_alerts,
) -> None:
    """Test creating issues based on alerts."""
    fixture_content = load_fixture(fixture, "homeassistant_alerts")
    aioclient_mock.clear_requests()
    aioclient_mock.get(
        "https://alerts.home-assistant.io/alerts.json",
        text=fixture_content,
    )
    for alert in json.loads(fixture_content):
        stub_alert(aioclient_mock, alert["filename"])

    activated_components = (
        "darksky",
        "hikvision",
        "hikvisioncam",
    )
    for domain in activated_components:
        hass.config.components.add(domain)

    with patch(
        "homeassistant.components.homeassistant_alerts.__version__",
        ha_version,
    ):
        assert await async_setup_component(hass, DOMAIN, {})

    client = await hass_ws_client(hass)

    await client.send_json({"id": 1, "type": "repairs/list_issues"})
    msg = await client.receive_json()
    assert msg["success"]
    assert msg["result"] == {
        "issues": [
            {
                "breaks_in_ha_version": None,
                "created": ANY,
                "dismissed_version": None,
                "domain": "homeassistant_alerts",
                "ignored": False,
                "is_fixable": False,
                "issue_id": f"{alert}_{integration}",
                "learn_more_url": None,
                "severity": "warning",
                "translation_key": "alert",
                "translation_placeholders": {
                    "title": f"Title for {alert}",
                    "description": f"Content for {alert}",
                },
            }
            for alert, integration in expected_alerts
        ]
    }


async def test_no_alerts(
    hass: HomeAssistant,
    hass_ws_client,
    aioclient_mock: AiohttpClientMocker,
) -> None:
    """Test creating issues based on alerts."""

    aioclient_mock.clear_requests()
    aioclient_mock.get(
        "https://alerts.home-assistant.io/alerts.json",
        text="",
    )

    assert await async_setup_component(hass, DOMAIN, {})

    client = await hass_ws_client(hass)

    await client.send_json({"id": 1, "type": "repairs/list_issues"})
    msg = await client.receive_json()
    assert msg["success"]
    assert msg["result"] == {"issues": []}


@pytest.mark.parametrize(
    "ha_version, fixture_1, expected_alerts_1, fixture_2, expected_alerts_2",
    (
        (
            "2022.7.0",
            "alerts_1.json",
            [
                ("aladdin_connect.markdown", "aladdin_connect"),
                ("dark_sky.markdown", "darksky"),
                ("hikvision.markdown", "hikvision"),
                ("hikvision.markdown", "hikvisioncam"),
                ("hive_us.markdown", "hive"),
                ("homematicip_cloud.markdown", "homematicip_cloud"),
                ("logi_circle.markdown", "logi_circle"),
                ("neato.markdown", "neato"),
                ("nest.markdown", "nest"),
                ("senseme.markdown", "senseme"),
                ("sochain.markdown", "sochain"),
            ],
            "alerts_2.json",
            [
                ("dark_sky.markdown", "darksky"),
                ("hikvision.markdown", "hikvision"),
                ("hikvision.markdown", "hikvisioncam"),
                ("hive_us.markdown", "hive"),
                ("homematicip_cloud.markdown", "homematicip_cloud"),
                ("logi_circle.markdown", "logi_circle"),
                ("neato.markdown", "neato"),
                ("nest.markdown", "nest"),
                ("senseme.markdown", "senseme"),
                ("sochain.markdown", "sochain"),
            ],
        ),
        (
            "2022.7.0",
            "alerts_2.json",
            [
                ("dark_sky.markdown", "darksky"),
                ("hikvision.markdown", "hikvision"),
                ("hikvision.markdown", "hikvisioncam"),
                ("hive_us.markdown", "hive"),
                ("homematicip_cloud.markdown", "homematicip_cloud"),
                ("logi_circle.markdown", "logi_circle"),
                ("neato.markdown", "neato"),
                ("nest.markdown", "nest"),
                ("senseme.markdown", "senseme"),
                ("sochain.markdown", "sochain"),
            ],
            "alerts_1.json",
            [
                ("aladdin_connect.markdown", "aladdin_connect"),
                ("dark_sky.markdown", "darksky"),
                ("hikvision.markdown", "hikvision"),
                ("hikvision.markdown", "hikvisioncam"),
                ("hive_us.markdown", "hive"),
                ("homematicip_cloud.markdown", "homematicip_cloud"),
                ("logi_circle.markdown", "logi_circle"),
                ("neato.markdown", "neato"),
                ("nest.markdown", "nest"),
                ("senseme.markdown", "senseme"),
                ("sochain.markdown", "sochain"),
            ],
        ),
    ),
)
async def test_alerts_change(
    hass: HomeAssistant,
    hass_ws_client,
    aioclient_mock: AiohttpClientMocker,
    ha_version: str,
    fixture_1: str,
    expected_alerts_1: list[tuple(str, str)],
    fixture_2: str,
    expected_alerts_2: list[tuple(str, str)],
) -> None:
    """Test creating issues based on alerts."""
    fixture_1_content = load_fixture(fixture_1, "homeassistant_alerts")
    aioclient_mock.clear_requests()
    aioclient_mock.get(
        "https://alerts.home-assistant.io/alerts.json",
        text=fixture_1_content,
    )
    for alert in json.loads(fixture_1_content):
        stub_alert(aioclient_mock, alert["filename"])

    activated_components = (
        "aladdin_connect",
        "darksky",
        "hikvision",
        "hikvisioncam",
        "hive",
        "homematicip_cloud",
        "logi_circle",
        "neato",
        "nest",
        "senseme",
        "sochain",
    )
    for domain in activated_components:
        hass.config.components.add(domain)

    with patch(
        "homeassistant.components.homeassistant_alerts.__version__",
        ha_version,
    ):
        assert await async_setup_component(hass, DOMAIN, {})

    now = dt_util.utcnow()

    client = await hass_ws_client(hass)

    await client.send_json({"id": 1, "type": "repairs/list_issues"})
    msg = await client.receive_json()
    assert msg["success"]
    assert_lists_same(
        msg["result"]["issues"],
        [
            {
                "breaks_in_ha_version": None,
                "created": ANY,
                "dismissed_version": None,
                "domain": "homeassistant_alerts",
                "ignored": False,
                "is_fixable": False,
                "issue_id": f"{alert}_{integration}",
                "learn_more_url": None,
                "severity": "warning",
                "translation_key": "alert",
                "translation_placeholders": {
                    "title": f"Title for {alert}",
                    "description": f"Content for {alert}",
                },
            }
            for alert, integration in expected_alerts_1
        ],
    )

    fixture_2_content = load_fixture(fixture_2, "homeassistant_alerts")
    aioclient_mock.clear_requests()
    aioclient_mock.get(
        "https://alerts.home-assistant.io/alerts.json",
        text=fixture_2_content,
    )
    for alert in json.loads(fixture_2_content):
        stub_alert(aioclient_mock, alert["filename"])

    future = now + UPDATE_INTERVAL + timedelta(seconds=1)
    async_fire_time_changed(hass, future)
    await hass.async_block_till_done()

    await client.send_json({"id": 2, "type": "repairs/list_issues"})
    msg = await client.receive_json()
    assert msg["success"]
    assert_lists_same(
        msg["result"]["issues"],
        [
            {
                "breaks_in_ha_version": None,
                "created": ANY,
                "dismissed_version": None,
                "domain": "homeassistant_alerts",
                "ignored": False,
                "is_fixable": False,
                "issue_id": f"{alert}_{integration}",
                "learn_more_url": None,
                "severity": "warning",
                "translation_key": "alert",
                "translation_placeholders": {
                    "title": f"Title for {alert}",
                    "description": f"Content for {alert}",
                },
            }
            for alert, integration in expected_alerts_2
        ],
    )