"""Zwave util methods."""
import asyncio
import logging

import homeassistant.util.dt as dt_util

from . import const

_LOGGER = logging.getLogger(__name__)


def check_node_schema(node, schema):
    """Check if node matches the passed node schema."""
    if const.DISC_NODE_ID in schema and node.node_id not in schema[const.DISC_NODE_ID]:
        _LOGGER.debug(
            "node.node_id %s not in node_id %s",
            node.node_id,
            schema[const.DISC_NODE_ID],
        )
        return False
    if (
        const.DISC_GENERIC_DEVICE_CLASS in schema
        and node.generic not in schema[const.DISC_GENERIC_DEVICE_CLASS]
    ):
        _LOGGER.debug(
            "node.generic %s not in generic_device_class %s",
            node.generic,
            schema[const.DISC_GENERIC_DEVICE_CLASS],
        )
        return False
    if (
        const.DISC_SPECIFIC_DEVICE_CLASS in schema
        and node.specific not in schema[const.DISC_SPECIFIC_DEVICE_CLASS]
    ):
        _LOGGER.debug(
            "node.specific %s not in specific_device_class %s",
            node.specific,
            schema[const.DISC_SPECIFIC_DEVICE_CLASS],
        )
        return False
    return True


def check_value_schema(value, schema):
    """Check if the value matches the passed value schema."""
    if (
        const.DISC_COMMAND_CLASS in schema
        and value.command_class not in schema[const.DISC_COMMAND_CLASS]
    ):
        _LOGGER.debug(
            "value.command_class %s not in command_class %s",
            value.command_class,
            schema[const.DISC_COMMAND_CLASS],
        )
        return False
    if const.DISC_TYPE in schema and value.type not in schema[const.DISC_TYPE]:
        _LOGGER.debug(
            "value.type %s not in type %s", value.type, schema[const.DISC_TYPE]
        )
        return False
    if const.DISC_GENRE in schema and value.genre not in schema[const.DISC_GENRE]:
        _LOGGER.debug(
            "value.genre %s not in genre %s", value.genre, schema[const.DISC_GENRE]
        )
        return False
    if const.DISC_INDEX in schema and value.index not in schema[const.DISC_INDEX]:
        _LOGGER.debug(
            "value.index %s not in index %s", value.index, schema[const.DISC_INDEX]
        )
        return False
    if (
        const.DISC_INSTANCE in schema
        and value.instance not in schema[const.DISC_INSTANCE]
    ):
        _LOGGER.debug(
            "value.instance %s not in instance %s",
            value.instance,
            schema[const.DISC_INSTANCE],
        )
        return False
    if const.DISC_SCHEMAS in schema:
        found = False
        for schema_item in schema[const.DISC_SCHEMAS]:
            found = found or check_value_schema(value, schema_item)
        if not found:
            return False

    return True


def compute_value_unique_id(node, value):
    """Compute unique_id a value would get if it were to get one."""
    return f"{node.node_id}-{value.object_id}"


def node_name(node):
    """Return the name of the node."""
    if is_node_parsed(node):
        return node.name or f"{node.manufacturer_name} {node.product_name}"
    return f"Unknown Node {node.node_id}"


def node_device_id_and_name(node, instance=1):
    """Return the name and device ID for the value with the given index."""
    name = node_name(node)
    if instance == 1:
        return ((const.DOMAIN, node.node_id), name)
    name = f"{name} ({instance})"
    return ((const.DOMAIN, node.node_id, instance), name)


async def check_has_unique_id(entity, ready_callback, timeout_callback):
    """Wait for entity to have unique_id."""
    start_time = dt_util.utcnow()
    while True:
        waited = int((dt_util.utcnow() - start_time).total_seconds())
        if entity.unique_id:
            ready_callback(waited)
            return
        if waited >= const.NODE_READY_WAIT_SECS:
            # Wait up to NODE_READY_WAIT_SECS seconds for unique_id to appear.
            timeout_callback(waited)
            return
        await asyncio.sleep(1)


def is_node_parsed(node):
    """Check whether the node has been parsed or still waiting to be parsed."""
    return bool((node.manufacturer_name and node.product_name) or node.name)
