"""Tests for homekit_controller config flow."""
import json
from unittest import mock

import homekit
import pytest

from homeassistant.components.homekit_controller import config_flow
from homeassistant.components.homekit_controller.const import KNOWN_DEVICES

from tests.common import MockConfigEntry
from tests.components.homekit_controller.common import (
    Accessory,
    FakeService,
    setup_platform,
)

PAIRING_START_FORM_ERRORS = [
    (homekit.BusyError, "busy_error"),
    (homekit.MaxTriesError, "max_tries_error"),
    (KeyError, "pairing_failed"),
]

PAIRING_START_ABORT_ERRORS = [
    (homekit.AccessoryNotFoundError, "accessory_not_found_error"),
    (homekit.UnavailableError, "already_paired"),
]

PAIRING_FINISH_FORM_ERRORS = [
    (homekit.MaxPeersError, "max_peers_error"),
    (homekit.AuthenticationError, "authentication_error"),
    (homekit.UnknownError, "unknown_error"),
    (KeyError, "pairing_failed"),
]

PAIRING_FINISH_ABORT_ERRORS = [
    (homekit.AccessoryNotFoundError, "accessory_not_found_error")
]


def _setup_flow_handler(hass):
    flow = config_flow.HomekitControllerFlowHandler()
    flow.hass = hass
    flow.context = {}

    flow.controller = mock.Mock()
    flow.controller.pairings = {}

    return flow


async def _setup_flow_zeroconf(hass, discovery_info):
    result = await hass.config_entries.flow.async_init(
        "homekit_controller", context={"source": "zeroconf"}, data=discovery_info
    )
    return result


async def test_discovery_works(hass):
    """Test a device being discovered."""
    discovery_info = {
        "name": "TestDevice",
        "host": "127.0.0.1",
        "port": 8080,
        "properties": {"md": "TestDevice", "id": "00:00:00:00:00:00", "c#": 1, "sf": 1},
    }

    flow = _setup_flow_handler(hass)

    # Device is discovered
    result = await flow.async_step_zeroconf(discovery_info)
    assert result["type"] == "form"
    assert result["step_id"] == "pair"
    assert flow.context == {
        "hkid": "00:00:00:00:00:00",
        "title_placeholders": {"name": "TestDevice"},
        "unique_id": "00:00:00:00:00:00",
    }

    # User initiates pairing - device enters pairing mode and displays code
    result = await flow.async_step_pair({})
    assert result["type"] == "form"
    assert result["step_id"] == "pair"
    assert flow.controller.start_pairing.call_count == 1

    pairing = mock.Mock(pairing_data={"AccessoryPairingID": "00:00:00:00:00:00"})

    pairing.list_accessories_and_characteristics.return_value = [
        {
            "aid": 1,
            "services": [
                {
                    "characteristics": [{"type": "23", "value": "Koogeek-LS1-20833F"}],
                    "type": "3e",
                }
            ],
        }
    ]

    # Pairing doesn't error error and pairing results
    flow.controller.pairings = {"00:00:00:00:00:00": pairing}
    result = await flow.async_step_pair({"pairing_code": "111-22-33"})
    assert result["type"] == "create_entry"
    assert result["title"] == "Koogeek-LS1-20833F"
    assert result["data"] == pairing.pairing_data


async def test_discovery_works_upper_case(hass):
    """Test a device being discovered."""
    discovery_info = {
        "name": "TestDevice",
        "host": "127.0.0.1",
        "port": 8080,
        "properties": {"MD": "TestDevice", "ID": "00:00:00:00:00:00", "C#": 1, "SF": 1},
    }

    flow = _setup_flow_handler(hass)

    # Device is discovered
    result = await flow.async_step_zeroconf(discovery_info)
    assert result["type"] == "form"
    assert result["step_id"] == "pair"
    assert flow.context == {
        "hkid": "00:00:00:00:00:00",
        "title_placeholders": {"name": "TestDevice"},
        "unique_id": "00:00:00:00:00:00",
    }

    # User initiates pairing - device enters pairing mode and displays code
    result = await flow.async_step_pair({})
    assert result["type"] == "form"
    assert result["step_id"] == "pair"
    assert flow.controller.start_pairing.call_count == 1

    pairing = mock.Mock(pairing_data={"AccessoryPairingID": "00:00:00:00:00:00"})

    pairing.list_accessories_and_characteristics.return_value = [
        {
            "aid": 1,
            "services": [
                {
                    "characteristics": [{"type": "23", "value": "Koogeek-LS1-20833F"}],
                    "type": "3e",
                }
            ],
        }
    ]

    flow.controller.pairings = {"00:00:00:00:00:00": pairing}
    result = await flow.async_step_pair({"pairing_code": "111-22-33"})
    assert result["type"] == "create_entry"
    assert result["title"] == "Koogeek-LS1-20833F"
    assert result["data"] == pairing.pairing_data


async def test_discovery_works_missing_csharp(hass):
    """Test a device being discovered that has missing mdns attrs."""
    discovery_info = {