"""Tests for entity permissions."""
import pytest
import voluptuous as vol

from homeassistant.auth.permissions.entities import (
    ENTITY_POLICY_SCHEMA,
    compile_entities,
)
from homeassistant.auth.permissions.models import PermissionLookup
from homeassistant.helpers.device_registry import DeviceEntry
from homeassistant.helpers.entity_registry import RegistryEntry

from tests.common import mock_device_registry, mock_registry


def test_entities_none():
    """Test entity ID policy."""
    policy = None
    compiled = compile_entities(policy, None)
    assert compiled("light.kitchen", "read") is False


def test_entities_empty():
    """Test entity ID policy."""
    policy = {}
    ENTITY_POLICY_SCHEMA(policy)
    compiled = compile_entities(policy, None)
    assert compiled("light.kitchen", "read") is False


def test_entities_false():
    """Test entity ID policy."""
    policy = False
    with pytest.raises(vol.Invalid):
        ENTITY_POLICY_SCHEMA(policy)


def test_entities_true():
    """Test entity ID policy."""
    policy = True
    ENTITY_POLICY_SCHEMA(policy)
    compiled = compile_entities(policy, None)
    assert compiled("light.kitchen", "read") is True


def test_entities_domains_true():
    """Test entity ID policy."""
    policy = {"domains": True}
    ENTITY_POLICY_SCHEMA(policy)
    compiled = compile_entities(policy, None)
    assert compiled("light.kitchen", "read") is True


def test_entities_domains_domain_true():
    """Test entity ID policy."""
    policy = {"domains": {"light": True}}
    ENTITY_POLICY_SCHEMA(policy)
    compiled = compile_entities(policy, None)
    assert compiled("light.kitchen", "read") is True
    assert compiled("switch.kitchen", "read") is False


def test_entities_domains_domain_false():
    """Test entity ID policy."""
    policy = {"domains": {"light": False}}
    with pytest.raises(vol.Invalid):
        ENTITY_POLICY_SCHEMA(policy)


def test_entities_entity_ids_true():
    """Test entity ID policy."""
    policy = {"entity_ids": True}
    ENTITY_POLICY_SCHEMA(policy)
    compiled = compile_entities(policy, None)
    assert compiled("light.kitchen", "read") is True


def test_entities_entity_ids_false():
    """Test entity ID policy."""
    policy = {"entity_ids": False}
    with pytest.raises(vol.Invalid):
        ENTITY_POLICY_SCHEMA(policy)


def test_entities_entity_ids_entity_id_true():
    """Test entity ID policy."""
    policy = {"entity_ids": {"light.kitchen": True}}
    ENTITY_POLICY_SCHEMA(policy)
    compiled = compile_entities(policy, None)
    assert compiled("light.kitchen", "read") is True
    assert compiled("switch.kitchen", "read") is False


def test_entities_entity_ids_entity_id_false():
    """Test entity ID policy."""
    policy = {"entity_ids": {"light.kitchen": False}}
    with pytest.raises(vol.Invalid):
        ENTITY_POLICY_SCHEMA(policy)


def test_entities_control_only():
    """Test policy granting control only."""
    policy = {"entity_ids": {"light.kitchen": {"read": True}}}
    ENTITY_POLICY_SCHEMA(policy)
    compiled = compile_entities(policy, None)
    assert compiled("light.kitchen", "read") is True
    assert compiled("light.kitchen", "control") is False
    assert compiled("light.kitchen", "edit") is False


def test_entities_read_control():
    """Test policy granting control only."""
    policy = {"domains": {"light": {"read": True, "control": True}}}
    ENTITY_POLICY_SCHEMA(policy)
    compiled = compile_entities(policy, None)
    assert compiled("light.kitchen", "read") is True
    assert compiled("light.kitchen", "control") is True
    assert compiled("light.kitchen", "edit") is False


def test_entities_all_allow():
    """Test policy allowing all entities."""
    policy = {"all": True}
    ENTITY_POLICY_SCHEMA(policy)
    compiled = compile_entities(policy, None)
    assert compiled("light.kitchen", "read") is True
    assert compiled("light.kitchen", "control") is True
    assert compiled("switch.kitchen", "read") is True


def test_entities_all_read():
    """Test policy applying read to all entities."""
    policy = {"all": {"read": True}}
    ENTITY_POLICY_SCHEMA(policy)
    compiled = compile_entities(policy, None)
    assert compiled("light.kitchen", "read") is True
    assert compiled("light.kitchen", "control") is False
    assert compiled("switch.kitchen", "read") is True


def test_entities_all_control():
    """Test entity ID policy applying control to all."""
    policy = {"all": {"control": True}}
    ENTITY_POLICY_SCHEMA(policy)
    compiled = compile_entities(policy, None)
    assert compiled("light.kitchen", "read") is False
    assert compiled("light.kitchen", "control") is True
    assert compiled("switch.kitchen", "read") is False
    assert compiled("switch.kitchen", "control") is True


def test_entities_device_id_boolean(hass):
    """Test entity ID policy applying control on device id."""
    entity_registry = mock_registry(
        hass,
        {
            "test_domain.allowed": RegistryEntry(
                entity_id="test_domain.allowed",
                unique_id="1234",
                platform="test_platform",
                device_id="mock-allowed-dev-id",
            ),
            "test_domain.not_allowed": RegistryEntry(
                entity_id="test_domain.not_allowed",
                unique_id="5678",
                platform="test_platform",
                device_id="mock-not-allowed-dev-id",
            ),
        },
    )
    device_registry = mock_device_registry(hass)

    policy = {"device_ids": {"mock-allowed-dev-id": {"read": True}}}
    ENTITY_POLICY_SCHEMA(policy)
    compiled = compile_entities(
        policy, PermissionLookup(entity_registry, device_registry)
    )
    assert compiled("test_domain.allowed", "read") is True
    assert compiled("test_domain.allowed", "control") is False
    assert compiled("test_domain.not_allowed", "read") is False
    assert compiled("test_domain.not_allowed", "control") is False


def test_entities_areas_true():
    """Test entity ID policy for areas."""
    policy = {"area_ids": True}
    ENTITY_POLICY_SCHEMA(policy)
    compiled = compile_entities(policy, None)
    assert compiled("light.kitchen", "read") is True


def test_entities_areas_area_true(hass):
    """Test entity ID policy for areas with specific area."""
    entity_registry = mock_registry(
        hass,
        {
            "light.kitchen": RegistryEntry(
                entity_id="light.kitchen",
                unique_id="1234",
                platform="test_platform",
                device_id="mock-dev-id",
            )
        },
    )
    device_registry = mock_device_registry(
        hass, {"mock-dev-id": DeviceEntry(id="mock-dev-id", area_id="mock-area-id")}
    )

    policy = {"area_ids": {"mock-area-id": {"read": True, "control": True}}}
    ENTITY_POLICY_SCHEMA(policy)
    compiled = compile_entities(
        policy, PermissionLookup(entity_registry, device_registry)
    )
    assert compiled("light.kitchen", "read") is True
    assert compiled("light.kitchen", "control") is True
    assert compiled("light.kitchen", "edit") is False
    assert compiled("switch.kitchen", "read") is False
