"""The tests for the Sure Petcare lock platform."""
import pytest
from surepy.exceptions import SurePetcareError

from homeassistant.components.surepetcare.const import DOMAIN
from homeassistant.helpers import entity_registry as er
from homeassistant.setup import async_setup_component

from . import HOUSEHOLD_ID, MOCK_CAT_FLAP, MOCK_CONFIG, MOCK_PET_FLAP

EXPECTED_ENTITY_IDS = {
    "lock.cat_flap_locked_in": f"{HOUSEHOLD_ID}-{MOCK_CAT_FLAP['id']}-locked_in",
    "lock.cat_flap_locked_out": f"{HOUSEHOLD_ID}-{MOCK_CAT_FLAP['id']}-locked_out",
    "lock.cat_flap_locked_all": f"{HOUSEHOLD_ID}-{MOCK_CAT_FLAP['id']}-locked_all",
    "lock.pet_flap_locked_in": f"{HOUSEHOLD_ID}-{MOCK_PET_FLAP['id']}-locked_in",
    "lock.pet_flap_locked_out": f"{HOUSEHOLD_ID}-{MOCK_PET_FLAP['id']}-locked_out",
    "lock.pet_flap_locked_all": f"{HOUSEHOLD_ID}-{MOCK_PET_FLAP['id']}-locked_all",
}


async def test_locks(hass, surepetcare) -> None:
    """Test the generation of unique ids."""
    assert await async_setup_component(hass, DOMAIN, MOCK_CONFIG)
    await hass.async_block_till_done()

    entity_registry = er.async_get(hass)
    state_entity_ids = hass.states.async_entity_ids()

    for entity_id, unique_id in EXPECTED_ENTITY_IDS.items():
        surepetcare.reset_mock()

        assert entity_id in state_entity_ids
        state = hass.states.get(entity_id)
        assert state
        assert state.state == "unlocked"
        entity = entity_registry.async_get(entity_id)
        assert entity.unique_id == unique_id

        await hass.services.async_call(
            "lock", "unlock", {"entity_id": entity_id}, blocking=True
        )
        state = hass.states.get(entity_id)
        assert state.state == "unlocked"
        # already unlocked
        assert surepetcare.unlock.call_count == 0

        await hass.services.async_call(
            "lock", "lock", {"entity_id": entity_id}, blocking=True
        )
        state = hass.states.get(entity_id)
        assert state.state == "locked"
        if "locked_in" in entity_id:
            assert surepetcare.lock_in.call_count == 1
        elif "locked_out" in entity_id:
            assert surepetcare.lock_out.call_count == 1
        elif "locked_all" in entity_id:
            assert surepetcare.lock.call_count == 1

        # lock again should not trigger another request
        await hass.services.async_call(
            "lock", "lock", {"entity_id": entity_id}, blocking=True
        )
        state = hass.states.get(entity_id)
        assert state.state == "locked"
        if "locked_in" in entity_id:
            assert surepetcare.lock_in.call_count == 1
        elif "locked_out" in entity_id:
            assert surepetcare.lock_out.call_count == 1
        elif "locked_all" in entity_id:
            assert surepetcare.lock.call_count == 1

        await hass.services.async_call(
            "lock", "unlock", {"entity_id": entity_id}, blocking=True
        )
        state = hass.states.get(entity_id)
        assert state.state == "unlocked"
        assert surepetcare.unlock.call_count == 1


async def test_lock_failing(hass, surepetcare) -> None:
    """Test handling of lock failing."""
    assert await async_setup_component(hass, DOMAIN, MOCK_CONFIG)
    await hass.async_block_till_done()

    surepetcare.lock_in.side_effect = SurePetcareError
    surepetcare.lock_out.side_effect = SurePetcareError
    surepetcare.lock.side_effect = SurePetcareError

    for entity_id, unique_id in EXPECTED_ENTITY_IDS.items():
        with pytest.raises(SurePetcareError):
            await hass.services.async_call(
                "lock", "lock", {"entity_id": entity_id}, blocking=True
            )
        state = hass.states.get(entity_id)
        assert state.state == "unlocked"


async def test_unlock_failing(hass, surepetcare) -> None:
    """Test handling of unlock failing."""
    assert await async_setup_component(hass, DOMAIN, MOCK_CONFIG)
    await hass.async_block_till_done()

    entity_id = list(EXPECTED_ENTITY_IDS)[0]

    await hass.services.async_call(
        "lock", "lock", {"entity_id": entity_id}, blocking=True
    )
    surepetcare.unlock.side_effect = SurePetcareError

    with pytest.raises(SurePetcareError):
        await hass.services.async_call(
            "lock", "unlock", {"entity_id": entity_id}, blocking=True
        )
    state = hass.states.get(entity_id)
    assert state.state == "locked"
