import logging
from typing import cast

from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
from homeassistant.const import CONF_NAME
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.device_registry import DeviceEntry
from homeassistant.helpers.entity import Entity, async_generate_entity_id
import homeassistant.helpers.entity_registry as er
from homeassistant.helpers.typing import ConfigType

from custom_components.powercalc.common import SourceEntity
from custom_components.powercalc.const import (
    CONF_COST_SENSOR_FRIENDLY_NAMING,
    CONF_COST_SENSOR_NAMING,
    CONF_ENERGY_SENSOR_FRIENDLY_NAMING,
    CONF_ENERGY_SENSOR_NAMING,
    CONF_POWER_SENSOR_FRIENDLY_NAMING,
    CONF_POWER_SENSOR_NAMING,
    CONF_STANDBY_ENERGY_SENSOR_NAMING,
    DEFAULT_COST_NAME_PATTERN,
    DEFAULT_ENERGY_NAME_PATTERN,
    DEFAULT_POWER_NAME_PATTERN,
    DEFAULT_STANDBY_ENERGY_NAME_PATTERN,
    DOMAIN,
)
from custom_components.powercalc.device_binding import bind_entity_to_registry_metadata

ENTITY_ID_FORMAT = SENSOR_DOMAIN + ".{}"

_LOGGER = logging.getLogger(__name__)


class BaseEntity(Entity):
    async def async_added_to_hass(self) -> None:
        """Bind configured registry metadata."""
        await super().async_added_to_hass()

        bind_entity_to_registry_metadata(
            self.hass,
            self.entity_id,
            cast(DeviceEntry | None, getattr(self, "_powercalc_device_entry", None)),
            cast(ConfigType | None, getattr(self, "_sensor_config", None)),
        )


def generate_power_sensor_name(
    sensor_config: ConfigType,
    name: str | None = None,
    source_entity: SourceEntity | None = None,
) -> str:
    """Generates the name to use for a power sensor."""
    return _generate_sensor_name(
        sensor_config,
        CONF_POWER_SENSOR_NAMING,
        CONF_POWER_SENSOR_FRIENDLY_NAMING,
        DEFAULT_POWER_NAME_PATTERN,
        name,
        source_entity,
    )


def generate_energy_sensor_name(
    sensor_config: ConfigType,
    name: str | None = None,
    source_entity: SourceEntity | None = None,
) -> str:
    """Generates the name to use for an energy sensor."""
    return _generate_sensor_name(
        sensor_config,
        CONF_ENERGY_SENSOR_NAMING,
        CONF_ENERGY_SENSOR_FRIENDLY_NAMING,
        DEFAULT_ENERGY_NAME_PATTERN,
        name,
        source_entity,
    )


def generate_standby_energy_sensor_name(
    sensor_config: ConfigType,
    name: str | None = None,
    source_entity: SourceEntity | None = None,
) -> str:
    """Generate the name to use for a standby energy sensor."""
    return _generate_sensor_name(
        sensor_config,
        CONF_STANDBY_ENERGY_SENSOR_NAMING,
        CONF_STANDBY_ENERGY_SENSOR_NAMING,
        DEFAULT_STANDBY_ENERGY_NAME_PATTERN,
        name,
        source_entity,
    )


def generate_cost_sensor_name(
    sensor_config: ConfigType,
    name: str | None = None,
    source_entity: SourceEntity | None = None,
) -> str:
    """Generates the name to use for a cost sensor."""
    return _generate_sensor_name(
        sensor_config,
        CONF_COST_SENSOR_NAMING,
        CONF_COST_SENSOR_FRIENDLY_NAMING,
        DEFAULT_COST_NAME_PATTERN,
        name,
        source_entity,
    )


def _generate_sensor_name(
    sensor_config: ConfigType,
    naming_conf_key: str,
    friendly_naming_conf_key: str,
    default_pattern: str,
    name: str | None = None,
    source_entity: SourceEntity | None = None,
) -> str:
    """Generates the name to use for a sensor."""
    if name is None and source_entity:
        name = source_entity.name

    if friendly_naming_conf_key in sensor_config:
        friendly_name_pattern = str(sensor_config.get(friendly_naming_conf_key))
        return friendly_name_pattern.format(name)

    name_pattern = str(sensor_config.get(naming_conf_key, default_pattern))
    return name_pattern.format(name)


@callback
def generate_power_sensor_entity_id(
    hass: HomeAssistant,
    sensor_config: ConfigType,
    source_entity: SourceEntity | None = None,
    name: str | None = None,
    unique_id: str | None = None,
) -> str:
    """Generates the entity_id to use for a power sensor."""
    return _generate_sensor_entity_id(
        hass,
        sensor_config,
        CONF_POWER_SENSOR_NAMING,
        DEFAULT_POWER_NAME_PATTERN,
        source_entity,
        name,
        unique_id,
    )


@callback
def generate_energy_sensor_entity_id(
    hass: HomeAssistant,
    sensor_config: ConfigType,
    source_entity: SourceEntity | None = None,
    name: str | None = None,
    unique_id: str | None = None,
) -> str:
    """Generates the entity_id to use for an energy sensor."""
    return _generate_sensor_entity_id(
        hass,
        sensor_config,
        CONF_ENERGY_SENSOR_NAMING,
        DEFAULT_ENERGY_NAME_PATTERN,
        source_entity,
        name,
        unique_id,
    )


@callback
def generate_standby_energy_sensor_entity_id(
    hass: HomeAssistant,
    sensor_config: ConfigType,
    source_entity: SourceEntity | None = None,
    name: str | None = None,
    unique_id: str | None = None,
) -> str:
    """Generate the entity ID to use for a standby energy sensor."""
    return _generate_sensor_entity_id(
        hass,
        sensor_config,
        CONF_STANDBY_ENERGY_SENSOR_NAMING,
        DEFAULT_STANDBY_ENERGY_NAME_PATTERN,
        source_entity,
        name,
        unique_id,
    )


@callback
def generate_cost_sensor_entity_id(
    hass: HomeAssistant,
    sensor_config: ConfigType,
    source_entity: SourceEntity | None = None,
    name: str | None = None,
    unique_id: str | None = None,
) -> str:
    """Generates the entity_id to use for a cost sensor."""
    return _generate_sensor_entity_id(
        hass,
        sensor_config,
        CONF_COST_SENSOR_NAMING,
        DEFAULT_COST_NAME_PATTERN,
        source_entity,
        name,
        unique_id,
    )


def _generate_sensor_entity_id(
    hass: HomeAssistant,
    sensor_config: ConfigType,
    naming_conf_key: str,
    default_pattern: str,
    source_entity: SourceEntity | None = None,
    name: str | None = None,
    unique_id: str | None = None,
) -> str:
    """Generates the entity_id to use for a sensor."""
    if entity_id := get_entity_id_by_unique_id(hass, unique_id):
        return entity_id
    name_pattern = str(sensor_config.get(naming_conf_key, default_pattern))
    object_id = name or sensor_config.get(CONF_NAME)
    if object_id is None and source_entity:
        object_id = source_entity.object_id
    return async_generate_entity_id(
        ENTITY_ID_FORMAT,
        name_pattern.format(object_id),
        hass=hass,
    )


def get_entity_id_by_unique_id(
    hass: HomeAssistant,
    unique_id: str | None,
) -> str | None:
    if unique_id is None:
        return None
    entity_reg = er.async_get(hass)
    return entity_reg.async_get_entity_id(SENSOR_DOMAIN, DOMAIN, unique_id)
