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

from vulcan import (
    Account,
    ExpiredTokenException,
    InvalidPINException,
    InvalidSymbolException,
    InvalidTokenException,
    UnauthorizedCertificateException,
)
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
from homeassistant.const import CONF_PIN, CONF_REGION, CONF_TOKEN

from tests.common import MockConfigEntry, load_fixture

fake_keystore = Keystore("", "", "", "", "")
fake_account = Account(
    login_id=1,
    user_login="example@example.com",
    user_name="example@example.com",
    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.FlowResultType.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.FlowResultType.FORM
    assert result["step_id"] == "auth"
    assert result["errors"] is None

    with patch(
        "homeassistant.components.vulcan.async_setup_entry",
        return_value=True,
    ) as mock_setup_entry:
        result = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {CONF_TOKEN: "token", CONF_REGION: "region", CONF_PIN: "000000"},
        )
        await hass.async_block_till_done()

    assert result["type"] == data_entry_flow.FlowResultType.CREATE_ENTRY
    assert result["title"] == "Jan Kowalski"
    assert len(mock_setup_entry.mock_calls) == 1


@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.FlowResultType.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.FlowResultType.FORM
    assert result["step_id"] == "select_student"
    assert result["errors"] == {}

    with patch(
        "homeassistant.components.vulcan.async_setup_entry",
        return_value=True,
    ) as mock_setup_entry:
        result = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {"student": "0"},
        )

    assert result["type"] == data_entry_flow.FlowResultType.CREATE_ENTRY
    assert result["title"] == "Jan Kowalski"
    assert len(mock_setup_entry.mock_calls) == 1


@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"},
    ).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.FlowResultType.FORM
    assert result["step_id"] == "reauth_confirm"
    assert result["errors"] == {}

    with patch(
        "homeassistant.components.vulcan.async_setup_entry",
        return_value=True,
    ) as mock_setup_entry:
        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.FlowResultType.ABORT
    assert result["reason"] == "reauth_successful"
    assert len(mock_setup_entry.mock_calls) == 1


@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_without_matching_entries(
    mock_account, mock_keystore, mock_student, hass
):
    """Test a aborted config flow reauth caused by leak of matching 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="0",
        data={"student_id": "1"},
    ).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.FlowResultType.FORM
    assert result["step_id"] == "reauth_confirm"
    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.FlowResultType.ABORT
    assert result["reason"] == "no_matching_entries"


@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.FlowResultType.FORM
    assert result["step_id"] == "reauth_confirm"
    assert result["errors"] == {}
    with patch(
        "homeassistant.components.vulcan.config_flow.Account.register",
        side_effect=InvalidTokenException,
    ):

        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.FlowResultType.FORM
        assert result["step_id"] == "reauth_confirm"
        assert result["errors"] == {"base": "invalid_token"}

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

        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.FlowResultType.FORM
        assert result["step_id"] == "reauth_confirm"
        assert result["errors"] == {"base": "expired_token"}

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

        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.FlowResultType.FORM
        assert result["step_id"] == "reauth_confirm"
        assert result["errors"] == {"base": "invalid_pin"}

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

        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.FlowResultType.FORM
        assert result["step_id"] == "reauth_confirm"
        assert result["errors"] == {"base": "invalid_symbol"}

    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.FlowResultType.FORM
        assert result["step_id"] == "reauth_confirm"
        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.FlowResultType.FORM
        assert result["step_id"] == "reauth_confirm"
        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.FlowResultType.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.FlowResultType.FORM
    assert result["step_id"] == "auth"
    assert result["errors"] is None

    with patch(
        "homeassistant.components.vulcan.async_setup_entry",
        return_value=True,
    ) as mock_setup_entry:
        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.FlowResultType.CREATE_ENTRY
    assert result["title"] == "Jan Kowalski"
    assert len(mock_setup_entry.mock_calls) == 2


@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.FlowResultType.FORM
    assert result["step_id"] == "add_next_config_entry"
    assert result["errors"] == {}

    with patch(
        "homeassistant.components.vulcan.async_setup_entry",
        return_value=True,
    ) as mock_setup_entry:
        result = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {"use_saved_credentials": True},
        )

    assert result["type"] == data_entry_flow.FlowResultType.CREATE_ENTRY
    assert result["title"] == "Jan Kowalski"
    assert len(mock_setup_entry.mock_calls) == 2


@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.FlowResultType.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.FlowResultType.FORM
    assert result["step_id"] == "select_student"
    assert result["errors"] == {}

    with patch(
        "homeassistant.components.vulcan.async_setup_entry",
        return_value=True,
    ) as mock_setup_entry:
        result = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {"student": "0"},
        )

    assert result["type"] == data_entry_flow.FlowResultType.CREATE_ENTRY
    assert result["title"] == "Jan Kowalski"
    assert len(mock_setup_entry.mock_calls) == 2


@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.FlowResultType.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.FlowResultType.FORM
    assert result["step_id"] == "select_saved_credentials"
    assert result["errors"] is None

    with patch(
        "homeassistant.components.vulcan.async_setup_entry",
        return_value=True,
    ) as mock_setup_entry:
        result = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {"credentials": "123"},
        )

    assert result["type"] == data_entry_flow.FlowResultType.CREATE_ENTRY
    assert result["title"] == "Jan Kowalski"
    assert len(mock_setup_entry.mock_calls) == 3


@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.FlowResultType.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.FlowResultType.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.FlowResultType.FORM
    assert result["step_id"] == "select_student"
    assert result["errors"] == {}

    with patch(
        "homeassistant.components.vulcan.async_setup_entry",
        return_value=True,
    ) as mock_setup_entry:
        result = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {"student": "0"},
        )

    assert result["type"] == data_entry_flow.FlowResultType.CREATE_ENTRY
    assert result["title"] == "Jan Kowalski"
    assert len(mock_setup_entry.mock_calls) == 3


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.FlowResultType.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=UnauthorizedCertificateException,
    ):
        assert result["type"] == data_entry_flow.FlowResultType.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.FlowResultType.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.FlowResultType.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.FlowResultType.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.FlowResultType.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.FlowResultType.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.FlowResultType.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.FlowResultType.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.FlowResultType.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.FlowResultType.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=InvalidTokenException,
    ):
        result = await hass.config_entries.flow.async_init(
            const.DOMAIN, context={"source": config_entries.SOURCE_USER}
        )

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

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

        assert result["type"] == data_entry_flow.FlowResultType.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=InvalidSymbolException,
    ):
        result = await hass.config_entries.flow.async_init(
            const.DOMAIN, context={"source": config_entries.SOURCE_USER}
        )

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

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

        assert result["type"] == data_entry_flow.FlowResultType.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=InvalidPINException,
    ):
        result = await hass.config_entries.flow.async_init(
            const.DOMAIN, context={"source": config_entries.SOURCE_USER}
        )

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

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

        assert result["type"] == data_entry_flow.FlowResultType.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=ExpiredTokenException,
    ):
        result = await hass.config_entries.flow.async_init(
            const.DOMAIN, context={"source": config_entries.SOURCE_USER}
        )

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

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

        assert result["type"] == data_entry_flow.FlowResultType.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_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.FlowResultType.FORM
        assert result["step_id"] == "auth"
        assert result["errors"] is None

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

        assert result["type"] == data_entry_flow.FlowResultType.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.FlowResultType.FORM
        assert result["step_id"] == "auth"
        assert result["errors"] is None

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

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