"""Tests for the Rova config flow."""

from unittest.mock import MagicMock

import pytest
from requests.exceptions import ConnectTimeout, HTTPError

from homeassistant.components.rova.const import (
    CONF_HOUSE_NUMBER,
    CONF_HOUSE_NUMBER_SUFFIX,
    CONF_ZIP_CODE,
    DOMAIN,
)
from homeassistant.config_entries import SOURCE_USER
from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultType

from tests.common import MockConfigEntry

ZIP_CODE = "7991AD"
HOUSE_NUMBER = "10"
HOUSE_NUMBER_SUFFIX = "a"


async def test_user(hass: HomeAssistant, mock_rova: MagicMock) -> None:
    """Test user config."""
    result = await hass.config_entries.flow.async_init(
        DOMAIN, context={"source": SOURCE_USER}
    )
    assert result.get("type") is FlowResultType.FORM
    assert result.get("step_id") == "user"

    # test with all information provided
    result = await hass.config_entries.flow.async_init(
        DOMAIN,
        context={"source": SOURCE_USER},
        data={
            CONF_ZIP_CODE: ZIP_CODE,
            CONF_HOUSE_NUMBER: HOUSE_NUMBER,
            CONF_HOUSE_NUMBER_SUFFIX: HOUSE_NUMBER_SUFFIX,
        },
    )
    assert result.get("type") is FlowResultType.CREATE_ENTRY

    data = result.get("data")
    assert data
    assert data[CONF_ZIP_CODE] == ZIP_CODE
    assert data[CONF_HOUSE_NUMBER] == HOUSE_NUMBER
    assert data[CONF_HOUSE_NUMBER_SUFFIX] == HOUSE_NUMBER_SUFFIX


async def test_error_if_not_rova_area(
    hass: HomeAssistant, mock_rova: MagicMock
) -> None:
    """Test we raise errors if rova does not collect at the given address."""
    result = await hass.config_entries.flow.async_init(
        DOMAIN, context={"source": SOURCE_USER}
    )

    # test with area where rova does not collect
    mock_rova.return_value.is_rova_area.return_value = False

    result = await hass.config_entries.flow.async_configure(
        result["flow_id"],
        {
            CONF_ZIP_CODE: ZIP_CODE,
            CONF_HOUSE_NUMBER: HOUSE_NUMBER,
            CONF_HOUSE_NUMBER_SUFFIX: HOUSE_NUMBER_SUFFIX,
        },
    )

    assert result.get("type") is FlowResultType.FORM
    assert result.get("errors") == {"base": "invalid_rova_area"}

    # now reset the return value and test if we can recover
    mock_rova.return_value.is_rova_area.return_value = True

    result = await hass.config_entries.flow.async_configure(
        result["flow_id"],
        {
            CONF_ZIP_CODE: ZIP_CODE,
            CONF_HOUSE_NUMBER: HOUSE_NUMBER,
            CONF_HOUSE_NUMBER_SUFFIX: HOUSE_NUMBER_SUFFIX,
        },
    )

    assert result["type"] is FlowResultType.CREATE_ENTRY
    assert result["title"] == f"{ZIP_CODE} {HOUSE_NUMBER} {HOUSE_NUMBER_SUFFIX}"
    assert result["data"] == {
        CONF_ZIP_CODE: ZIP_CODE,
        CONF_HOUSE_NUMBER: HOUSE_NUMBER,
        CONF_HOUSE_NUMBER_SUFFIX: HOUSE_NUMBER_SUFFIX,
    }


async def test_abort_if_already_setup(hass: HomeAssistant) -> None:
    """Test we abort if rova is already setup."""
    MockConfigEntry(
        domain=DOMAIN,
        unique_id=f"{ZIP_CODE}{HOUSE_NUMBER}{HOUSE_NUMBER_SUFFIX}",
        data={
            CONF_ZIP_CODE: ZIP_CODE,
            CONF_HOUSE_NUMBER: HOUSE_NUMBER,
            CONF_HOUSE_NUMBER_SUFFIX: HOUSE_NUMBER_SUFFIX,
        },
    ).add_to_hass(hass)

    result = await hass.config_entries.flow.async_init(
        DOMAIN,
        context={"source": SOURCE_USER},
        data={
            CONF_ZIP_CODE: ZIP_CODE,
            CONF_HOUSE_NUMBER: HOUSE_NUMBER,
            CONF_HOUSE_NUMBER_SUFFIX: HOUSE_NUMBER_SUFFIX,
        },
    )
    assert result["type"] is FlowResultType.ABORT
    assert result["reason"] == "already_configured"


@pytest.mark.parametrize(
    ("exception", "error"),
    [
        (ConnectTimeout(), "cannot_connect"),
        (HTTPError(), "cannot_connect"),
    ],
)
async def test_abort_if_api_throws_exception(
    hass: HomeAssistant, exception: Exception, error: str, mock_rova: MagicMock
) -> None:
    """Test different exceptions for the Rova entity."""
    result = await hass.config_entries.flow.async_init(
        DOMAIN,
        context={"source": SOURCE_USER},
    )

    # test with exception
    mock_rova.return_value.is_rova_area.side_effect = exception

    result = await hass.config_entries.flow.async_configure(
        result["flow_id"],
        {
            CONF_ZIP_CODE: ZIP_CODE,
            CONF_HOUSE_NUMBER: HOUSE_NUMBER,
            CONF_HOUSE_NUMBER_SUFFIX: HOUSE_NUMBER_SUFFIX,
        },
    )
    assert result.get("type") is FlowResultType.FORM
    assert result.get("errors") == {"base": error}

    # now reset the side effect to see if we can recover
    mock_rova.return_value.is_rova_area.side_effect = None

    result = await hass.config_entries.flow.async_configure(
        result["flow_id"],
        {
            CONF_ZIP_CODE: ZIP_CODE,
            CONF_HOUSE_NUMBER: HOUSE_NUMBER,
            CONF_HOUSE_NUMBER_SUFFIX: HOUSE_NUMBER_SUFFIX,
        },
    )

    assert result["type"] is FlowResultType.CREATE_ENTRY
    assert result["title"] == f"{ZIP_CODE} {HOUSE_NUMBER} {HOUSE_NUMBER_SUFFIX}"
    assert result["data"] == {
        CONF_ZIP_CODE: ZIP_CODE,
        CONF_HOUSE_NUMBER: HOUSE_NUMBER,
        CONF_HOUSE_NUMBER_SUFFIX: HOUSE_NUMBER_SUFFIX,
    }
