"""Test the Smart Meter B-route config flow."""

from collections.abc import Generator
from unittest.mock import AsyncMock, Mock, patch

from momonga import MomongaSkJoinFailure, MomongaSkScanFailure
import pytest

from homeassistant.components.route_b_smart_meter.const import DOMAIN, ENTRY_TITLE
from homeassistant.components.usb import SerialDevice, USBDevice
from homeassistant.config_entries import SOURCE_USER
from homeassistant.const import CONF_DEVICE, CONF_ID, CONF_PASSWORD
from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultType


@pytest.fixture
def mock_serial_ports() -> Generator[AsyncMock]:
    """Override scan_serial_ports."""
    device = USBDevice(
        device="/dev/ttyUSB42",
        vid="1234",
        pid="5678",
        serial_number="123456",
        manufacturer="Test",
        description="Test Device",
    )

    unrelated_device = SerialDevice(
        device="/dev/ttyUSB41",
        serial_number=None,
        manufacturer=None,
        description=None,
    )

    with patch(
        "homeassistant.components.route_b_smart_meter.config_flow.async_scan_serial_ports",
        return_value=[unrelated_device, device],
    ) as mock:
        yield mock


async def test_step_user_form(
    hass: HomeAssistant,
    mock_setup_entry: AsyncMock,
    mock_serial_ports: AsyncMock,
    mock_momonga: Mock,
    user_input: dict[str, str],
) -> None:
    """Test we get the form."""
    result = await hass.config_entries.flow.async_init(
        DOMAIN, context={"source": SOURCE_USER}
    )
    assert result["type"] is FlowResultType.FORM
    assert not result["errors"]
    result = await hass.config_entries.flow.async_configure(
        result["flow_id"],
        user_input,
    )
    await hass.async_block_till_done()

    assert result["type"] is FlowResultType.CREATE_ENTRY
    assert result["title"] == ENTRY_TITLE
    assert result["data"] == user_input
    assert result["result"].unique_id == user_input[CONF_ID]
    mock_setup_entry.assert_called_once()
    mock_serial_ports.assert_called()
    mock_momonga.assert_called_once_with(
        dev=user_input[CONF_DEVICE],
        rbid=user_input[CONF_ID],
        pwd=user_input[CONF_PASSWORD],
    )


@pytest.mark.parametrize(
    ("error", "message"),
    [
        (MomongaSkJoinFailure, "invalid_auth"),
        (MomongaSkScanFailure, "cannot_connect"),
        (Exception, "unknown"),
    ],
)
@pytest.mark.usefixtures("mock_setup_entry")
async def test_step_user_form_errors(
    hass: HomeAssistant,
    error: Exception,
    message: str,
    mock_serial_ports: AsyncMock,
    mock_momonga: AsyncMock,
    user_input: dict[str, str],
) -> None:
    """Test we handle error."""
    result_init = await hass.config_entries.flow.async_init(
        DOMAIN, context={"source": SOURCE_USER}
    )
    mock_momonga.side_effect = error
    result_configure = await hass.config_entries.flow.async_configure(
        result_init["flow_id"],
        user_input,
    )

    assert result_configure["type"] is FlowResultType.FORM
    assert result_configure["errors"] == {"base": message}
    await hass.async_block_till_done()
    mock_serial_ports.assert_called()
    mock_momonga.assert_called_once_with(
        dev=user_input[CONF_DEVICE],
        rbid=user_input[CONF_ID],
        pwd=user_input[CONF_PASSWORD],
    )

    mock_momonga.side_effect = None
    result = await hass.config_entries.flow.async_configure(
        result_configure["flow_id"],
        user_input,
    )

    assert result["type"] is FlowResultType.CREATE_ENTRY
    assert result["title"] == ENTRY_TITLE
    assert result["data"] == user_input
