"""Viessmann ViCare sensor device."""
import logging

import requests

from homeassistant.const import (
    CONF_DEVICE_CLASS,
    CONF_ICON,
    CONF_NAME,
    CONF_UNIT_OF_MEASUREMENT,
    DEVICE_CLASS_POWER,
    DEVICE_CLASS_TEMPERATURE,
    ENERGY_KILO_WATT_HOUR,
    POWER_WATT,
    TEMP_CELSIUS,
    UNIT_PERCENTAGE,
)
from homeassistant.helpers.entity import Entity

from . import (
    DOMAIN as VICARE_DOMAIN,
    PYVICARE_ERROR,
    VICARE_API,
    VICARE_HEATING_TYPE,
    VICARE_NAME,
    HeatingType,
)

_LOGGER = logging.getLogger(__name__)

CONF_GETTER = "getter"

SENSOR_TYPE_TEMPERATURE = "temperature"

SENSOR_OUTSIDE_TEMPERATURE = "outside_temperature"
SENSOR_SUPPLY_TEMPERATURE = "supply_temperature"
SENSOR_RETURN_TEMPERATURE = "return_temperature"

# gas sensors
SENSOR_BOILER_TEMPERATURE = "boiler_temperature"
SENSOR_BURNER_MODULATION = "burner_modulation"
SENSOR_BURNER_STARTS = "burner_starts"
SENSOR_BURNER_HOURS = "burner_hours"
SENSOR_BURNER_POWER = "burner_power"
SENSOR_DHW_GAS_CONSUMPTION_TODAY = "hotwater_gas_consumption_today"
SENSOR_DHW_GAS_CONSUMPTION_THIS_WEEK = "hotwater_gas_consumption_heating_this_week"
SENSOR_DHW_GAS_CONSUMPTION_THIS_MONTH = "hotwater_gas_consumption_heating_this_month"
SENSOR_DHW_GAS_CONSUMPTION_THIS_YEAR = "hotwater_gas_consumption_heating_this_year"
SENSOR_GAS_CONSUMPTION_TODAY = "gas_consumption_heating_today"
SENSOR_GAS_CONSUMPTION_THIS_WEEK = "gas_consumption_heating_this_week"
SENSOR_GAS_CONSUMPTION_THIS_MONTH = "gas_consumption_heating_this_month"
SENSOR_GAS_CONSUMPTION_THIS_YEAR = "gas_consumption_heating_this_year"

# heatpump sensors
SENSOR_COMPRESSOR_STARTS = "compressor_starts"
SENSOR_COMPRESSOR_HOURS = "compressor_hours"

SENSOR_TYPES = {
    SENSOR_OUTSIDE_TEMPERATURE: {
        CONF_NAME: "Outside Temperature",
        CONF_ICON: None,
        CONF_UNIT_OF_MEASUREMENT: TEMP_CELSIUS,
        CONF_GETTER: lambda api: api.getOutsideTemperature(),
        CONF_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE,
    },
    SENSOR_SUPPLY_TEMPERATURE: {
        CONF_NAME: "Supply Temperature",
        CONF_ICON: None,
        CONF_UNIT_OF_MEASUREMENT: TEMP_CELSIUS,
        CONF_GETTER: lambda api: api.getSupplyTemperature(),
        CONF_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE,
    },
    # gas sensors
    SENSOR_BOILER_TEMPERATURE: {
        CONF_NAME: "Boiler Temperature",
        CONF_ICON: None,
        CONF_UNIT_OF_MEASUREMENT: TEMP_CELSIUS,
        CONF_GETTER: lambda api: api.getBoilerTemperature(),
        CONF_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE,
    },
    SENSOR_BURNER_MODULATION: {
        CONF_NAME: "Burner modulation",
        CONF_ICON: "mdi:percent",
        CONF_UNIT_OF_MEASUREMENT: UNIT_PERCENTAGE,
        CONF_GETTER: lambda api: api.getBurnerModulation(),
        CONF_DEVICE_CLASS: None,
    },
    SENSOR_DHW_GAS_CONSUMPTION_TODAY: {
        CONF_NAME: "Hot water gas consumption today",
        CONF_ICON: "mdi:power",
        CONF_UNIT_OF_MEASUREMENT: ENERGY_KILO_WATT_HOUR,
        CONF_GETTER: lambda api: api.getGasConsumptionDomesticHotWaterToday(),
        CONF_DEVICE_CLASS: None,
    },
    SENSOR_DHW_GAS_CONSUMPTION_THIS_WEEK: {
        CONF_NAME: "Hot water gas consumption this week",
        CONF_ICON: "mdi:power",
        CONF_UNIT_OF_MEASUREMENT: ENERGY_KILO_WATT_HOUR,
        CONF_GETTER: lambda api: api.getGasConsumptionDomesticHotWaterThisWeek(),
        CONF_DEVICE_CLASS: None,
    },
    SENSOR_DHW_GAS_CONSUMPTION_THIS_MONTH: {
        CONF_NAME: "Hot water gas consumption this month",
        CONF_ICON: "mdi:power",
        CONF_UNIT_OF_MEASUREMENT: ENERGY_KILO_WATT_HOUR,
        CONF_GETTER: lambda api: api.getGasConsumptionDomesticHotWaterThisMonth(),
        CONF_DEVICE_CLASS: None,
    },
    SENSOR_DHW_GAS_CONSUMPTION_THIS_YEAR: {
        CONF_NAME: "Hot water gas consumption this year",
        CONF_ICON: "mdi:power",
        CONF_UNIT_OF_MEASUREMENT: ENERGY_KILO_WATT_HOUR,
        CONF_GETTER: lambda api: api.getGasConsumptionDomesticHotWaterThisYear(),
        CONF_DEVICE_CLASS: None,
    },
    SENSOR_GAS_CONSUMPTION_TODAY: {
        CONF_NAME: "Heating gas consumption today",
        CONF_ICON: "mdi:power",
        CONF_UNIT_OF_MEASUREMENT: ENERGY_KILO_WATT_HOUR,
        CONF_GETTER: lambda api: api.getGasConsumptionHeatingToday(),
        CONF_DEVICE_CLASS: None,
    },
    SENSOR_GAS_CONSUMPTION_THIS_WEEK: {
        CONF_NAME: "Heating gas consumption this week",
        CONF_ICON: "mdi:power",
        CONF_UNIT_OF_MEASUREMENT: ENERGY_KILO_WATT_HOUR,
        CONF_GETTER: lambda api: api.getGasConsumptionHeatingThisWeek(),
        CONF_DEVICE_CLASS: None,
    },
    SENSOR_GAS_CONSUMPTION_THIS_MONTH: {
        CONF_NAME: "Heating gas consumption this month",
        CONF_ICON: "mdi:power",
        CONF_UNIT_OF_MEASUREMENT: ENERGY_KILO_WATT_HOUR,
        CONF_GETTER: lambda api: api.getGasConsumptionHeatingThisMonth(),
        CONF_DEVICE_CLASS: None,
    },
    SENSOR_GAS_CONSUMPTION_THIS_YEAR: {
        CONF_NAME: "Heating gas consumption this year",
        CONF_ICON: "mdi:power",
        CONF_UNIT_OF_MEASUREMENT: ENERGY_KILO_WATT_HOUR,
        CONF_GETTER: lambda api: api.getGasConsumptionHeatingThisYear(),
        CONF_DEVICE_CLASS: None,
    },
    SENSOR_BURNER_STARTS: {
        CONF_NAME: "Burner Starts",
        CONF_ICON: "mdi:counter",
        CONF_UNIT_OF_MEASUREMENT: None,
        CONF_GETTER: lambda api: api.getBurnerStarts(),
        CONF_DEVICE_CLASS: None,
    },
    SENSOR_BURNER_HOURS: {
        CONF_NAME: "Burner Hours",
        CONF_ICON: "mdi:counter",
        CONF_UNIT_OF_MEASUREMENT: None,
        CONF_GETTER: lambda api: api.getBurnerHours(),
        CONF_DEVICE_CLASS: None,
    },
    SENSOR_BURNER_POWER: {
        CONF_NAME: "Burner Current Power",
        CONF_ICON: None,
        CONF_UNIT_OF_MEASUREMENT: POWER_WATT,
        CONF_GETTER: lambda api: api.getCurrentPower(),
        CONF_DEVICE_CLASS: DEVICE_CLASS_POWER,
    },
    # heatpump sensors
    SENSOR_COMPRESSOR_STARTS: {
        CONF_NAME: "Compressor Starts",
        CONF_ICON: "mdi:counter",
        CONF_UNIT_OF_MEASUREMENT: None,
        CONF_GETTER: lambda api: api.getCompressorStarts(),
        CONF_DEVICE_CLASS: None,
    },
    SENSOR_COMPRESSOR_HOURS: {
        CONF_NAME: "Compressor Hours",
        CONF_ICON: "mdi:counter",
        CONF_UNIT_OF_MEASUREMENT: None,
        CONF_GETTER: lambda api: api.getCompressorHours(),
        CONF_DEVICE_CLASS: None,
    },
    SENSOR_RETURN_TEMPERATURE: {
        CONF_NAME: "Return Temperature",
        CONF_ICON: None,
        CONF_UNIT_OF_MEASUREMENT: TEMP_CELSIUS,
        CONF_GETTER: lambda api: api.getReturnTemperature(),
        CONF_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE,
    },
}

SENSORS_GENERIC = [SENSOR_OUTSIDE_TEMPERATURE, SENSOR_SUPPLY_TEMPERATURE]

SENSORS_BY_HEATINGTYPE = {
    HeatingType.gas: [
        SENSOR_BOILER_TEMPERATURE,
        SENSOR_BURNER_HOURS,
        SENSOR_BURNER_MODULATION,
        SENSOR_BURNER_STARTS,
        SENSOR_BURNER_POWER,
        SENSOR_DHW_GAS_CONSUMPTION_TODAY,
        SENSOR_DHW_GAS_CONSUMPTION_THIS_WEEK,
        SENSOR_DHW_GAS_CONSUMPTION_THIS_MONTH,
        SENSOR_DHW_GAS_CONSUMPTION_THIS_YEAR,
        SENSOR_GAS_CONSUMPTION_TODAY,
        SENSOR_GAS_CONSUMPTION_THIS_WEEK,
        SENSOR_GAS_CONSUMPTION_THIS_MONTH,
        SENSOR_GAS_CONSUMPTION_THIS_YEAR,
    ],
    HeatingType.heatpump: [
        SENSOR_COMPRESSOR_HOURS,
        SENSOR_COMPRESSOR_STARTS,
        SENSOR_RETURN_TEMPERATURE,
    ],
}


def setup_platform(hass, config, add_entities, discovery_info=None):
    """Create the ViCare sensor devices."""
    if discovery_info is None:
        return

    vicare_api = hass.data[VICARE_DOMAIN][VICARE_API]
    heating_type = hass.data[VICARE_DOMAIN][VICARE_HEATING_TYPE]

    sensors = SENSORS_GENERIC.copy()

    if heating_type != HeatingType.generic:
        sensors.extend(SENSORS_BY_HEATINGTYPE[heating_type])

    add_entities(
        [
            ViCareSensor(hass.data[VICARE_DOMAIN][VICARE_NAME], vicare_api, sensor)
            for sensor in sensors
        ]
    )


class ViCareSensor(Entity):
    """Representation of a ViCare sensor."""

    def __init__(self, name, api, sensor_type):
        """Initialize the sensor."""
        self._sensor = SENSOR_TYPES[sensor_type]
        self._name = f"{name} {self._sensor[CONF_NAME]}"
        self._api = api
        self._sensor_type = sensor_type
        self._state = None

    @property
    def available(self):
        """Return True if entity is available."""
        return self._state is not None and self._state != PYVICARE_ERROR

    @property
    def unique_id(self):
        """Return a unique ID."""
        return f"{self._api.service.id}-{self._sensor_type}"

    @property
    def name(self):
        """Return the name of the sensor."""
        return self._name

    @property
    def icon(self):
        """Icon to use in the frontend, if any."""
        return self._sensor[CONF_ICON]

    @property
    def state(self):
        """Return the state of the sensor."""
        return self._state

    @property
    def unit_of_measurement(self):
        """Return the unit of measurement."""
        return self._sensor[CONF_UNIT_OF_MEASUREMENT]

    @property
    def device_class(self):
        """Return the class of this device, from component DEVICE_CLASSES."""
        return self._sensor[CONF_DEVICE_CLASS]

    def update(self):
        """Update state of sensor."""
        try:
            self._state = self._sensor[CONF_GETTER](self._api)
        except requests.exceptions.ConnectionError:
            _LOGGER.error("Unable to retrieve data from ViCare server")
        except ValueError:
            _LOGGER.error("Unable to decode data from ViCare server")
