"""Test the Nina config flow."""
from __future__ import annotations

from copy import deepcopy
import json
from typing import Any
from unittest.mock import patch

from pynina import ApiError

from homeassistant import data_entry_flow
from homeassistant.components.nina.const import (
    CONF_FILTER_CORONA,
    CONF_MESSAGE_SLOTS,
    CONF_REGIONS,
    CONST_REGION_A_TO_D,
    CONST_REGION_E_TO_H,
    CONST_REGION_I_TO_L,
    CONST_REGION_M_TO_Q,
    CONST_REGION_R_TO_U,
    CONST_REGION_V_TO_Z,
    DOMAIN,
)
from homeassistant.config_entries import SOURCE_USER
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er

from . import mocked_request_function

from tests.common import MockConfigEntry, load_fixture

DUMMY_DATA: dict[str, Any] = {
    CONF_MESSAGE_SLOTS: 5,
    CONST_REGION_A_TO_D: ["095760000000_0", "095760000000_1"],
    CONST_REGION_E_TO_H: ["010610000000_0", "010610000000_1"],
    CONST_REGION_I_TO_L: ["071320000000_0", "071320000000_1"],
    CONST_REGION_M_TO_Q: ["071380000000_0", "071380000000_1"],
    CONST_REGION_R_TO_U: ["072320000000_0", "072320000000_1"],
    CONST_REGION_V_TO_Z: ["081270000000_0", "081270000000_1"],
    CONF_FILTER_CORONA: True,
}

DUMMY_RESPONSE_REGIONS: dict[str, Any] = json.loads(
    load_fixture("sample_regions.json", "nina")
)
DUMMY_RESPONSE_WARNIGNS: dict[str, Any] = json.loads(
    load_fixture("sample_warnings.json", "nina")
)


async def test_show_set_form(hass: HomeAssistant) -> None:
    """Test that the setup form is served."""
    with patch(
        "pynina.baseApi.BaseAPI._makeRequest",
        wraps=mocked_request_function,
    ):

        result: dict[str, Any] = await hass.config_entries.flow.async_init(
            DOMAIN, context={"source": SOURCE_USER}
        )

        assert result["type"] == data_entry_flow.FlowResultType.FORM
        assert result["step_id"] == "user"


async def test_step_user_connection_error(hass: HomeAssistant) -> None:
    """Test starting a flow by user but no connection."""
    with patch(
        "pynina.baseApi.BaseAPI._makeRequest",
        side_effect=ApiError("Could not connect to Api"),
    ):

        result: dict[str, Any] = await hass.config_entries.flow.async_init(
            DOMAIN, context={"source": SOURCE_USER}, data=deepcopy(DUMMY_DATA)
        )

        assert result["type"] == data_entry_flow.FlowResultType.FORM
        assert result["errors"] == {"base": "cannot_connect"}


async def test_step_user_unexpected_exception(hass: HomeAssistant) -> None:
    """Test starting a flow by user but with an unexpected exception."""
    with patch(
        "pynina.baseApi.BaseAPI._makeRequest",
        side_effect=Exception("DUMMY"),
    ):

        result: dict[str, Any] = await hass.config_entries.flow.async_init(
            DOMAIN, context={"source": SOURCE_USER}, data=deepcopy(DUMMY_DATA)
        )

        assert result["type"] == data_entry_flow.FlowResultType.ABORT


async def test_step_user(hass: HomeAssistant) -> None:
    """Test starting a flow by user with valid values."""
    with patch(
        "pynina.baseApi.BaseAPI._makeRequest",
        wraps=mocked_request_function,
    ), patch(
        "homeassistant.components.nina.async_setup_entry",
        return_value=True,
    ):

        result: dict[str, Any] = await hass.config_entries.flow.async_init(
            DOMAIN, context={"source": SOURCE_USER}, data=deepcopy(DUMMY_DATA)
        )

        assert result["type"] == data_entry_flow.FlowResultType.CREATE_ENTRY
        assert result["title"] == "NINA"


async def test_step_user_no_selection(hass: HomeAssistant) -> None:
    """Test starting a flow by user with no selection."""
    with patch(
        "pynina.baseApi.BaseAPI._makeRequest",
        wraps=mocked_request_function,
    ):

        result: dict[str, Any] = await hass.config_entries.flow.async_init(
            DOMAIN, context={"source": SOURCE_USER}, data={}
        )

        assert result["type"] == data_entry_flow.FlowResultType.FORM
        assert result["step_id"] == "user"
        assert result["errors"] == {"base": "no_selection"}


async def test_step_user_already_configured(hass: HomeAssistant) -> None:
    """Test starting a flow by user but it was already configured."""
    with patch(
        "pynina.baseApi.BaseAPI._makeRequest",
        wraps=mocked_request_function,
    ):
        result: dict[str, Any] = await hass.config_entries.flow.async_init(
            DOMAIN, context={"source": SOURCE_USER}, data=deepcopy(DUMMY_DATA)
        )

        result = await hass.config_entries.flow.async_init(
            DOMAIN, context={"source": SOURCE_USER}, data=deepcopy(DUMMY_DATA)
        )

        assert result["type"] == data_entry_flow.FlowResultType.ABORT
        assert result["reason"] == "single_instance_allowed"


async def test_options_flow_init(hass: HomeAssistant) -> None:
    """Test config flow options."""
    config_entry = MockConfigEntry(
        domain=DOMAIN,
        title="NINA",
        data={
            CONF_FILTER_CORONA: deepcopy(DUMMY_DATA[CONF_FILTER_CORONA]),
            CONF_MESSAGE_SLOTS: deepcopy(DUMMY_DATA[CONF_MESSAGE_SLOTS]),
            CONST_REGION_A_TO_D: deepcopy(DUMMY_DATA[CONST_REGION_A_TO_D]),
            CONF_REGIONS: {"095760000000": "Aach"},
        },
    )
    config_entry.add_to_hass(hass)

    with patch(
        "homeassistant.components.nina.async_setup_entry", return_value=True
    ), patch(
        "pynina.baseApi.BaseAPI._makeRequest",
        wraps=mocked_request_function,
    ):
        await hass.config_entries.async_setup(config_entry.entry_id)
        await hass.async_block_till_done()

        result = await hass.config_entries.options.async_init(config_entry.entry_id)

        assert result["type"] == data_entry_flow.FlowResultType.FORM
        assert result["step_id"] == "init"

        result = await hass.config_entries.options.async_configure(
            result["flow_id"],
            user_input={
                CONST_REGION_A_TO_D: ["072350000000_1"],
                CONST_REGION_E_TO_H: [],
                CONST_REGION_I_TO_L: [],
                CONST_REGION_M_TO_Q: [],
                CONST_REGION_R_TO_U: [],
                CONST_REGION_V_TO_Z: [],
            },
        )

        assert result["type"] == data_entry_flow.FlowResultType.CREATE_ENTRY
        assert result["data"] is None

        assert dict(config_entry.data) == {
            CONF_FILTER_CORONA: deepcopy(DUMMY_DATA[CONF_FILTER_CORONA]),
            CONF_MESSAGE_SLOTS: deepcopy(DUMMY_DATA[CONF_MESSAGE_SLOTS]),
            CONST_REGION_A_TO_D: ["072350000000_1"],
            CONST_REGION_E_TO_H: [],
            CONST_REGION_I_TO_L: [],
            CONST_REGION_M_TO_Q: [],
            CONST_REGION_R_TO_U: [],
            CONST_REGION_V_TO_Z: [],
            CONF_REGIONS: {
                "072350000000": "Damflos (Trier-Saarburg - Rheinland-Pfalz)"
            },
        }


async def test_options_flow_with_no_selection(hass: HomeAssistant) -> None:
    """Test config flow options with no selection."""
    config_entry = MockConfigEntry(
        domain=DOMAIN,
        title="NINA",
        data=deepcopy(DUMMY_DATA),
    )
    config_entry.add_to_hass(hass)

    with patch(
        "homeassistant.components.nina.async_setup_entry", return_value=True
    ), patch(
        "pynina.baseApi.BaseAPI._makeRequest",
        wraps=mocked_request_function,
    ):
        await hass.config_entries.async_setup(config_entry.entry_id)
        await hass.async_block_till_done()

        result = await hass.config_entries.options.async_init(config_entry.entry_id)

        assert result["type"] == data_entry_flow.FlowResultType.FORM
        assert result["step_id"] == "init"

        result = await hass.config_entries.options.async_configure(
            result["flow_id"],
            user_input={
                CONST_REGION_A_TO_D: [],
                CONST_REGION_E_TO_H: [],
                CONST_REGION_I_TO_L: [],
                CONST_REGION_M_TO_Q: [],
                CONST_REGION_R_TO_U: [],
                CONST_REGION_V_TO_Z: [],
            },
        )

        assert result["type"] == data_entry_flow.FlowResultType.FORM
        assert result["step_id"] == "init"
        assert result["errors"] == {"base": "no_selection"}


async def test_options_flow_connection_error(hass: HomeAssistant) -> None:
    """Test config flow options but no connection."""
    config_entry = MockConfigEntry(
        domain=DOMAIN,
        title="NINA",
        data=deepcopy(DUMMY_DATA),
    )
    config_entry.add_to_hass(hass)

    with patch(
        "pynina.baseApi.BaseAPI._makeRequest",
        side_effect=ApiError("Could not connect to Api"),
    ), patch(
        "homeassistant.components.nina.async_setup_entry",
        return_value=True,
    ):
        await hass.config_entries.async_setup(config_entry.entry_id)
        await hass.async_block_till_done()

        result = await hass.config_entries.options.async_init(config_entry.entry_id)

        assert result["type"] == data_entry_flow.FlowResultType.FORM
        assert result["errors"] == {"base": "cannot_connect"}


async def test_options_flow_unexpected_exception(hass: HomeAssistant) -> None:
    """Test config flow options but with an unexpected exception."""
    config_entry = MockConfigEntry(
        domain=DOMAIN,
        title="NINA",
        data=deepcopy(DUMMY_DATA),
    )
    config_entry.add_to_hass(hass)

    with patch(
        "pynina.baseApi.BaseAPI._makeRequest",
        side_effect=Exception("DUMMY"),
    ), patch(
        "homeassistant.components.nina.async_setup_entry",
        return_value=True,
    ):
        await hass.config_entries.async_setup(config_entry.entry_id)
        await hass.async_block_till_done()

        result = await hass.config_entries.options.async_init(config_entry.entry_id)

        assert result["type"] == data_entry_flow.FlowResultType.ABORT


async def test_options_flow_entity_removal(hass: HomeAssistant) -> None:
    """Test if old entities are removed."""
    config_entry = MockConfigEntry(
        domain=DOMAIN,
        title="NINA",
        data=deepcopy(DUMMY_DATA) | {CONF_REGIONS: {"095760000000": "Aach"}},
    )
    config_entry.add_to_hass(hass)

    with patch(
        "pynina.baseApi.BaseAPI._makeRequest",
        wraps=mocked_request_function,
    ), patch(
        "homeassistant.components.nina._async_update_listener"
    ) as mock_update_listener:
        await hass.config_entries.async_setup(config_entry.entry_id)
        await hass.async_block_till_done()

        result = await hass.config_entries.options.async_init(config_entry.entry_id)

        result = await hass.config_entries.options.async_configure(
            result["flow_id"],
            user_input={
                CONF_MESSAGE_SLOTS: 2,
                CONST_REGION_A_TO_D: ["072350000000", "095760000000"],
                CONST_REGION_E_TO_H: [],
                CONST_REGION_I_TO_L: [],
                CONST_REGION_M_TO_Q: [],
                CONST_REGION_R_TO_U: [],
                CONST_REGION_V_TO_Z: [],
            },
        )

        assert result["type"] == data_entry_flow.FlowResultType.CREATE_ENTRY

        entity_registry: er = er.async_get(hass)
        entries = er.async_entries_for_config_entry(
            entity_registry, config_entry.entry_id
        )

        assert len(entries) == 2
        assert len(mock_update_listener.mock_calls) == 1