"""Tests for the HomeKit AID manager."""
import os
from unittest.mock import patch

from fnvhash import fnv1a_32
import pytest

from homeassistant.components.homekit.aidmanager import (
    AccessoryAidStorage,
    get_aid_storage_filename_for_entry_id,
    get_system_unique_id,
)
from homeassistant.helpers import device_registry
from homeassistant.helpers.storage import STORAGE_DIR

from tests.common import MockConfigEntry, mock_device_registry, mock_registry


@pytest.fixture
def device_reg(hass):
    """Return an empty, loaded, registry."""
    return mock_device_registry(hass)


@pytest.fixture
def entity_reg(hass):
    """Return an empty, loaded, registry."""
    return mock_registry(hass)


async def test_aid_generation(hass, device_reg, entity_reg):
    """Test generating aids."""
    config_entry = MockConfigEntry(domain="test", data={})
    config_entry.add_to_hass(hass)
    device_entry = device_reg.async_get_or_create(
        config_entry_id=config_entry.entry_id,
        connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")},
    )
    light_ent = entity_reg.async_get_or_create(
        "light", "device", "unique_id", device_id=device_entry.id
    )
    light_ent2 = entity_reg.async_get_or_create(
        "light", "device", "other_unique_id", device_id=device_entry.id
    )
    remote_ent = entity_reg.async_get_or_create(
        "remote", "device", "unique_id", device_id=device_entry.id
    )
    hass.states.async_set(light_ent.entity_id, "on")
    hass.states.async_set(light_ent2.entity_id, "on")
    hass.states.async_set(remote_ent.entity_id, "on")
    hass.states.async_set("remote.has_no_unique_id", "on")

    with patch(
        "homeassistant.components.homekit.aidmanager.AccessoryAidStorage.async_schedule_save"
    ):
        aid_storage = AccessoryAidStorage(hass, config_entry)
    await aid_storage.async_initialize()

    for _ in range(0, 2):
        assert (
            aid_storage.get_or_allocate_aid_for_entity_id(light_ent.entity_id)
            == 1953095294
        )
        assert (
            aid_storage.get_or_allocate_aid_for_entity_id(light_ent2.entity_id)
            == 1975378727
        )
        assert (
            aid_storage.get_or_allocate_aid_for_entity_id(remote_ent.entity_id)
            == 3508011530
        )
        assert (
            aid_storage.get_or_allocate_aid_for_entity_id("remote.has_no_unique_id")
            == 1751603975
        )

    aid_storage.delete_aid(get_system_unique_id(light_ent))
    aid_storage.delete_aid(get_system_unique_id(light_ent2))
    aid_storage.delete_aid(get_system_unique_id(remote_ent))
    aid_storage.delete_aid("non-existent-one")

    for _ in range(0, 2):
        assert (
            aid_storage.get_or_allocate_aid_for_entity_id(light_ent.entity_id)
            == 1953095294
        )
        assert (
            aid_storage.get_or_allocate_aid_for_entity_id(light_ent2.entity_id)
            == 1975378727
        )
        assert (
            aid_storage.get_or_allocate_aid_for_entity_id(remote_ent.entity_id)
            == 3508011530
        )
        assert (
            aid_storage.get_or_allocate_aid_for_entity_id("remote.has_no_unique_id")
            == 1751603975
        )


async def test_no_aid_collision(hass, device_reg, entity_reg):
    """Test generating aids."""
    config_entry = MockConfigEntry(domain="test", data={})
    config_entry.add_to_hass(hass)
    device_entry = device_reg.async_get_or_create(
        config_entry_id=config_entry.entry_id,
        connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")},
    )

    with patch(
        "homeassistant.components.homekit.aidmanager.AccessoryAidStorage.async_schedule_save"
    ):
        aid_storage = AccessoryAidStorage(hass, config_entry)
    await aid_storage.async_initialize()

    seen_aids = set()

    for unique_id in range(0, 202):
        ent = entity_reg.async_get_or_create(
            "light", "device", unique_id, device_id=device_entry.id
        )
        hass.states.async_set(ent.entity_id, "on")
        aid = aid_storage.get_or_allocate_aid_for_entity_id(ent.entity_id)
        assert aid not in seen_aids
        seen_aids.add(aid)


async def test_aid_generation_no_unique_ids_handles_collision(
    hass, device_reg, entity_reg
):
    """Test colliding aids is stable."""
    config_entry = MockConfigEntry(domain="test", data={})
    config_entry.add_to_hass(hass)
    aid_storage = AccessoryAidStorage(hass, config_entry)
    await aid_storage.async_initialize()

    device_entry = device_reg.async_get_or_create(
        config_entry_id=config_entry.entry_id,
        connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")},
    )

    seen_aids = set()
    collisions = []

    for light_id in range(0, 220):
        entity_id = f"light.light{light_id}"
        hass.states.async_set(entity_id, "on")
        expected_aid = fnv1a_32(entity_id.encode("utf-8"))
        aid = aid_storage.get_or_allocate_aid_for_entity_id(entity_id)
        if aid != expected_aid:
            collisions.append(entity_id)

        assert aid not in seen_aids
        seen_aids.add(aid)

    light_ent = entity_reg.async_get_or_create(
        "light", "device", "unique_id", device_id=device_entry.id
    )
    hass.states.async_set(light_ent.entity_id, "on")
    aid_storage.get_or_allocate_aid_for_entity_id(light_ent.entity_id)

    assert not collisions

    assert aid_storage.allocations == {
        "device.light.unique_id": 1953095294,
        "light.light0": 301577847,
        "light.light1": 284800228,
        "light.light10": 2367138236,
        "light.light100": 2822760292,
        "light.light101": 2839537911,
        "light.light102": 2856315530,
        "light.light103": 2873093149,
        "light.light104": 2755649816,
        "light.light105": 2772427435,
        "light.light106": 2789205054,
        "light.light107": 2805982673,
        "light.light108": 2688539340,
        "light.light109": 2705316959,
        "light.light11": 2383915855,
        "light.light110": 776141037,
        "light.light111": 759363418,
        "light.light112": 742585799,
        "light.light113": 725808180,
        "light.light114": 709030561,
        "light.light115": 692252942,
        "light.light116": 675475323,
        "light.light117": 658697704,
        "light.light118": 641920085,
        "light.light119": 625142466,
        "light.light12": 2400693474,
        "light.light120": 340070038,
        "light.light121": 356847657,
        "light.light122": 306514800,
        "light.light123": 323292419,
        "light.light124": 407180514,
        "light.light125": 423958133,
        "light.light126": 373625276,
        "light.light127": 390402895,
        "light.light128": 474290990,
        "light.light129": 491068609,
        "light.light13": 2417471093,
        "light.light130": 440882847,
        "light.light131": 424105228,
        "light.light132": 474438085,
        "light.light133": 457660466,
        "light.light134": 373772371,
        "light.light135": 356994752,
        "light.light136": 407327609,
        "light.light137": 390549990,
        "light.light138": 575103799,
        "light.light139": 558326180,
        "light.light14": 2300027760,
        "light.light140": 271973824,
        "light.light141": 288751443,
        "light.light142": 305529062,
        "light.light143": 322306681,
        "light.light144": 339084300,
        "light.light145": 355861919,
        "light.light146": 372639538,
        "light.light147": 389417157,
        "light.light148": 406194776,
        "light.light149": 422972395,
        "light.light15": 2316805379,
        "light.light150": 2520321865,
        "light.light151": 2503544246,
        "light.light152": 2486766627,
        "light.light153": 2469989008,
        "light.light154": 2587432341,
        "light.light155": 2570654722,
        "light.light156": 2553877103,
        "light.light157": 2537099484,
        "light.light158": 2654542817,
        "light.light159": 2637765198,
        "light.light16": 2333582998,
        "light.light160": 2621134674,
        "light.light161": 2637912293,
        "light.light162": 2587579436,
        "light.light163": 2604357055,
        "light.light164": 2554024198,
        "light.light165": 2570801817,
        "light.light166": 2520468960,
        "light.light167": 2537246579,
        "light.light168": 2755355626,
        "light.light169": 2772133245,
        "light.light17": 2350360617,
        "light.light170": 2721947483,
        "light.light171": 2705169864,
        "light.light172": 2755502721,
        "light.light173": 2738725102,
        "light.light174": 2789057959,
        "light.light175": 2772280340,
        "light.light176": 2822613197,
        "light.light177": 2805835578,
        "light.light178": 2587726531,
        "light.light179": 2570948912,
        "light.light18": 2501359188,
        "light.light180": 408166252,
        "light.light181": 424943871,
        "light.light182": 441721490,
        "light.light183": 458499109,
        "light.light184": 341055776,
        "light.light185": 357833395,
        "light.light186": 374611014,
        "light.light187": 391388633,
        "light.light188": 542387204,
        "light.light189": 559164823,
        "light.light19": 2518136807,
        "light.light190": 508979061,
        "light.light191": 492201442,
        "light.light192": 475423823,
        "light.light193": 458646204,
        "light.light194": 441868585,
        "light.light195": 425090966,
        "light.light196": 408313347,
        "light.light197": 391535728,
        "light.light198": 643200013,
        "light.light199": 626422394,
        "light.light2": 335133085,
        "light.light20": 522144599,
        "light.light200": 1698935589,
        "light.light201": 1682157970,
        "light.light202": 1665380351,
        "light.light203": 1648602732,
        "light.light204": 1631825113,
        "light.light205": 1615047494,
        "light.light206": 1598269875,
        "light.light207": 1581492256,
        "light.light208": 1833156541,
        "light.light209": 1816378922,
        "light.light21": 505366980,
        "light.light210": 1598122780,
        "light.light211": 1614900399,
        "light.light212": 1631678018,
        "light.light213": 1648455637,
        "light.light214": 1531012304,
        "light.light215": 1547789923,
        "light.light216": 1564567542,
        "light.light217": 1581345161,
        "light.light218": 1732343732,
        "light.light219": 1749121351,
        "light.light22": 555699837,
        "light.light23": 538922218,
        "light.light24": 455034123,
        "light.light25": 438256504,
        "light.light26": 488589361,
        "light.light27": 471811742,
        "light.light28": 387923647,
        "light.light29": 371146028,
        "light.light3": 318355466,
        "light.light30": 421331790,
        "light.light31": 438109409,
        "light.light32": 387776552,
        "light.light33": 404554171,
        "light.light34": 488442266,
        "light.light35": 505219885,
        "light.light36": 454887028,
        "light.light37": 471664647,
        "light.light38": 287110838,
        "light.light39": 303888457,
        "light.light4": 234467371,
        "light.light40": 454048385,
        "light.light41": 437270766,
        "light.light42": 420493147,
        "light.light43": 403715528,
        "light.light44": 521158861,
        "light.light45": 504381242,
        "light.light46": 487603623,
        "light.light47": 470826004,
        "light.light48": 319827433,
        "light.light49": 303049814,
        "light.light5": 217689752,
        "light.light50": 353235576,
        "light.light51": 370013195,
        "light.light52": 386790814,
        "light.light53": 403568433,
        "light.light54": 420346052,
        "light.light55": 437123671,
        "light.light56": 453901290,
        "light.light57": 470678909,
        "light.light58": 219014624,
        "light.light59": 235792243,
        "light.light6": 268022609,
        "light.light60": 2266325427,
        "light.light61": 2249547808,
        "light.light62": 2299880665,
        "light.light63": 2283103046,
        "light.light64": 2333435903,
        "light.light65": 2316658284,
        "light.light66": 2366991141,
        "light.light67": 2350213522,
        "light.light68": 2400546379,
        "light.light69": 2383768760,
        "light.light7": 251244990,
        "light.light70": 554861194,
        "light.light71": 571638813,
        "light.light72": 521305956,
        "light.light73": 538083575,
        "light.light74": 487750718,
        "light.light75": 504528337,
        "light.light76": 454195480,
        "light.light77": 470973099,
        "light.light78": 420640242,
        "light.light79": 437417861,
        "light.light8": 167356895,
        "light.light80": 2735113021,
        "light.light81": 2718335402,
        "light.light82": 2701557783,
        "light.light83": 2684780164,
        "light.light84": 2668002545,
        "light.light85": 2651224926,
        "light.light86": 2634447307,
        "light.light87": 2617669688,
        "light.light88": 2600892069,
        "light.light89": 2584114450,
        "light.light9": 150579276,
        "light.light90": 2634300212,
        "light.light91": 2651077831,
        "light.light92": 2667855450,
        "light.light93": 2684633069,
        "light.light94": 2567189736,
        "light.light95": 2583967355,
        "light.light96": 2600744974,
        "light.light97": 2617522593,
        "light.light98": 2500079260,
        "light.light99": 2516856879,
    }

    await aid_storage.async_save()
    await hass.async_block_till_done()

    with patch("fnvhash.fnv1a_32", side_effect=Exception):
        aid_storage = AccessoryAidStorage(hass, config_entry)
    await aid_storage.async_initialize()

    assert aid_storage.allocations == {
        "device.light.unique_id": 1953095294,
        "light.light0": 301577847,
        "light.light1": 284800228,
        "light.light10": 2367138236,
        "light.light100": 2822760292,
        "light.light101": 2839537911,
        "light.light102": 2856315530,
        "light.light103": 2873093149,
        "light.light104": 2755649816,
        "light.light105": 2772427435,
        "light.light106": 2789205054,
        "light.light107": 2805982673,
        "light.light108": 2688539340,
        "light.light109": 2705316959,
        "light.light11": 2383915855,
        "light.light110": 776141037,
        "light.light111": 759363418,
        "light.light112": 742585799,
        "light.light113": 725808180,
        "light.light114": 709030561,
        "light.light115": 692252942,
        "light.light116": 675475323,
        "light.light117": 658697704,
        "light.light118": 641920085,
        "light.light119": 625142466,
        "light.light12": 2400693474,
        "light.light120": 340070038,
        "light.light121": 356847657,
        "light.light122": 306514800,
        "light.light123": 323292419,
        "light.light124": 407180514,
        "light.light125": 423958133,
        "light.light126": 373625276,
        "light.light127": 390402895,
        "light.light128": 474290990,
        "light.light129": 491068609,
        "light.light13": 2417471093,
        "light.light130": 440882847,
        "light.light131": 424105228,
        "light.light132": 474438085,
        "light.light133": 457660466,
        "light.light134": 373772371,
        "light.light135": 356994752,
        "light.light136": 407327609,
        "light.light137": 390549990,
        "light.light138": 575103799,
        "light.light139": 558326180,
        "light.light14": 2300027760,
        "light.light140": 271973824,
        "light.light141": 288751443,
        "light.light142": 305529062,
        "light.light143": 322306681,
        "light.light144": 339084300,
        "light.light145": 355861919,
        "light.light146": 372639538,
        "light.light147": 389417157,
        "light.light148": 406194776,
        "light.light149": 422972395,
        "light.light15": 2316805379,
        "light.light150": 2520321865,
        "light.light151": 2503544246,
        "light.light152": 2486766627,
        "light.light153": 2469989008,
        "light.light154": 2587432341,
        "light.light155": 2570654722,
        "light.light156": 2553877103,
        "light.light157": 2537099484,
        "light.light158": 2654542817,
        "light.light159": 2637765198,
        "light.light16": 2333582998,
        "light.light160": 2621134674,
        "light.light161": 2637912293,
        "light.light162": 2587579436,
        "light.light163": 2604357055,
        "light.light164": 2554024198,
        "light.light165": 2570801817,
        "light.light166": 2520468960,
        "light.light167": 2537246579,
        "light.light168": 2755355626,
        "light.light169": 2772133245,
        "light.light17": 2350360617,
        "light.light170": 2721947483,
        "light.light171": 2705169864,
        "light.light172": 2755502721,
        "light.light173": 2738725102,
        "light.light174": 2789057959,
        "light.light175": 2772280340,
        "light.light176": 2822613197,
        "light.light177": 2805835578,
        "light.light178": 2587726531,
        "light.light179": 2570948912,
        "light.light18": 2501359188,
        "light.light180": 408166252,
        "light.light181": 424943871,
        "light.light182": 441721490,
        "light.light183": 458499109,
        "light.light184": 341055776,
        "light.light185": 357833395,
        "light.light186": 374611014,
        "light.light187": 391388633,
        "light.light188": 542387204,
        "light.light189": 559164823,
        "light.light19": 2518136807,
        "light.light190": 508979061,
        "light.light191": 492201442,
        "light.light192": 475423823,
        "light.light193": 458646204,
        "light.light194": 441868585,
        "light.light195": 425090966,
        "light.light196": 408313347,
        "light.light197": 391535728,
        "light.light198": 643200013,
        "light.light199": 626422394,
        "light.light2": 335133085,
        "light.light20": 522144599,
        "light.light200": 1698935589,
        "light.light201": 1682157970,
        "light.light202": 1665380351,
        "light.light203": 1648602732,
        "light.light204": 1631825113,
        "light.light205": 1615047494,
        "light.light206": 1598269875,
        "light.light207": 1581492256,
        "light.light208": 1833156541,
        "light.light209": 1816378922,
        "light.light21": 505366980,
        "light.light210": 1598122780,
        "light.light211": 1614900399,
        "light.light212": 1631678018,
        "light.light213": 1648455637,
        "light.light214": 1531012304,
        "light.light215": 1547789923,
        "light.light216": 1564567542,
        "light.light217": 1581345161,
        "light.light218": 1732343732,
        "light.light219": 1749121351,
        "light.light22": 555699837,
        "light.light23": 538922218,
        "light.light24": 455034123,
        "light.light25": 438256504,
        "light.light26": 488589361,
        "light.light27": 471811742,
        "light.light28": 387923647,
        "light.light29": 371146028,
        "light.light3": 318355466,
        "light.light30": 421331790,
        "light.light31": 438109409,
        "light.light32": 387776552,
        "light.light33": 404554171,
        "light.light34": 488442266,
        "light.light35": 505219885,
        "light.light36": 454887028,
        "light.light37": 471664647,
        "light.light38": 287110838,
        "light.light39": 303888457,
        "light.light4": 234467371,
        "light.light40": 454048385,
        "light.light41": 437270766,
        "light.light42": 420493147,
        "light.light43": 403715528,
        "light.light44": 521158861,
        "light.light45": 504381242,
        "light.light46": 487603623,
        "light.light47": 470826004,
        "light.light48": 319827433,
        "light.light49": 303049814,
        "light.light5": 217689752,
        "light.light50": 353235576,
        "light.light51": 370013195,
        "light.light52": 386790814,
        "light.light53": 403568433,
        "light.light54": 420346052,
        "light.light55": 437123671,
        "light.light56": 453901290,
        "light.light57": 470678909,
        "light.light58": 219014624,
        "light.light59": 235792243,
        "light.light6": 268022609,
        "light.light60": 2266325427,
        "light.light61": 2249547808,
        "light.light62": 2299880665,
        "light.light63": 2283103046,
        "light.light64": 2333435903,
        "light.light65": 2316658284,
        "light.light66": 2366991141,
        "light.light67": 2350213522,
        "light.light68": 2400546379,
        "light.light69": 2383768760,
        "light.light7": 251244990,
        "light.light70": 554861194,
        "light.light71": 571638813,
        "light.light72": 521305956,
        "light.light73": 538083575,
        "light.light74": 487750718,
        "light.light75": 504528337,
        "light.light76": 454195480,
        "light.light77": 470973099,
        "light.light78": 420640242,
        "light.light79": 437417861,
        "light.light8": 167356895,
        "light.light80": 2735113021,
        "light.light81": 2718335402,
        "light.light82": 2701557783,
        "light.light83": 2684780164,
        "light.light84": 2668002545,
        "light.light85": 2651224926,
        "light.light86": 2634447307,
        "light.light87": 2617669688,
        "light.light88": 2600892069,
        "light.light89": 2584114450,
        "light.light9": 150579276,
        "light.light90": 2634300212,
        "light.light91": 2651077831,
        "light.light92": 2667855450,
        "light.light93": 2684633069,
        "light.light94": 2567189736,
        "light.light95": 2583967355,
        "light.light96": 2600744974,
        "light.light97": 2617522593,
        "light.light98": 2500079260,
        "light.light99": 2516856879,
    }

    aidstore = get_aid_storage_filename_for_entry_id(config_entry.entry_id)
    aid_storage_path = hass.config.path(STORAGE_DIR, aidstore)
    if await hass.async_add_executor_job(os.path.exists, aid_storage_path):
        await hass.async_add_executor_job(os.unlink, aid_storage_path)