"""The tests for the feedreader config flow."""

from unittest.mock import Mock, patch
import urllib

import pytest

from homeassistant.components.feedreader import CONF_URLS
from homeassistant.components.feedreader.const import (
    CONF_MAX_ENTRIES,
    DEFAULT_MAX_ENTRIES,
    DOMAIN,
)
from homeassistant.config_entries import SOURCE_RECONFIGURE, SOURCE_USER
from homeassistant.const import CONF_URL
from homeassistant.core import DOMAIN as HA_DOMAIN, HomeAssistant
from homeassistant.data_entry_flow import FlowResultType
from homeassistant.helpers import issue_registry as ir
from homeassistant.setup import async_setup_component

from . import create_mock_entry
from .const import FEED_TITLE, URL, VALID_CONFIG_DEFAULT


@pytest.fixture(name="feedparser")
def feedparser_fixture(feed_one_event: bytes) -> Mock:
    """Patch libraries."""
    with (
        patch(
            "homeassistant.components.feedreader.config_flow.feedparser.http.get",
            return_value=feed_one_event,
        ) as feedparser,
    ):
        yield feedparser


@pytest.fixture(name="setup_entry")
def setup_entry_fixture(feed_one_event: bytes) -> Mock:
    """Patch libraries."""
    with (
        patch("homeassistant.components.feedreader.async_setup_entry") as setup_entry,
    ):
        yield setup_entry


async def test_user(hass: HomeAssistant, feedparser, setup_entry) -> None:
    """Test starting a flow by user."""
    # init user flow
    result = await hass.config_entries.flow.async_init(
        DOMAIN, context={"source": SOURCE_USER}
    )
    assert result["type"] is FlowResultType.FORM
    assert result["step_id"] == "user"

    # success
    result = await hass.config_entries.flow.async_configure(
        result["flow_id"], user_input={CONF_URL: URL}
    )
    assert result["type"] is FlowResultType.CREATE_ENTRY
    assert result["title"] == FEED_TITLE
    assert result["data"][CONF_URL] == URL
    assert result["options"][CONF_MAX_ENTRIES] == DEFAULT_MAX_ENTRIES


async def test_user_errors(
    hass: HomeAssistant, feedparser, setup_entry, feed_one_event
) -> None:
    """Test starting a flow by user which results in an URL error."""
    # init user flow
    result = await hass.config_entries.flow.async_init(
        DOMAIN, context={"source": SOURCE_USER}
    )
    assert result["type"] is FlowResultType.FORM
    assert result["step_id"] == "user"

    # raise URLError
    feedparser.side_effect = urllib.error.URLError("Test")
    feedparser.return_value = None
    result = await hass.config_entries.flow.async_configure(
        result["flow_id"], user_input={CONF_URL: URL}
    )
    assert result["type"] is FlowResultType.FORM
    assert result["step_id"] == "user"
    assert result["errors"] == {"base": "url_error"}

    # no feed entries returned
    feedparser.side_effect = None
    feedparser.return_value = None
    result = await hass.config_entries.flow.async_configure(
        result["flow_id"], user_input={CONF_URL: URL}
    )
    assert result["type"] is FlowResultType.FORM
    assert result["step_id"] == "user"
    assert result["errors"] == {"base": "no_feed_entries"}

    # success
    feedparser.side_effect = None
    feedparser.return_value = feed_one_event
    result = await hass.config_entries.flow.async_configure(
        result["flow_id"], user_input={CONF_URL: URL}
    )
    assert result["type"] is FlowResultType.CREATE_ENTRY
    assert result["title"] == FEED_TITLE
    assert result["data"][CONF_URL] == URL
    assert result["options"][CONF_MAX_ENTRIES] == DEFAULT_MAX_ENTRIES


@pytest.mark.parametrize(
    ("data", "expected_data", "expected_options"),
    [
        ({CONF_URLS: [URL]}, {CONF_URL: URL}, {CONF_MAX_ENTRIES: DEFAULT_MAX_ENTRIES}),
        (
            {CONF_URLS: [URL], CONF_MAX_ENTRIES: 5},
            {CONF_URL: URL},
            {CONF_MAX_ENTRIES: 5},
        ),
    ],
)
async def test_import(
    hass: HomeAssistant,
    issue_registry: ir.IssueRegistry,
    data,
    expected_data,
    expected_options,
    feedparser,
    setup_entry,
) -> None:
    """Test starting an import flow."""
    config_entries = hass.config_entries.async_entries(DOMAIN)
    assert not config_entries

    assert await async_setup_component(hass, DOMAIN, {DOMAIN: data})

    config_entries = hass.config_entries.async_entries(DOMAIN)
    assert config_entries
    assert len(config_entries) == 1
    assert config_entries[0].title == FEED_TITLE
    assert config_entries[0].data == expected_data
    assert config_entries[0].options == expected_options

    assert issue_registry.async_get_issue(HA_DOMAIN, "deprecated_yaml_feedreader")


@pytest.mark.parametrize(
    ("side_effect", "return_value", "expected_issue_id"),
    [
        (
            urllib.error.URLError("Test"),
            None,
            "import_yaml_error_feedreader_url_error_http_some_rss_local_rss_feed_xml",
        ),
        (
            None,
            None,
            "import_yaml_error_feedreader_no_feed_entries_http_some_rss_local_rss_feed_xml",
        ),
    ],
)
async def test_import_errors(
    hass: HomeAssistant,
    issue_registry: ir.IssueRegistry,
    feedparser,
    setup_entry,
    feed_one_event,
    side_effect,
    return_value,
    expected_issue_id,
) -> None:
    """Test starting an import flow which results in an URL error."""
    config_entries = hass.config_entries.async_entries(DOMAIN)
    assert not config_entries

    # raise URLError
    feedparser.side_effect = side_effect
    feedparser.return_value = return_value
    assert await async_setup_component(hass, DOMAIN, {DOMAIN: {CONF_URLS: [URL]}})
    assert issue_registry.async_get_issue(DOMAIN, expected_issue_id)


async def test_reconfigure(hass: HomeAssistant, feedparser) -> None:
    """Test starting a reconfigure flow."""
    entry = create_mock_entry(VALID_CONFIG_DEFAULT)
    entry.add_to_hass(hass)
    await hass.config_entries.async_setup(entry.entry_id)
    await hass.async_block_till_done()

    # init user flow
    result = await hass.config_entries.flow.async_init(
        DOMAIN,
        context={
            "source": SOURCE_RECONFIGURE,
            "entry_id": entry.entry_id,
        },
        data=entry.data,
    )
    assert result["type"] is FlowResultType.FORM
    assert result["step_id"] == "reconfigure_confirm"

    # success
    with patch(
        "homeassistant.config_entries.ConfigEntries.async_reload"
    ) as mock_async_reload:
        result = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            user_input={
                CONF_URL: "http://other.rss.local/rss_feed.xml",
            },
        )
    assert result["type"] is FlowResultType.ABORT
    assert result["reason"] == "reconfigure_successful"
    assert entry.data == {
        CONF_URL: "http://other.rss.local/rss_feed.xml",
    }

    await hass.async_block_till_done()
    assert mock_async_reload.call_count == 1


async def test_reconfigure_errors(
    hass: HomeAssistant, feedparser, setup_entry, feed_one_event
) -> None:
    """Test starting a reconfigure flow by user which results in an URL error."""
    entry = create_mock_entry(VALID_CONFIG_DEFAULT)
    entry.add_to_hass(hass)

    # init user flow
    result = await hass.config_entries.flow.async_init(
        DOMAIN,
        context={
            "source": SOURCE_RECONFIGURE,
            "entry_id": entry.entry_id,
        },
        data=entry.data,
    )
    assert result["type"] is FlowResultType.FORM
    assert result["step_id"] == "reconfigure_confirm"

    # raise URLError
    feedparser.side_effect = urllib.error.URLError("Test")
    feedparser.return_value = None
    result = await hass.config_entries.flow.async_configure(
        result["flow_id"],
        user_input={
            CONF_URL: "http://other.rss.local/rss_feed.xml",
        },
    )
    assert result["type"] is FlowResultType.FORM
    assert result["step_id"] == "reconfigure_confirm"
    assert result["errors"] == {"base": "url_error"}

    # no feed entries returned
    feedparser.side_effect = None
    feedparser.return_value = None
    result = await hass.config_entries.flow.async_configure(
        result["flow_id"],
        user_input={
            CONF_URL: "http://other.rss.local/rss_feed.xml",
        },
    )
    assert result["type"] is FlowResultType.FORM
    assert result["step_id"] == "reconfigure_confirm"
    assert result["errors"] == {"base": "no_feed_entries"}

    # success
    feedparser.side_effect = None
    feedparser.return_value = feed_one_event

    # success
    result = await hass.config_entries.flow.async_configure(
        result["flow_id"],
        user_input={
            CONF_URL: "http://other.rss.local/rss_feed.xml",
        },
    )
    assert result["type"] is FlowResultType.ABORT
    assert result["reason"] == "reconfigure_successful"
    assert entry.data == {
        CONF_URL: "http://other.rss.local/rss_feed.xml",
    }


async def test_options_flow(hass: HomeAssistant) -> None:
    """Test options flow."""
    entry = create_mock_entry(VALID_CONFIG_DEFAULT)
    entry.add_to_hass(hass)

    result = await hass.config_entries.options.async_init(entry.entry_id)
    result = await hass.config_entries.options.async_configure(
        result["flow_id"],
        user_input={
            CONF_MAX_ENTRIES: 10,
        },
    )

    assert result["type"] is FlowResultType.CREATE_ENTRY
    assert result["data"] == {
        CONF_MAX_ENTRIES: 10,
    }