"""Test the Uonet+ Vulcan config flow."""
import json
from unittest import mock
from unittest.mock import patch

from vulcan import Account
from vulcan.model import Student

from homeassistant import config_entries, data_entry_flow
from homeassistant.components.vulcan import config_flow, const, register
from homeassistant.components.vulcan.config_flow import (
    ClientConnectionError,
    Keystore,
    VulcanAPIException,
)
from homeassistant.const import CONF_PIN, CONF_REGION, CONF_SCAN_INTERVAL, CONF_TOKEN

from tests.common import MockConfigEntry, load_fixture

fake_keystore = Keystore("", "", "", "", "")
fake_account = Account(
    login_id=1,
    user_login="<EMAIL>",
    user_name="<EMAIL>",
    rest_url="rest_url",
)


async def test_show_form(hass):
    """Test that the form is served with no input."""
    flow = config_flow.VulcanFlowHandler()
    flow.hass = hass

    result = await flow.async_step_user(user_input=None)

    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert result["step_id"] == "auth"


@mock.patch("homeassistant.components.vulcan.config_flow.Vulcan.get_students")
@mock.patch("homeassistant.components.vulcan.config_flow.Account.register")
@mock.patch("homeassistant.components.vulcan.config_flow.Keystore.create")
async def test_config_flow_auth_success(
    mock_keystore, mock_account, mock_student, hass
):
    """Test a successful config flow initialized by the user."""
    mock_keystore.return_value = fake_keystore
    mock_account.return_value = fake_account
    mock_student.return_value = [
        Student.load(load_fixture("fake_student_1.json", "vulcan"))
    ]
    result = await hass.config_entries.flow.async_init(
        const.DOMAIN, context={"source": config_entries.SOURCE_USER}
    )

    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert result["step_id"] == "auth"
    assert result["errors"] is None
    result = await hass.config_entries.flow.async_configure(
        result["flow_id"],
        {CONF_TOKEN: "token", CONF_REGION: "region", CONF_PIN: "000000"},
    )

    assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
    assert result["title"] == "<NAME>"


@mock.patch("homeassistant.components.vulcan.config_flow.Vulcan.get_students")
@mock.patch("homeassistant.components.vulcan.config_flow.Account.register")
@mock.patch("homeassistant.components.vulcan.config_flow.Keystore.create")
async def test_config_flow_auth_success_with_multiple_students(
    mock_keystore, mock_account, mock_student, hass
):
    """Test a successful config flow with multiple students."""
    mock_keystore.return_value = fake_keystore
    mock_account.return_value = fake_account
    mock_student.return_value = [
        Student.load(student)
        for student in [load_fixture("fake_student_1.json", "vulcan")]
        + [load_fixture("fake_student_2.json", "vulcan")]
    ]
    result = await hass.config_entries.flow.async_init(
        const.DOMAIN, context={"source": config_entries.SOURCE_USER}
    )

    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert result["step_id"] == "auth"
    assert result["errors"] is None

    result = await hass.config_entries.flow.async_configure(
        result["flow_id"],
        {CONF_TOKEN: "token", CONF_REGION: "region", CONF_PIN: "000000"},
    )

    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert result["step_id"] == "select_student"
    assert result["errors"] == {}

    result = await hass.config_entries.flow.async_configure(
        result["flow_id"],
        {"student": "0"},
    )

    assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
    assert result["title"] == "<NAME>"


@mock.patch("homeassistant.components.vulcan.config_flow.Vulcan.get_students")
@mock.patch("homeassistant.components.vulcan.config_flow.Keystore.create")
@mock.patch("homeassistant.components.vulcan.config_flow.Account.register")
async def test_config_flow_reauth_success(
    mock_account, mock_keystore, mock_student, hass
):
    """Test a successful config flow reauth."""
    mock_keystore.return_value = fake_keystore
    mock_account.return_value = fake_account
    mock_student.return_value = [
        Student.load(load_fixture("fake_student_1.json", "vulcan"))
    ]
    MockConfigEntry(
        domain=const.DOMAIN,
        unique_id="0",
        data={"student_id": "0", "login": "<EMAIL>"},
    ).add_to_hass(hass)
    result = await hass.config_entries.flow.async_init(
        const.DOMAIN, context={"source": config_entries.SOURCE_REAUTH}
    )

    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert result["step_id"] == "reauth"
    assert result["errors"] == {}

    result = await hass.config_entries.flow.async_configure(
        result["flow_id"],
        {CONF_TOKEN: "token", CONF_REGION: "region", CONF_PIN: "000000"},
    )

    assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
    assert result["reason"] == "reauth_successful"


@mock.patch("homeassistant.components.vulcan.config_flow.Keystore.create")
@mock.patch("homeassistant.components.vulcan.config_flow.Account.register")
async def test_config_flow_reauth_with_errors(mock_account, mock_keystore, hass):
    """Test reauth config flow with errors."""
    mock_keystore.return_value = fake_keystore
    mock_account.return_value = fake_account
    result = await hass.config_entries.flow.async_init(
        const.DOMAIN, context={"source": config_entries.SOURCE_REAUTH}
    )
    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert result["step_id"] == "reauth"
    assert result["errors"] == {}
    with patch(
        "homeassistant.components.vulcan.config_flow.Account.register",
        side_effect=VulcanAPIException("Invalid token."),
    ):

        result = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {CONF_TOKEN: "token", CONF_REGION: "region", CONF_PIN: "000000"},
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "reauth"
        assert result["errors"] == {"base": "invalid_token"}

    with patch(
        "homeassistant.components.vulcan.config_flow.Account.register",
        side_effect=VulcanAPIException("Expired token."),
    ):

        result = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {CONF_TOKEN: "token", CONF_REGION: "region", CONF_PIN: "000000"},
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "reauth"
        assert result["errors"] == {"base": "expired_token"}

    with patch(
        "homeassistant.components.vulcan.config_flow.Account.register",
        side_effect=VulcanAPIException("Invalid PIN."),
    ):

        result = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {CONF_TOKEN: "token", CONF_REGION: "region", CONF_PIN: "000000"},
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "reauth"
        assert result["errors"] == {"base": "invalid_pin"}

    with patch(
        "homeassistant.components.vulcan.config_flow.Account.register",
        side_effect=VulcanAPIException("Unknown error"),
    ):

        result = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {CONF_TOKEN: "token", CONF_REGION: "region", CONF_PIN: "000000"},
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "reauth"
        assert result["errors"] == {"base": "unknown"}

    with patch(
        "homeassistant.components.vulcan.config_flow.Account.register",
        side_effect=RuntimeError("Internal Server Error (ArgumentException)"),
    ):

        result = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {CONF_TOKEN: "token", CONF_REGION: "region", CONF_PIN: "000000"},
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "reauth"
        assert result["errors"] == {"base": "invalid_symbol"}

    with patch(
        "homeassistant.components.vulcan.config_flow.Account.register",
        side_effect=RuntimeError("Unknown error"),
    ):

        result = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {CONF_TOKEN: "token", CONF_REGION: "region", CONF_PIN: "000000"},
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "reauth"
        assert result["errors"] == {"base": "unknown"}

    with patch(
        "homeassistant.components.vulcan.config_flow.Account.register",
        side_effect=ClientConnectionError,
    ):

        result = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {CONF_TOKEN: "token", CONF_REGION: "region", CONF_PIN: "000000"},
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "reauth"
        assert result["errors"] == {"base": "cannot_connect"}

    with patch(
        "homeassistant.components.vulcan.config_flow.Account.register",
        side_effect=Exception,
    ):

        result = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {CONF_TOKEN: "token", CONF_REGION: "region", CONF_PIN: "000000"},
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "reauth"
        assert result["errors"] == {"base": "unknown"}


@mock.patch("homeassistant.components.vulcan.config_flow.Vulcan.get_students")
@mock.patch("homeassistant.components.vulcan.config_flow.Keystore.create")
@mock.patch("homeassistant.components.vulcan.config_flow.Account.register")
async def test_multiple_config_entries(mock_account, mock_keystore, mock_student, hass):
    """Test a successful config flow for multiple config entries."""
    mock_keystore.return_value = fake_keystore
    mock_account.return_value = fake_account
    mock_student.return_value = [
        Student.load(load_fixture("fake_student_1.json", "vulcan"))
    ]
    MockConfigEntry(
        domain=const.DOMAIN,
        unique_id="123456",
        data=json.loads(load_fixture("fake_config_entry_data.json", "vulcan")),
    ).add_to_hass(hass)
    await register.register(hass, "token", "region", "000000")
    result = await hass.config_entries.flow.async_init(
        const.DOMAIN, context={"source": config_entries.SOURCE_USER}
    )

    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert result["step_id"] == "add_next_config_entry"
    assert result["errors"] == {}

    result = await hass.config_entries.flow.async_configure(
        result["flow_id"],
        {"use_saved_credentials": False},
    )

    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert result["step_id"] == "auth"
    assert result["errors"] is None

    result = await hass.config_entries.flow.async_configure(
        result["flow_id"],
        {CONF_TOKEN: "token", CONF_REGION: "region", CONF_PIN: "000000"},
    )

    assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
    assert result["title"] == "<NAME>"


@mock.patch("homeassistant.components.vulcan.config_flow.Vulcan.get_students")
async def test_multiple_config_entries_using_saved_credentials(mock_student, hass):
    """Test a successful config flow for multiple config entries using saved credentials."""
    mock_student.return_value = [
        Student.load(load_fixture("fake_student_1.json", "vulcan"))
    ]
    MockConfigEntry(
        domain=const.DOMAIN,
        unique_id="123456",
        data=json.loads(load_fixture("fake_config_entry_data.json", "vulcan")),
    ).add_to_hass(hass)

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

    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert result["step_id"] == "add_next_config_entry"
    assert result["errors"] == {}

    result = await hass.config_entries.flow.async_configure(
        result["flow_id"],
        {"use_saved_credentials": True},
    )

    assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
    assert result["title"] == "<NAME>"


@mock.patch("homeassistant.components.vulcan.config_flow.Vulcan.get_students")
async def test_multiple_config_entries_using_saved_credentials_2(mock_student, hass):
    """Test a successful config flow for multiple config entries using saved credentials (different situation)."""
    mock_student.return_value = [
        Student.load(load_fixture("fake_student_1.json", "vulcan"))
    ] + [Student.load(load_fixture("fake_student_2.json", "vulcan"))]
    MockConfigEntry(
        domain=const.DOMAIN,
        unique_id="123456",
        data=json.loads(load_fixture("fake_config_entry_data.json", "vulcan")),
    ).add_to_hass(hass)

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

    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert result["step_id"] == "add_next_config_entry"
    assert result["errors"] == {}

    result = await hass.config_entries.flow.async_configure(
        result["flow_id"],
        {"use_saved_credentials": True},
    )

    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert result["step_id"] == "select_student"
    assert result["errors"] == {}

    result = await hass.config_entries.flow.async_configure(
        result["flow_id"],
        {"student": "0"},
    )

    assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
    assert result["title"] == "<NAME>"


@mock.patch("homeassistant.components.vulcan.config_flow.Vulcan.get_students")
async def test_multiple_config_entries_using_saved_credentials_3(mock_student, hass):
    """Test a successful config flow for multiple config entries using saved credentials."""
    mock_student.return_value = [
        Student.load(load_fixture("fake_student_1.json", "vulcan"))
    ]
    MockConfigEntry(
        entry_id="456",
        domain=const.DOMAIN,
        unique_id="234567",
        data=json.loads(load_fixture("fake_config_entry_data.json", "vulcan"))
        | {"student_id": "456"},
    ).add_to_hass(hass)
    MockConfigEntry(
        entry_id="123",
        domain=const.DOMAIN,
        unique_id="123456",
        data=json.loads(load_fixture("fake_config_entry_data.json", "vulcan")),
    ).add_to_hass(hass)

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

    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert result["step_id"] == "add_next_config_entry"
    assert result["errors"] == {}

    result = await hass.config_entries.flow.async_configure(
        result["flow_id"],
        {"use_saved_credentials": True},
    )

    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert result["step_id"] == "select_saved_credentials"
    assert result["errors"] is None

    result = await hass.config_entries.flow.async_configure(
        result["flow_id"],
        {"credentials": "123"},
    )

    assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
    assert result["title"] == "<NAME>"


@mock.patch("homeassistant.components.vulcan.config_flow.Vulcan.get_students")
async def test_multiple_config_entries_using_saved_credentials_4(mock_student, hass):
    """Test a successful config flow for multiple config entries using saved credentials (different situation)."""
    mock_student.return_value = [
        Student.load(load_fixture("fake_student_1.json", "vulcan"))
    ] + [Student.load(load_fixture("fake_student_2.json", "vulcan"))]
    MockConfigEntry(
        entry_id="456",
        domain=const.DOMAIN,
        unique_id="234567",
        data=json.loads(load_fixture("fake_config_entry_data.json", "vulcan"))
        | {"student_id": "456"},
    ).add_to_hass(hass)
    MockConfigEntry(
        entry_id="123",
        domain=const.DOMAIN,
        unique_id="123456",
        data=json.loads(load_fixture("fake_config_entry_data.json", "vulcan")),
    ).add_to_hass(hass)

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

    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert result["step_id"] == "add_next_config_entry"
    assert result["errors"] == {}

    result = await hass.config_entries.flow.async_configure(
        result["flow_id"],
        {"use_saved_credentials": True},
    )

    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert result["step_id"] == "select_saved_credentials"
    assert result["errors"] is None

    result = await hass.config_entries.flow.async_configure(
        result["flow_id"],
        {"credentials": "123"},
    )

    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert result["step_id"] == "select_student"
    assert result["errors"] == {}

    result = await hass.config_entries.flow.async_configure(
        result["flow_id"],
        {"student": "0"},
    )

    assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
    assert result["title"] == "<NAME>"


async def test_multiple_config_entries_without_valid_saved_credentials(hass):
    """Test a unsuccessful config flow for multiple config entries without valid saved credentials."""
    MockConfigEntry(
        entry_id="456",
        domain=const.DOMAIN,
        unique_id="234567",
        data=json.loads(load_fixture("fake_config_entry_data.json", "vulcan"))
        | {"student_id": "456"},
    ).add_to_hass(hass)
    MockConfigEntry(
        entry_id="123",
        domain=const.DOMAIN,
        unique_id="123456",
        data=json.loads(load_fixture("fake_config_entry_data.json", "vulcan")),
    ).add_to_hass(hass)

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

    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert result["step_id"] == "add_next_config_entry"
    assert result["errors"] == {}

    result = await hass.config_entries.flow.async_configure(
        result["flow_id"],
        {"use_saved_credentials": True},
    )
    with patch(
        "homeassistant.components.vulcan.config_flow.Vulcan.get_students",
        side_effect=VulcanAPIException("The certificate is not authorized."),
    ):
        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "select_saved_credentials"
        assert result["errors"] is None

        result = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {"credentials": "123"},
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "auth"
        assert result["errors"] == {"base": "expired_credentials"}


async def test_multiple_config_entries_using_saved_credentials_with_connections_issues(
    hass,
):
    """Test a unsuccessful config flow for multiple config entries without valid saved credentials."""
    MockConfigEntry(
        entry_id="456",
        domain=const.DOMAIN,
        unique_id="234567",
        data=json.loads(load_fixture("fake_config_entry_data.json", "vulcan"))
        | {"student_id": "456"},
    ).add_to_hass(hass)
    MockConfigEntry(
        entry_id="123",
        domain=const.DOMAIN,
        unique_id="123456",
        data=json.loads(load_fixture("fake_config_entry_data.json", "vulcan")),
    ).add_to_hass(hass)

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

    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert result["step_id"] == "add_next_config_entry"
    assert result["errors"] == {}

    result = await hass.config_entries.flow.async_configure(
        result["flow_id"],
        {"use_saved_credentials": True},
    )
    with patch(
        "homeassistant.components.vulcan.config_flow.Vulcan.get_students",
        side_effect=ClientConnectionError,
    ):
        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "select_saved_credentials"
        assert result["errors"] is None

        result = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {"credentials": "123"},
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "select_saved_credentials"
        assert result["errors"] == {"base": "cannot_connect"}


async def test_multiple_config_entries_using_saved_credentials_with_unknown_error(hass):
    """Test a unsuccessful config flow for multiple config entries without valid saved credentials."""
    MockConfigEntry(
        entry_id="456",
        domain=const.DOMAIN,
        unique_id="234567",
        data=json.loads(load_fixture("fake_config_entry_data.json", "vulcan"))
        | {"student_id": "456"},
    ).add_to_hass(hass)
    MockConfigEntry(
        entry_id="123",
        domain=const.DOMAIN,
        unique_id="123456",
        data=json.loads(load_fixture("fake_config_entry_data.json", "vulcan")),
    ).add_to_hass(hass)

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

    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert result["step_id"] == "add_next_config_entry"
    assert result["errors"] == {}

    result = await hass.config_entries.flow.async_configure(
        result["flow_id"],
        {"use_saved_credentials": True},
    )
    with patch(
        "homeassistant.components.vulcan.config_flow.Vulcan.get_students",
        side_effect=Exception,
    ):
        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "select_saved_credentials"
        assert result["errors"] is None

        result = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {"credentials": "123"},
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "auth"
        assert result["errors"] == {"base": "unknown"}


async def test_multiple_config_entries_using_saved_credentials_with_unknown_api_error(
    hass,
):
    """Test a unsuccessful config flow for multiple config entries without valid saved credentials."""
    MockConfigEntry(
        entry_id="456",
        domain=const.DOMAIN,
        unique_id="234567",
        data=json.loads(load_fixture("fake_config_entry_data.json", "vulcan"))
        | {"student_id": "456"},
    ).add_to_hass(hass)
    MockConfigEntry(
        entry_id="123",
        domain=const.DOMAIN,
        unique_id="123456",
        data=json.loads(load_fixture("fake_config_entry_data.json", "vulcan")),
    ).add_to_hass(hass)

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

    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert result["step_id"] == "add_next_config_entry"
    assert result["errors"] == {}

    result = await hass.config_entries.flow.async_configure(
        result["flow_id"],
        {"use_saved_credentials": True},
    )
    with patch(
        "homeassistant.components.vulcan.config_flow.Vulcan.get_students",
        side_effect=VulcanAPIException("Unknown error"),
    ):
        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "select_saved_credentials"
        assert result["errors"] is None

        result = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {"credentials": "123"},
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "auth"
        assert result["errors"] == {"base": "unknown"}


@mock.patch("homeassistant.components.vulcan.config_flow.Vulcan.get_students")
@mock.patch("homeassistant.components.vulcan.config_flow.Keystore.create")
@mock.patch("homeassistant.components.vulcan.config_flow.Account.register")
async def test_student_already_exists(mock_account, mock_keystore, mock_student, hass):
    """Test config entry when student's entry already exists."""
    mock_keystore.return_value = fake_keystore
    mock_account.return_value = fake_account
    mock_student.return_value = [
        Student.load(load_fixture("fake_student_1.json", "vulcan"))
    ]
    MockConfigEntry(
        domain=const.DOMAIN,
        unique_id="0",
        data=json.loads(load_fixture("fake_config_entry_data.json", "vulcan"))
        | {"student_id": "0"},
    ).add_to_hass(hass)

    await register.register(hass, "token", "region", "000000")

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

    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert result["step_id"] == "add_next_config_entry"
    assert result["errors"] == {}

    result = await hass.config_entries.flow.async_configure(
        result["flow_id"],
        {"use_saved_credentials": True},
    )

    assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
    assert result["reason"] == "all_student_already_configured"


@mock.patch("homeassistant.components.vulcan.config_flow.Keystore.create")
async def test_config_flow_auth_invalid_token(mock_keystore, hass):
    """Test a config flow initialized by the user using invalid token."""
    mock_keystore.return_value = fake_keystore
    with patch(
        "homeassistant.components.vulcan.config_flow.Account.register",
        side_effect=VulcanAPIException("Invalid token."),
    ):
        result = await hass.config_entries.flow.async_init(
            const.DOMAIN, context={"source": config_entries.SOURCE_USER}
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "auth"
        assert result["errors"] is None

        result = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {CONF_TOKEN: "<PASSWORD>", CONF_REGION: "region", CONF_PIN: "000000"},
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "auth"
        assert result["errors"] == {"base": "invalid_token"}


@mock.patch("homeassistant.components.vulcan.config_flow.Keystore.create")
async def test_config_flow_auth_invalid_region(mock_keystore, hass):
    """Test a config flow initialized by the user using invalid region."""
    mock_keystore.return_value = fake_keystore
    with patch(
        "homeassistant.components.vulcan.config_flow.Account.register",
        side_effect=RuntimeError("Internal Server Error (ArgumentException)"),
    ):
        result = await hass.config_entries.flow.async_init(
            const.DOMAIN, context={"source": config_entries.SOURCE_USER}
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "auth"
        assert result["errors"] is None

        result = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {CONF_TOKEN: "<PASSWORD>", CONF_REGION: "invalid_region", CONF_PIN: "000000"},
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "auth"
        assert result["errors"] == {"base": "invalid_symbol"}


@mock.patch("homeassistant.components.vulcan.config_flow.Keystore.create")
async def test_config_flow_auth_invalid_pin(mock_keystore, hass):
    """Test a config flow initialized by the with invalid pin."""
    mock_keystore.return_value = fake_keystore
    with patch(
        "homeassistant.components.vulcan.config_flow.Account.register",
        side_effect=VulcanAPIException("Invalid PIN."),
    ):
        result = await hass.config_entries.flow.async_init(
            const.DOMAIN, context={"source": config_entries.SOURCE_USER}
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "auth"
        assert result["errors"] is None

        result = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {CONF_TOKEN: "3<PASSWORD>", CONF_REGION: "region", CONF_PIN: "000000"},
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "auth"
        assert result["errors"] == {"base": "invalid_pin"}


@mock.patch("homeassistant.components.vulcan.config_flow.Keystore.create")
async def test_config_flow_auth_expired_token(mock_keystore, hass):
    """Test a config flow initialized by the with expired token."""
    mock_keystore.return_value = fake_keystore
    with patch(
        "homeassistant.components.vulcan.config_flow.Account.register",
        side_effect=VulcanAPIException("Expired token."),
    ):
        result = await hass.config_entries.flow.async_init(
            const.DOMAIN, context={"source": config_entries.SOURCE_USER}
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "auth"
        assert result["errors"] is None

        result = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {CONF_TOKEN: "<PASSWORD>", CONF_REGION: "region", CONF_PIN: "000000"},
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "auth"
        assert result["errors"] == {"base": "expired_token"}


@mock.patch("homeassistant.components.vulcan.config_flow.Keystore.create")
async def test_config_flow_auth_api_unknown_error(mock_keystore, hass):
    """Test a config flow with unknown API error."""
    mock_keystore.return_value = fake_keystore
    with patch(
        "homeassistant.components.vulcan.config_flow.Account.register",
        side_effect=VulcanAPIException("Unknown error"),
    ):
        result = await hass.config_entries.flow.async_init(
            const.DOMAIN, context={"source": config_entries.SOURCE_USER}
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "auth"
        assert result["errors"] is None

        result = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {CONF_TOKEN: "<PASSWORD>", CONF_REGION: "region", CONF_PIN: "000000"},
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "auth"
        assert result["errors"] == {"base": "unknown"}


@mock.patch("homeassistant.components.vulcan.config_flow.Keystore.create")
async def test_config_flow_auth_api_unknown_runtime_error(mock_keystore, hass):
    """Test a config flow with runtime error."""
    mock_keystore.return_value = fake_keystore
    with patch(
        "homeassistant.components.vulcan.config_flow.Account.register",
        side_effect=RuntimeError("Unknown error"),
    ):
        result = await hass.config_entries.flow.async_init(
            const.DOMAIN, context={"source": config_entries.SOURCE_USER}
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "auth"
        assert result["errors"] is None

        result = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {CONF_TOKEN: "3<PASSWORD>", CONF_REGION: "region", CONF_PIN: "000000"},
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "auth"
        assert result["errors"] == {"base": "unknown"}


@mock.patch("homeassistant.components.vulcan.config_flow.Keystore.create")
async def test_config_flow_auth_connection_error(mock_keystore, hass):
    """Test a config flow with connection error."""
    mock_keystore.return_value = fake_keystore
    with patch(
        "homeassistant.components.vulcan.config_flow.Account.register",
        side_effect=ClientConnectionError,
    ):
        result = await hass.config_entries.flow.async_init(
            const.DOMAIN, context={"source": config_entries.SOURCE_USER}
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "auth"
        assert result["errors"] is None

        result = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {CONF_TOKEN: "3S<PASSWORD>", CONF_REGION: "region", CONF_PIN: "000000"},
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "auth"
        assert result["errors"] == {"base": "cannot_connect"}


@mock.patch("homeassistant.components.vulcan.config_flow.Keystore.create")
async def test_config_flow_auth_unknown_error(mock_keystore, hass):
    """Test a config flow with unknown error."""
    mock_keystore.return_value = fake_keystore
    with patch(
        "homeassistant.components.vulcan.config_flow.Account.register",
        side_effect=Exception,
    ):
        result = await hass.config_entries.flow.async_init(
            const.DOMAIN, context={"source": config_entries.SOURCE_USER}
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "auth"
        assert result["errors"] is None

        result = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {CONF_TOKEN: "<PASSWORD>", CONF_REGION: "invalid_region", CONF_PIN: "000000"},
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "auth"
        assert result["errors"] == {"base": "unknown"}


@mock.patch("homeassistant.components.vulcan.Vulcan.get_students")
async def test_options_flow(mock_student, hass):
    """Test config flow options."""
    mock_student.return_value = [
        Student.load(load_fixture("fake_student_1.json", "vulcan"))
    ]
    config_entry = MockConfigEntry(
        domain=const.DOMAIN,
        unique_id="0",
        data=json.loads(load_fixture("fake_config_entry_data.json", "vulcan")),
    )
    config_entry.add_to_hass(hass)

    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)

    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert result["step_id"] == "init"

    result = await hass.config_entries.options.async_configure(
        result["flow_id"], user_input={CONF_SCAN_INTERVAL: 2137}
    )

    assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
    assert config_entry.options == {CONF_SCAN_INTERVAL: 2137}

"""Test the Uonet+ Vulcan config flow."""
import json
from unittest import mock
from unittest.mock import patch

from vulcan import Account
from vulcan.model import Student

from homeassistant import config_entries, data_entry_flow
from homeassistant.components.vulcan import config_flow, const, register
from homeassistant.components.vulcan.config_flow import (
    ClientConnectionError,
    Keystore,
    VulcanAPIException,
)
from homeassistant.const import CONF_PIN, CONF_REGION, CONF_SCAN_INTERVAL, CONF_TOKEN

from tests.common import MockConfigEntry, load_fixture

fake_keystore = Keystore("", "", "", "", "")
fake_account = Account(
    login_id=1,
    user_login="<EMAIL>",
    user_name="<EMAIL>",
    rest_url="rest_url",
)


async def test_show_form(hass):
    """Test that the form is served with no input."""
    flow = config_flow.VulcanFlowHandler()
    flow.hass = hass

    result = await flow.async_step_user(user_input=None)

    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert result["step_id"] == "auth"


@mock.patch("homeassistant.components.vulcan.config_flow.Vulcan.get_students")
@mock.patch("homeassistant.components.vulcan.config_flow.Account.register")
@mock.patch("homeassistant.components.vulcan.config_flow.Keystore.create")
async def test_config_flow_auth_success(
    mock_keystore, mock_account, mock_student, hass
):
    """Test a successful config flow initialized by the user."""
    mock_keystore.return_value = fake_keystore
    mock_account.return_value = fake_account
    mock_student.return_value = [
        Student.load(load_fixture("fake_student_1.json", "vulcan"))
    ]
    result = await hass.config_entries.flow.async_init(
        const.DOMAIN, context={"source": config_entries.SOURCE_USER}
    )

    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert result["step_id"] == "auth"
    assert result["errors"] is None
    result = await hass.config_entries.flow.async_configure(
        result["flow_id"],
        {CONF_TOKEN: "token", CONF_REGION: "region", CONF_PIN: "000000"},
    )

    assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
    assert result["title"] == "<NAME>"


@mock.patch("homeassistant.components.vulcan.config_flow.Vulcan.get_students")
@mock.patch("homeassistant.components.vulcan.config_flow.Account.register")
@mock.patch("homeassistant.components.vulcan.config_flow.Keystore.create")
async def test_config_flow_auth_success_with_multiple_students(
    mock_keystore, mock_account, mock_student, hass
):
    """Test a successful config flow with multiple students."""
    mock_keystore.return_value = fake_keystore
    mock_account.return_value = fake_account
    mock_student.return_value = [
        Student.load(student)
        for student in [load_fixture("fake_student_1.json", "vulcan")]
        + [load_fixture("fake_student_2.json", "vulcan")]
    ]
    result = await hass.config_entries.flow.async_init(
        const.DOMAIN, context={"source": config_entries.SOURCE_USER}
    )

    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert result["step_id"] == "auth"
    assert result["errors"] is None

    result = await hass.config_entries.flow.async_configure(
        result["flow_id"],
        {CONF_TOKEN: "token", CONF_REGION: "region", CONF_PIN: "000000"},
    )

    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert result["step_id"] == "select_student"
    assert result["errors"] == {}

    result = await hass.config_entries.flow.async_configure(
        result["flow_id"],
        {"student": "0"},
    )

    assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
    assert result["title"] == "<NAME>"


@mock.patch("homeassistant.components.vulcan.config_flow.Vulcan.get_students")
@mock.patch("homeassistant.components.vulcan.config_flow.Keystore.create")
@mock.patch("homeassistant.components.vulcan.config_flow.Account.register")
async def test_config_flow_reauth_success(
    mock_account, mock_keystore, mock_student, hass
):
    """Test a successful config flow reauth."""
    mock_keystore.return_value = fake_keystore
    mock_account.return_value = fake_account
    mock_student.return_value = [
        Student.load(load_fixture("fake_student_1.json", "vulcan"))
    ]
    MockConfigEntry(
        domain=const.DOMAIN,
        unique_id="0",
        data={"student_id": "0", "login": "<EMAIL>"},
    ).add_to_hass(hass)
    result = await hass.config_entries.flow.async_init(
        const.DOMAIN, context={"source": config_entries.SOURCE_REAUTH}
    )

    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert result["step_id"] == "reauth"
    assert result["errors"] == {}

    result = await hass.config_entries.flow.async_configure(
        result["flow_id"],
        {CONF_TOKEN: "token", CONF_REGION: "region", CONF_PIN: "000000"},
    )

    assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
    assert result["reason"] == "reauth_successful"


@mock.patch("homeassistant.components.vulcan.config_flow.Keystore.create")
@mock.patch("homeassistant.components.vulcan.config_flow.Account.register")
async def test_config_flow_reauth_with_errors(mock_account, mock_keystore, hass):
    """Test reauth config flow with errors."""
    mock_keystore.return_value = fake_keystore
    mock_account.return_value = fake_account
    result = await hass.config_entries.flow.async_init(
        const.DOMAIN, context={"source": config_entries.SOURCE_REAUTH}
    )
    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert result["step_id"] == "reauth"
    assert result["errors"] == {}
    with patch(
        "homeassistant.components.vulcan.config_flow.Account.register",
        side_effect=VulcanAPIException("Invalid token."),
    ):

        result = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {CONF_TOKEN: "token", CONF_REGION: "region", CONF_PIN: "000000"},
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "reauth"
        assert result["errors"] == {"base": "invalid_token"}

    with patch(
        "homeassistant.components.vulcan.config_flow.Account.register",
        side_effect=VulcanAPIException("Expired token."),
    ):

        result = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {CONF_TOKEN: "token", CONF_REGION: "region", CONF_PIN: "000000"},
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "reauth"
        assert result["errors"] == {"base": "expired_token"}

    with patch(
        "homeassistant.components.vulcan.config_flow.Account.register",
        side_effect=VulcanAPIException("Invalid PIN."),
    ):

        result = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {CONF_TOKEN: "token", CONF_REGION: "region", CONF_PIN: "000000"},
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "reauth"
        assert result["errors"] == {"base": "invalid_pin"}

    with patch(
        "homeassistant.components.vulcan.config_flow.Account.register",
        side_effect=VulcanAPIException("Unknown error"),
    ):

        result = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {CONF_TOKEN: "token", CONF_REGION: "region", CONF_PIN: "000000"},
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "reauth"
        assert result["errors"] == {"base": "unknown"}

    with patch(
        "homeassistant.components.vulcan.config_flow.Account.register",
        side_effect=RuntimeError("Internal Server Error (ArgumentException)"),
    ):

        result = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {CONF_TOKEN: "token", CONF_REGION: "region", CONF_PIN: "000000"},
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "reauth"
        assert result["errors"] == {"base": "invalid_symbol"}

    with patch(
        "homeassistant.components.vulcan.config_flow.Account.register",
        side_effect=RuntimeError("Unknown error"),
    ):

        result = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {CONF_TOKEN: "token", CONF_REGION: "region", CONF_PIN: "000000"},
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "reauth"
        assert result["errors"] == {"base": "unknown"}

    with patch(
        "homeassistant.components.vulcan.config_flow.Account.register",
        side_effect=ClientConnectionError,
    ):

        result = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {CONF_TOKEN: "token", CONF_REGION: "region", CONF_PIN: "000000"},
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "reauth"
        assert result["errors"] == {"base": "cannot_connect"}

    with patch(
        "homeassistant.components.vulcan.config_flow.Account.register",
        side_effect=Exception,
    ):

        result = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {CONF_TOKEN: "token", CONF_REGION: "region", CONF_PIN: "000000"},
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "reauth"
        assert result["errors"] == {"base": "unknown"}


@mock.patch("homeassistant.components.vulcan.config_flow.Vulcan.get_students")
@mock.patch("homeassistant.components.vulcan.config_flow.Keystore.create")
@mock.patch("homeassistant.components.vulcan.config_flow.Account.register")
async def test_multiple_config_entries(mock_account, mock_keystore, mock_student, hass):
    """Test a successful config flow for multiple config entries."""
    mock_keystore.return_value = fake_keystore
    mock_account.return_value = fake_account
    mock_student.return_value = [
        Student.load(load_fixture("fake_student_1.json", "vulcan"))
    ]
    MockConfigEntry(
        domain=const.DOMAIN,
        unique_id="123456",
        data=json.loads(load_fixture("fake_config_entry_data.json", "vulcan")),
    ).add_to_hass(hass)
    await register.register(hass, "token", "region", "000000")
    result = await hass.config_entries.flow.async_init(
        const.DOMAIN, context={"source": config_entries.SOURCE_USER}
    )

    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert result["step_id"] == "add_next_config_entry"
    assert result["errors"] == {}

    result = await hass.config_entries.flow.async_configure(
        result["flow_id"],
        {"use_saved_credentials": False},
    )

    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert result["step_id"] == "auth"
    assert result["errors"] is None

    result = await hass.config_entries.flow.async_configure(
        result["flow_id"],
        {CONF_TOKEN: "token", CONF_REGION: "region", CONF_PIN: "000000"},
    )

    assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
    assert result["title"] == "<NAME>"


@mock.patch("homeassistant.components.vulcan.config_flow.Vulcan.get_students")
async def test_multiple_config_entries_using_saved_credentials(mock_student, hass):
    """Test a successful config flow for multiple config entries using saved credentials."""
    mock_student.return_value = [
        Student.load(load_fixture("fake_student_1.json", "vulcan"))
    ]
    MockConfigEntry(
        domain=const.DOMAIN,
        unique_id="123456",
        data=json.loads(load_fixture("fake_config_entry_data.json", "vulcan")),
    ).add_to_hass(hass)

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

    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert result["step_id"] == "add_next_config_entry"
    assert result["errors"] == {}

    result = await hass.config_entries.flow.async_configure(
        result["flow_id"],
        {"use_saved_credentials": True},
    )

    assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
    assert result["title"] == "<NAME>"


@mock.patch("homeassistant.components.vulcan.config_flow.Vulcan.get_students")
async def test_multiple_config_entries_using_saved_credentials_2(mock_student, hass):
    """Test a successful config flow for multiple config entries using saved credentials (different situation)."""
    mock_student.return_value = [
        Student.load(load_fixture("fake_student_1.json", "vulcan"))
    ] + [Student.load(load_fixture("fake_student_2.json", "vulcan"))]
    MockConfigEntry(
        domain=const.DOMAIN,
        unique_id="123456",
        data=json.loads(load_fixture("fake_config_entry_data.json", "vulcan")),
    ).add_to_hass(hass)

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

    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert result["step_id"] == "add_next_config_entry"
    assert result["errors"] == {}

    result = await hass.config_entries.flow.async_configure(
        result["flow_id"],
        {"use_saved_credentials": True},
    )

    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert result["step_id"] == "select_student"
    assert result["errors"] == {}

    result = await hass.config_entries.flow.async_configure(
        result["flow_id"],
        {"student": "0"},
    )

    assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
    assert result["title"] == "<NAME>"


@mock.patch("homeassistant.components.vulcan.config_flow.Vulcan.get_students")
async def test_multiple_config_entries_using_saved_credentials_3(mock_student, hass):
    """Test a successful config flow for multiple config entries using saved credentials."""
    mock_student.return_value = [
        Student.load(load_fixture("fake_student_1.json", "vulcan"))
    ]
    MockConfigEntry(
        entry_id="456",
        domain=const.DOMAIN,
        unique_id="234567",
        data=json.loads(load_fixture("fake_config_entry_data.json", "vulcan"))
        | {"student_id": "456"},
    ).add_to_hass(hass)
    MockConfigEntry(
        entry_id="123",
        domain=const.DOMAIN,
        unique_id="123456",
        data=json.loads(load_fixture("fake_config_entry_data.json", "vulcan")),
    ).add_to_hass(hass)

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

    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert result["step_id"] == "add_next_config_entry"
    assert result["errors"] == {}

    result = await hass.config_entries.flow.async_configure(
        result["flow_id"],
        {"use_saved_credentials": True},
    )

    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert result["step_id"] == "select_saved_credentials"
    assert result["errors"] is None

    result = await hass.config_entries.flow.async_configure(
        result["flow_id"],
        {"credentials": "123"},
    )

    assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
    assert result["title"] == "<NAME>"


@mock.patch("homeassistant.components.vulcan.config_flow.Vulcan.get_students")
async def test_multiple_config_entries_using_saved_credentials_4(mock_student, hass):
    """Test a successful config flow for multiple config entries using saved credentials (different situation)."""
    mock_student.return_value = [
        Student.load(load_fixture("fake_student_1.json", "vulcan"))
    ] + [Student.load(load_fixture("fake_student_2.json", "vulcan"))]
    MockConfigEntry(
        entry_id="456",
        domain=const.DOMAIN,
        unique_id="234567",
        data=json.loads(load_fixture("fake_config_entry_data.json", "vulcan"))
        | {"student_id": "456"},
    ).add_to_hass(hass)
    MockConfigEntry(
        entry_id="123",
        domain=const.DOMAIN,
        unique_id="123456",
        data=json.loads(load_fixture("fake_config_entry_data.json", "vulcan")),
    ).add_to_hass(hass)

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

    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert result["step_id"] == "add_next_config_entry"
    assert result["errors"] == {}

    result = await hass.config_entries.flow.async_configure(
        result["flow_id"],
        {"use_saved_credentials": True},
    )

    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert result["step_id"] == "select_saved_credentials"
    assert result["errors"] is None

    result = await hass.config_entries.flow.async_configure(
        result["flow_id"],
        {"credentials": "123"},
    )

    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert result["step_id"] == "select_student"
    assert result["errors"] == {}

    result = await hass.config_entries.flow.async_configure(
        result["flow_id"],
        {"student": "0"},
    )

    assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
    assert result["title"] == "<NAME>"


async def test_multiple_config_entries_without_valid_saved_credentials(hass):
    """Test a unsuccessful config flow for multiple config entries without valid saved credentials."""
    MockConfigEntry(
        entry_id="456",
        domain=const.DOMAIN,
        unique_id="234567",
        data=json.loads(load_fixture("fake_config_entry_data.json", "vulcan"))
        | {"student_id": "456"},
    ).add_to_hass(hass)
    MockConfigEntry(
        entry_id="123",
        domain=const.DOMAIN,
        unique_id="123456",
        data=json.loads(load_fixture("fake_config_entry_data.json", "vulcan")),
    ).add_to_hass(hass)

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

    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert result["step_id"] == "add_next_config_entry"
    assert result["errors"] == {}

    result = await hass.config_entries.flow.async_configure(
        result["flow_id"],
        {"use_saved_credentials": True},
    )
    with patch(
        "homeassistant.components.vulcan.config_flow.Vulcan.get_students",
        side_effect=VulcanAPIException("The certificate is not authorized."),
    ):
        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "select_saved_credentials"
        assert result["errors"] is None

        result = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {"credentials": "123"},
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "auth"
        assert result["errors"] == {"base": "expired_credentials"}


async def test_multiple_config_entries_using_saved_credentials_with_connections_issues(
    hass,
):
    """Test a unsuccessful config flow for multiple config entries without valid saved credentials."""
    MockConfigEntry(
        entry_id="456",
        domain=const.DOMAIN,
        unique_id="234567",
        data=json.loads(load_fixture("fake_config_entry_data.json", "vulcan"))
        | {"student_id": "456"},
    ).add_to_hass(hass)
    MockConfigEntry(
        entry_id="123",
        domain=const.DOMAIN,
        unique_id="123456",
        data=json.loads(load_fixture("fake_config_entry_data.json", "vulcan")),
    ).add_to_hass(hass)

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

    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert result["step_id"] == "add_next_config_entry"
    assert result["errors"] == {}

    result = await hass.config_entries.flow.async_configure(
        result["flow_id"],
        {"use_saved_credentials": True},
    )
    with patch(
        "homeassistant.components.vulcan.config_flow.Vulcan.get_students",
        side_effect=ClientConnectionError,
    ):
        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "select_saved_credentials"
        assert result["errors"] is None

        result = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {"credentials": "123"},
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "select_saved_credentials"
        assert result["errors"] == {"base": "cannot_connect"}


async def test_multiple_config_entries_using_saved_credentials_with_unknown_error(hass):
    """Test a unsuccessful config flow for multiple config entries without valid saved credentials."""
    MockConfigEntry(
        entry_id="456",
        domain=const.DOMAIN,
        unique_id="234567",
        data=json.loads(load_fixture("fake_config_entry_data.json", "vulcan"))
        | {"student_id": "456"},
    ).add_to_hass(hass)
    MockConfigEntry(
        entry_id="123",
        domain=const.DOMAIN,
        unique_id="123456",
        data=json.loads(load_fixture("fake_config_entry_data.json", "vulcan")),
    ).add_to_hass(hass)

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

    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert result["step_id"] == "add_next_config_entry"
    assert result["errors"] == {}

    result = await hass.config_entries.flow.async_configure(
        result["flow_id"],
        {"use_saved_credentials": True},
    )
    with patch(
        "homeassistant.components.vulcan.config_flow.Vulcan.get_students",
        side_effect=Exception,
    ):
        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "select_saved_credentials"
        assert result["errors"] is None

        result = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {"credentials": "123"},
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "auth"
        assert result["errors"] == {"base": "unknown"}


async def test_multiple_config_entries_using_saved_credentials_with_unknown_api_error(
    hass,
):
    """Test a unsuccessful config flow for multiple config entries without valid saved credentials."""
    MockConfigEntry(
        entry_id="456",
        domain=const.DOMAIN,
        unique_id="234567",
        data=json.loads(load_fixture("fake_config_entry_data.json", "vulcan"))
        | {"student_id": "456"},
    ).add_to_hass(hass)
    MockConfigEntry(
        entry_id="123",
        domain=const.DOMAIN,
        unique_id="123456",
        data=json.loads(load_fixture("fake_config_entry_data.json", "vulcan")),
    ).add_to_hass(hass)

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

    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert result["step_id"] == "add_next_config_entry"
    assert result["errors"] == {}

    result = await hass.config_entries.flow.async_configure(
        result["flow_id"],
        {"use_saved_credentials": True},
    )
    with patch(
        "homeassistant.components.vulcan.config_flow.Vulcan.get_students",
        side_effect=VulcanAPIException("Unknown error"),
    ):
        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "select_saved_credentials"
        assert result["errors"] is None

        result = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {"credentials": "123"},
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "auth"
        assert result["errors"] == {"base": "unknown"}


@mock.patch("homeassistant.components.vulcan.config_flow.Vulcan.get_students")
@mock.patch("homeassistant.components.vulcan.config_flow.Keystore.create")
@mock.patch("homeassistant.components.vulcan.config_flow.Account.register")
async def test_student_already_exists(mock_account, mock_keystore, mock_student, hass):
    """Test config entry when student's entry already exists."""
    mock_keystore.return_value = fake_keystore
    mock_account.return_value = fake_account
    mock_student.return_value = [
        Student.load(load_fixture("fake_student_1.json", "vulcan"))
    ]
    MockConfigEntry(
        domain=const.DOMAIN,
        unique_id="0",
        data=json.loads(load_fixture("fake_config_entry_data.json", "vulcan"))
        | {"student_id": "0"},
    ).add_to_hass(hass)

    await register.register(hass, "token", "region", "000000")

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

    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert result["step_id"] == "add_next_config_entry"
    assert result["errors"] == {}

    result = await hass.config_entries.flow.async_configure(
        result["flow_id"],
        {"use_saved_credentials": True},
    )

    assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
    assert result["reason"] == "all_student_already_configured"


@mock.patch("homeassistant.components.vulcan.config_flow.Keystore.create")
async def test_config_flow_auth_invalid_token(mock_keystore, hass):
    """Test a config flow initialized by the user using invalid token."""
    mock_keystore.return_value = fake_keystore
    with patch(
        "homeassistant.components.vulcan.config_flow.Account.register",
        side_effect=VulcanAPIException("Invalid token."),
    ):
        result = await hass.config_entries.flow.async_init(
            const.DOMAIN, context={"source": config_entries.SOURCE_USER}
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "auth"
        assert result["errors"] is None

        result = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {CONF_TOKEN: "<PASSWORD>", CONF_REGION: "region", CONF_PIN: "000000"},
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "auth"
        assert result["errors"] == {"base": "invalid_token"}


@mock.patch("homeassistant.components.vulcan.config_flow.Keystore.create")
async def test_config_flow_auth_invalid_region(mock_keystore, hass):
    """Test a config flow initialized by the user using invalid region."""
    mock_keystore.return_value = fake_keystore
    with patch(
        "homeassistant.components.vulcan.config_flow.Account.register",
        side_effect=RuntimeError("Internal Server Error (ArgumentException)"),
    ):
        result = await hass.config_entries.flow.async_init(
            const.DOMAIN, context={"source": config_entries.SOURCE_USER}
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "auth"
        assert result["errors"] is None

        result = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {CONF_TOKEN: "<PASSWORD>", CONF_REGION: "invalid_region", CONF_PIN: "000000"},
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "auth"
        assert result["errors"] == {"base": "invalid_symbol"}


@mock.patch("homeassistant.components.vulcan.config_flow.Keystore.create")
async def test_config_flow_auth_invalid_pin(mock_keystore, hass):
    """Test a config flow initialized by the with invalid pin."""
    mock_keystore.return_value = fake_keystore
    with patch(
        "homeassistant.components.vulcan.config_flow.Account.register",
        side_effect=VulcanAPIException("Invalid PIN."),
    ):
        result = await hass.config_entries.flow.async_init(
            const.DOMAIN, context={"source": config_entries.SOURCE_USER}
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "auth"
        assert result["errors"] is None

        result = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {CONF_TOKEN: "3<PASSWORD>", CONF_REGION: "region", CONF_PIN: "000000"},
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "auth"
        assert result["errors"] == {"base": "invalid_pin"}


@mock.patch("homeassistant.components.vulcan.config_flow.Keystore.create")
async def test_config_flow_auth_expired_token(mock_keystore, hass):
    """Test a config flow initialized by the with expired token."""
    mock_keystore.return_value = fake_keystore
    with patch(
        "homeassistant.components.vulcan.config_flow.Account.register",
        side_effect=VulcanAPIException("Expired token."),
    ):
        result = await hass.config_entries.flow.async_init(
            const.DOMAIN, context={"source": config_entries.SOURCE_USER}
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "auth"
        assert result["errors"] is None

        result = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {CONF_TOKEN: "<PASSWORD>", CONF_REGION: "region", CONF_PIN: "000000"},
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "auth"
        assert result["errors"] == {"base": "expired_token"}


@mock.patch("homeassistant.components.vulcan.config_flow.Keystore.create")
async def test_config_flow_auth_api_unknown_error(mock_keystore, hass):
    """Test a config flow with unknown API error."""
    mock_keystore.return_value = fake_keystore
    with patch(
        "homeassistant.components.vulcan.config_flow.Account.register",
        side_effect=VulcanAPIException("Unknown error"),
    ):
        result = await hass.config_entries.flow.async_init(
            const.DOMAIN, context={"source": config_entries.SOURCE_USER}
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "auth"
        assert result["errors"] is None

        result = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {CONF_TOKEN: "<PASSWORD>", CONF_REGION: "region", CONF_PIN: "000000"},
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "auth"
        assert result["errors"] == {"base": "unknown"}


@mock.patch("homeassistant.components.vulcan.config_flow.Keystore.create")
async def test_config_flow_auth_api_unknown_runtime_error(mock_keystore, hass):
    """Test a config flow with runtime error."""
    mock_keystore.return_value = fake_keystore
    with patch(
        "homeassistant.components.vulcan.config_flow.Account.register",
        side_effect=RuntimeError("Unknown error"),
    ):
        result = await hass.config_entries.flow.async_init(
            const.DOMAIN, context={"source": config_entries.SOURCE_USER}
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "auth"
        assert result["errors"] is None

        result = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {CONF_TOKEN: "3<PASSWORD>", CONF_REGION: "region", CONF_PIN: "000000"},
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "auth"
        assert result["errors"] == {"base": "unknown"}


@mock.patch("homeassistant.components.vulcan.config_flow.Keystore.create")
async def test_config_flow_auth_connection_error(mock_keystore, hass):
    """Test a config flow with connection error."""
    mock_keystore.return_value = fake_keystore
    with patch(
        "homeassistant.components.vulcan.config_flow.Account.register",
        side_effect=ClientConnectionError,
    ):
        result = await hass.config_entries.flow.async_init(
            const.DOMAIN, context={"source": config_entries.SOURCE_USER}
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "auth"
        assert result["errors"] is None

        result = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {CONF_TOKEN: "3S<PASSWORD>", CONF_REGION: "region", CONF_PIN: "000000"},
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "auth"
        assert result["errors"] == {"base": "cannot_connect"}


@mock.patch("homeassistant.components.vulcan.config_flow.Keystore.create")
async def test_config_flow_auth_unknown_error(mock_keystore, hass):
    """Test a config flow with unknown error."""
    mock_keystore.return_value = fake_keystore
    with patch(
        "homeassistant.components.vulcan.config_flow.Account.register",
        side_effect=Exception,
    ):
        result = await hass.config_entries.flow.async_init(
            const.DOMAIN, context={"source": config_entries.SOURCE_USER}
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "auth"
        assert result["errors"] is None

        result = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {CONF_TOKEN: "<PASSWORD>", CONF_REGION: "invalid_region", CONF_PIN: "000000"},
        )

        assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
        assert result["step_id"] == "auth"
        assert result["errors"] == {"base": "unknown"}


@mock.patch("homeassistant.components.vulcan.Vulcan.get_students")
async def test_options_flow(mock_student, hass):
    """Test config flow options."""
    mock_student.return_value = [
        Student.load(load_fixture("fake_student_1.json", "vulcan"))
    ]
    config_entry = MockConfigEntry(
        domain=const.DOMAIN,
        unique_id="0",
        data=json.loads(load_fixture("fake_config_entry_data.json", "vulcan")),
    )
    config_entry.add_to_hass(hass)

    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)

    assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
    assert result["step_id"] == "init"

    result = await hass.config_entries.options.async_configure(
        result["flow_id"], user_input={CONF_SCAN_INTERVAL: 2137}
    )

    assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
    assert config_entry.options == {CONF_SCAN_INTERVAL: 2137}

Test the Uonet+ Vulcan config flow. Test that the form is served with no input. Test a successful config flow initialized by the user. Test a successful config flow with multiple students. Test a successful config flow reauth. Test reauth config flow with errors. Test a successful config flow for multiple config entries. Test a successful config flow for multiple config entries using saved credentials. Test a successful config flow for multiple config entries using saved credentials (different situation). Test a successful config flow for multiple config entries using saved credentials. Test a successful config flow for multiple config entries using saved credentials (different situation). Test a unsuccessful config flow for multiple config entries without valid saved credentials. Test a unsuccessful config flow for multiple config entries without valid saved credentials. Test a unsuccessful config flow for multiple config entries without valid saved credentials. Test a unsuccessful config flow for multiple config entries without valid saved credentials. Test config entry when student's entry already exists. Test a config flow initialized by the user using invalid token. Test a config flow initialized by the user using invalid region. Test a config flow initialized by the with invalid pin. Test a config flow initialized by the with expired token. Test a config flow with unknown API error. Test a config flow with runtime error. Test a config flow with connection error. Test a config flow with unknown error. Test config flow options.