"""Tests for OwnTracks config flow."""
from unittest.mock import patch

import pytest

from homeassistant import config_entries, data_entry_flow
from homeassistant.components.owntracks import config_flow
from homeassistant.components.owntracks.config_flow import CONF_CLOUDHOOK, CONF_SECRET
from homeassistant.components.owntracks.const import DOMAIN
from homeassistant.config import async_process_ha_core_config
from homeassistant.const import CONF_WEBHOOK_ID
from homeassistant.setup import async_setup_component

from tests.common import MockConfigEntry

CONF_WEBHOOK_URL = "webhook_url"

BASE_URL = "http://example.com"
CLOUDHOOK = False
SECRET = "test-secret"
WEBHOOK_ID = "webhook_id"
WEBHOOK_URL = f"{BASE_URL}/api/webhook/webhook_id"


@pytest.fixture(name="webhook_id")
def mock_webhook_id():
    """Mock webhook_id."""
    with patch(
        "homeassistant.components.webhook.async_generate_id", return_value=WEBHOOK_ID
    ):
        yield


@pytest.fixture(name="secret")
def mock_secret():
    """Mock secret."""
    with patch("secrets.token_hex", return_value=SECRET):
        yield


@pytest.fixture(name="not_supports_encryption")
def mock_not_supports_encryption():
    """Mock non successful nacl import."""
    with patch(
        "homeassistant.components.owntracks.config_flow.supports_encryption",
        return_value=False,
    ):
        yield


async def init_config_flow(hass):
    """Init a configuration flow."""
    await async_process_ha_core_config(
        hass,
        {"external_url": BASE_URL},
    )
    flow = config_flow.OwnTracksFlow()
    flow.hass = hass
    return flow


async def test_user(hass, webhook_id, secret):
    """Test user step."""
    flow = await init_config_flow(hass)

    result = await flow.async_step_user()
    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert result["step_id"] == "user"

    result = await flow.async_step_user({})
    assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
    assert result["title"] == "OwnTracks"
    assert result["data"][CONF_WEBHOOK_ID] == WEBHOOK_ID
    assert result["data"][CONF_SECRET] == SECRET
    assert result["data"][CONF_CLOUDHOOK] == CLOUDHOOK
    assert result["description_placeholders"][CONF_WEBHOOK_URL] == WEBHOOK_URL


async def test_import(hass, webhook_id, secret):
    """Test import step."""
    flow = await init_config_flow(hass)

    result = await flow.async_step_import({})
    assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
    assert result["title"] == "OwnTracks"
    assert result["data"][CONF_WEBHOOK_ID] == WEBHOOK_ID
    assert result["data"][CONF_SECRET] == SECRET
    assert result["data"][CONF_CLOUDHOOK] == CLOUDHOOK
    assert result["description_placeholders"] is None


async def test_import_setup(hass):
    """Test that we automatically create a config flow."""
    await async_process_ha_core_config(
        hass,
        {"external_url": "http://example.com"},
    )

    assert not hass.config_entries.async_entries(DOMAIN)
    assert await async_setup_component(hass, DOMAIN, {"owntracks": {}})
    await hass.async_block_till_done()
    assert hass.config_entries.async_entries(DOMAIN)


async def test_abort_if_already_setup(hass):
    """Test that we can't add more than one instance."""
    flow = await init_config_flow(hass)

    MockConfigEntry(domain=DOMAIN, data={}).add_to_hass(hass)
    assert hass.config_entries.async_entries(DOMAIN)

    # Should fail, already setup (import)
    result = await flow.async_step_import({})
    assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
    assert result["reason"] == "single_instance_allowed"

    # Should fail, already setup (flow)
    result = await flow.async_step_user({})
    assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
    assert result["reason"] == "single_instance_allowed"


async def test_user_not_supports_encryption(hass, not_supports_encryption):
    """Test user step."""
    flow = await init_config_flow(hass)

    result = await flow.async_step_user({})
    assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
    assert (
        result["description_placeholders"]["secret"]
        == "Encryption is not supported because nacl is not installed."
    )


async def test_unload(hass):
    """Test unloading a config flow."""
    await async_process_ha_core_config(
        hass,
        {"external_url": "http://example.com"},
    )

    with patch(
        "homeassistant.config_entries.ConfigEntries.async_forward_entry_setup"
    ) as mock_forward:
        result = await hass.config_entries.flow.async_init(
            DOMAIN, context={"source": config_entries.SOURCE_IMPORT}, data={}
        )

    assert len(mock_forward.mock_calls) == 1
    entry = result["result"]

    assert mock_forward.mock_calls[0][1][0] is entry
    assert mock_forward.mock_calls[0][1][1] == "device_tracker"
    assert entry.data["webhook_id"] in hass.data["webhook"]

    with patch(
        "homeassistant.config_entries.ConfigEntries.async_unload_platforms",
        return_value=True,
    ) as mock_unload:
        assert await hass.config_entries.async_unload(entry.entry_id)

    assert len(mock_unload.mock_calls) == 1
    assert mock_forward.mock_calls[0][1][0] is entry
    assert mock_forward.mock_calls[0][1][1] == "device_tracker"
    assert entry.data["webhook_id"] not in hass.data["webhook"]


async def test_with_cloud_sub(hass):
    """Test creating a config flow while subscribed."""
    hass.config.components.add("cloud")
    with patch(
        "homeassistant.components.cloud.async_active_subscription", return_value=True
    ), patch(
        "homeassistant.components.cloud.async_create_cloudhook",
        return_value="https://hooks.nabu.casa/ABCD",
    ):
        result = await hass.config_entries.flow.async_init(
            DOMAIN, context={"source": config_entries.SOURCE_USER}, data={}
        )

    entry = result["result"]
    assert entry.data["cloudhook"]
    assert (
        result["description_placeholders"]["webhook_url"]
        == "https://hooks.nabu.casa/ABCD"
    )
