"""Test the Nmap Tracker config flow."""

from unittest.mock import patch

import pytest

from homeassistant import config_entries
from homeassistant.components.device_tracker import (
    CONF_CONSIDER_HOME,
    CONF_SCAN_INTERVAL,
)
from homeassistant.components.nmap_tracker.const import (
    CONF_HOME_INTERVAL,
    CONF_HOSTS_EXCLUDE,
    CONF_HOSTS_LIST,
    CONF_MAC_EXCLUDE,
    CONF_OPTIONS,
    DEFAULT_OPTIONS,
    DOMAIN,
)
from homeassistant.core import CoreState, HomeAssistant
from homeassistant.data_entry_flow import FlowResultType

from tests.common import MockConfigEntry


@pytest.mark.parametrize(
    "hosts", [["1.1.1.1"], ["192.168.1.0/24"], ["192.168.1.0/24", "192.168.2.0/24"]]
)
async def test_form(hass: HomeAssistant, hosts: str) -> None:
    """Test we get the form."""

    result = await hass.config_entries.flow.async_init(
        DOMAIN, context={"source": config_entries.SOURCE_USER}
    )
    assert result["type"] is FlowResultType.FORM
    assert result["errors"] == {}

    schema_defaults = result["data_schema"]({})
    assert CONF_SCAN_INTERVAL not in schema_defaults

    with patch(
        "homeassistant.components.nmap_tracker.async_setup_entry",
        return_value=True,
    ) as mock_setup_entry:
        result2 = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {
                CONF_HOSTS_LIST: hosts,
                CONF_HOME_INTERVAL: 3,
                CONF_OPTIONS: DEFAULT_OPTIONS,
                CONF_HOSTS_EXCLUDE: ["4.4.4.4"],
                CONF_MAC_EXCLUDE: ["00:00:00:00:00:00"],
            },
        )
        await hass.async_block_till_done()

    assert result2["type"] is FlowResultType.CREATE_ENTRY
    assert result2["title"] == f"Nmap Tracker {', '.join(hosts)}"
    assert result2["data"] == {}
    assert result2["options"] == {
        CONF_HOSTS_LIST: hosts,
        CONF_HOME_INTERVAL: 3,
        CONF_OPTIONS: DEFAULT_OPTIONS,
        CONF_HOSTS_EXCLUDE: ["4.4.4.4"],
        CONF_MAC_EXCLUDE: ["00:00:00:00:00:00"],
    }
    assert len(mock_setup_entry.mock_calls) == 1


async def test_form_range(hass: HomeAssistant) -> None:
    """Test we get the form and can take an ip range."""

    result = await hass.config_entries.flow.async_init(
        DOMAIN, context={"source": config_entries.SOURCE_USER}
    )
    assert result["type"] is FlowResultType.FORM
    assert result["errors"] == {}

    with patch(
        "homeassistant.components.nmap_tracker.async_setup_entry",
        return_value=True,
    ) as mock_setup_entry:
        result2 = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {
                CONF_HOSTS_LIST: ["192.168.0.5-12"],
                CONF_HOME_INTERVAL: 3,
                CONF_OPTIONS: DEFAULT_OPTIONS,
                CONF_HOSTS_EXCLUDE: ["4.4.4.4"],
                CONF_MAC_EXCLUDE: ["00:00:00:00:00:00"],
            },
        )
        await hass.async_block_till_done()

    assert result2["type"] is FlowResultType.CREATE_ENTRY
    assert result2["title"] == "Nmap Tracker 192.168.0.5-12"
    assert result2["data"] == {}
    assert result2["options"] == {
        CONF_HOSTS_LIST: ["192.168.0.5-12"],
        CONF_HOME_INTERVAL: 3,
        CONF_OPTIONS: DEFAULT_OPTIONS,
        CONF_HOSTS_EXCLUDE: ["4.4.4.4"],
        CONF_MAC_EXCLUDE: ["00:00:00:00:00:00"],
    }
    assert len(mock_setup_entry.mock_calls) == 1


async def test_form_invalid_hosts(hass: HomeAssistant) -> None:
    """Test invalid hosts passed in."""

    result = await hass.config_entries.flow.async_init(
        DOMAIN, context={"source": config_entries.SOURCE_USER}
    )
    assert result["type"] is FlowResultType.FORM
    assert result["errors"] == {}

    result2 = await hass.config_entries.flow.async_configure(
        result["flow_id"],
        {
            CONF_HOSTS_LIST: ["not an ip block"],
            CONF_HOME_INTERVAL: 3,
            CONF_OPTIONS: DEFAULT_OPTIONS,
            CONF_HOSTS_EXCLUDE: [],
            CONF_MAC_EXCLUDE: ["00:00:00:00:00:00"],
        },
    )
    await hass.async_block_till_done()

    assert result2["type"] is FlowResultType.FORM
    assert result2["errors"] == {CONF_HOSTS_LIST: "invalid_hosts"}


async def test_form_already_configured(hass: HomeAssistant) -> None:
    """Test duplicate host list."""

    config_entry = MockConfigEntry(
        domain=DOMAIN,
        data={},
        options={
            CONF_HOSTS_LIST: ["192.168.0.0/20"],
            CONF_HOME_INTERVAL: 3,
            CONF_OPTIONS: DEFAULT_OPTIONS,
            CONF_HOSTS_EXCLUDE: ["4.4.4.4"],
            CONF_MAC_EXCLUDE: ["00:00:00:00:00:00"],
        },
    )
    config_entry.add_to_hass(hass)
    result = await hass.config_entries.flow.async_init(
        DOMAIN, context={"source": config_entries.SOURCE_USER}
    )
    assert result["type"] is FlowResultType.FORM
    assert result["errors"] == {}

    result2 = await hass.config_entries.flow.async_configure(
        result["flow_id"],
        {
            CONF_HOSTS_LIST: ["192.168.0.0/20"],
            CONF_HOME_INTERVAL: 3,
            CONF_OPTIONS: DEFAULT_OPTIONS,
            CONF_HOSTS_EXCLUDE: [],
            CONF_MAC_EXCLUDE: ["00:00:00:00:00:00"],
        },
    )
    await hass.async_block_till_done()

    assert result2["type"] is FlowResultType.ABORT
    assert result2["reason"] == "already_configured"


async def test_form_invalid_ip_excludes(hass: HomeAssistant) -> None:
    """Test invalid ip excludes passed in."""

    result = await hass.config_entries.flow.async_init(
        DOMAIN, context={"source": config_entries.SOURCE_USER}
    )
    assert result["type"] is FlowResultType.FORM
    assert result["errors"] == {}

    result2 = await hass.config_entries.flow.async_configure(
        result["flow_id"],
        {
            CONF_HOSTS_LIST: ["3.3.3.3"],
            CONF_HOME_INTERVAL: 3,
            CONF_OPTIONS: DEFAULT_OPTIONS,
            CONF_HOSTS_EXCLUDE: ["not an exclude"],
            CONF_MAC_EXCLUDE: ["00:00:00:00:00:00"],
        },
    )
    await hass.async_block_till_done()

    assert result2["type"] is FlowResultType.FORM
    assert result2["errors"] == {CONF_HOSTS_EXCLUDE: "invalid_hosts"}


@pytest.mark.parametrize(
    "mac_excludes",
    [["1234567890"], ["1234567890", "11:22:33:44:55:66"], ["ABCDEFGHIJK"]],
)
async def test_form_invalid_mac_excludes(
    hass: HomeAssistant, mac_excludes: str
) -> None:
    """Test invalid mac excludes passed in."""

    result = await hass.config_entries.flow.async_init(
        DOMAIN, context={"source": config_entries.SOURCE_USER}
    )
    assert result["type"] is FlowResultType.FORM
    assert result["errors"] == {}

    result2 = await hass.config_entries.flow.async_configure(
        result["flow_id"],
        {
            CONF_HOSTS_LIST: ["3.3.3.3"],
            CONF_HOME_INTERVAL: 3,
            CONF_OPTIONS: DEFAULT_OPTIONS,
            CONF_HOSTS_EXCLUDE: ["4.4.4.4"],
            CONF_MAC_EXCLUDE: mac_excludes,
        },
    )
    await hass.async_block_till_done()

    assert result2["type"] is FlowResultType.FORM
    assert result2["errors"] == {CONF_MAC_EXCLUDE: "invalid_hosts"}


async def test_options_flow(hass: HomeAssistant) -> None:
    """Test we can edit options."""

    config_entry = MockConfigEntry(
        domain=DOMAIN,
        data={},
        options={
            CONF_HOSTS_LIST: ["192.168.1.0/24"],
            CONF_HOME_INTERVAL: 3,
            CONF_OPTIONS: DEFAULT_OPTIONS,
            CONF_HOSTS_EXCLUDE: ["4.4.4.4"],
            CONF_MAC_EXCLUDE: ["00:00:00:00:00:00", "11:22:33:44:55:66"],
        },
        version=1,
        minor_version=2,
    )
    config_entry.add_to_hass(hass)
    hass.set_state(CoreState.stopped)

    assert 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)
    await hass.async_block_till_done()

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

    assert result["data_schema"]({}) == {
        CONF_HOSTS_EXCLUDE: ["4.4.4.4"],
        CONF_HOME_INTERVAL: 3,
        CONF_HOSTS_LIST: ["192.168.1.0/24"],
        CONF_CONSIDER_HOME: 180,
        CONF_SCAN_INTERVAL: 120,
        CONF_OPTIONS: "-n -sn -PR -T4 --min-rate 10 --host-timeout 5s",
        CONF_MAC_EXCLUDE: ["00:00:00:00:00:00", "11:22:33:44:55:66"],
    }

    with patch(
        "homeassistant.components.nmap_tracker.async_setup_entry",
        return_value=True,
    ) as mock_setup_entry:
        result = await hass.config_entries.options.async_configure(
            result["flow_id"],
            user_input={
                CONF_HOSTS_LIST: ["192.168.1.0/24", "192.168.2.0/24"],
                CONF_HOME_INTERVAL: 5,
                CONF_CONSIDER_HOME: 500,
                CONF_OPTIONS: "-sn",
                CONF_HOSTS_EXCLUDE: ["4.4.4.4", "5.5.5.5"],
                CONF_SCAN_INTERVAL: 10,
                CONF_MAC_EXCLUDE: ["00:00:00:00:00:00", "11:22:33:44:55:66"],
            },
        )
        await hass.async_block_till_done()

    assert result["type"] is FlowResultType.CREATE_ENTRY
    assert config_entry.options == {
        CONF_HOSTS_LIST: ["192.168.1.0/24", "192.168.2.0/24"],
        CONF_HOME_INTERVAL: 5,
        CONF_CONSIDER_HOME: 500,
        CONF_OPTIONS: "-sn",
        CONF_HOSTS_EXCLUDE: ["4.4.4.4", "5.5.5.5"],
        CONF_SCAN_INTERVAL: 10,
        CONF_MAC_EXCLUDE: ["00:00:00:00:00:00", "11:22:33:44:55:66"],
    }
    assert len(mock_setup_entry.mock_calls) == 1
