# pylint: disable=line-too-long, too-many-lines, invalid-name

"""Config flow for Versatile Thermostat integration."""
from __future__ import annotations

from typing import Any
import re
from vtherm_api.log_collector import get_vtherm_logger
import copy
from collections.abc import Mapping  # pylint: disable=import-error
import voluptuous as vol

from homeassistant.core import callback
from homeassistant.config_entries import (
    ConfigEntry,
    ConfigFlow as HAConfigFlow,
    OptionsFlow,
)
from homeassistant.const import UnitOfTemperature

from homeassistant.data_entry_flow import FlowHandler, FlowResult

from .const import *  # pylint: disable=wildcard-import, unused-wildcard-import
from .config_schema import *  # pylint: disable=wildcard-import, unused-wildcard-import
from .vtherm_central_api import VersatileThermostatAPI
from .commons import check_and_extract_service_configuration

COMES_FROM = "comes_from"
PLUGINS_LINK_PLACEHOLDER = "plugins_link"
PLUGINS_LINK = "[plugins](https://www.versatile-thermostat.org/en/plugins/)"

_LOGGER = get_vtherm_logger(__name__)

def add_suggested_values_to_schema(
    data_schema: vol.Schema, suggested_values: Mapping[str, Any]
) -> vol.Schema:
    """Make a copy of the schema, populated with suggested values.

    For each schema marker matching items in `suggested_values`,
    the `suggested_value` will be set. The existing `suggested_value` will
    be left untouched if there is no matching item.
    """
    schema = {}
    for key, val in data_schema.schema.items():
        new_key = key
        if key in suggested_values and isinstance(key, vol.Marker):
            # Copy the marker to not modify the flow schema
            new_key = copy.copy(key)
            new_key.description = {"suggested_value": suggested_values[key]}
        schema[new_key] = val
    _LOGGER.debug("add_suggested_values_to_schema: schema=%s", schema)
    return vol.Schema(schema)


class VersatileThermostatBaseConfigFlow(FlowHandler):
    """The base Config flow class. Used to put some code in commons."""

    VERSION = CONFIG_VERSION
    MINOR_VERSION = CONFIG_MINOR_VERSION

    def __init__(self, infos) -> None:
        super().__init__()
        _LOGGER.debug("CTOR BaseConfigFlow infos: %s", infos)
        self._infos: dict = infos
        self._learning_type_changed = False
        self._placeholders = {
            CONF_NAME: "",
            PLUGINS_LINK_PLACEHOLDER: PLUGINS_LINK,
        }

        # VTherm API should have been initialized before arriving here
        vtherm_api = VersatileThermostatAPI.get_vtherm_api()
        if vtherm_api is not None:
            self._central_config = vtherm_api.find_central_configuration()
        else:
            self._central_config = None

        self._init_central_config_flags(infos)
        self._init_feature_flags(infos)

    def _init_feature_flags(self, _):
        """Fix features selection depending to infos"""
        is_central_config = (
            self._infos.get(CONF_THERMOSTAT_TYPE) == CONF_THERMOSTAT_CENTRAL_CONFIG
        )

        self._infos[CONF_USE_WINDOW_FEATURE] = (
            self._infos.get(CONF_USE_WINDOW_CENTRAL_CONFIG, False)
            or self._infos.get(CONF_WINDOW_SENSOR) is not None
            or self._infos.get(CONF_WINDOW_AUTO_OPEN_THRESHOLD) is not None
        )
        self._infos[CONF_USE_MOTION_FEATURE] = self._infos.get(
            CONF_USE_MOTION_FEATURE, False
        ) and (self._infos.get(CONF_MOTION_SENSOR) is not None or is_central_config)

        self._infos[CONF_USE_POWER_FEATURE] = (
            self._infos.get(CONF_USE_POWER_CENTRAL_CONFIG, False)
            or self._infos.get(CONF_USE_POWER_FEATURE, False)
            or (is_central_config and self._infos.get(CONF_POWER_SENSOR) is not None and self._infos.get(CONF_MAX_POWER_SENSOR) is not None)
        )
        self._infos[CONF_USE_PRESENCE_FEATURE] = (
            self._infos.get(CONF_USE_PRESENCE_CENTRAL_CONFIG, False)
            or self._infos.get(CONF_PRESENCE_SENSOR) is not None
        )

        self._infos[CONF_USE_CENTRAL_BOILER_FEATURE] = (
            self._infos.get(CONF_CENTRAL_BOILER_ACTIVATION_SRV) is not None
            and self._infos.get(CONF_CENTRAL_BOILER_DEACTIVATION_SRV) is not None
        )

        self._infos[CONF_USE_AUTO_START_STOP_FEATURE] = (
            self._infos.get(CONF_USE_AUTO_START_STOP_FEATURE, False) is True
            and self._infos.get(CONF_THERMOSTAT_TYPE) == CONF_THERMOSTAT_CLIMATE
        )

        self._infos[CONF_USE_HEATING_FAILURE_DETECTION_FEATURE] = self._infos.get(
            CONF_USE_HEATING_FAILURE_DETECTION_FEATURE, False
        )

    def _init_central_config_flags(self, infos):
        """Initialisation of central configuration flags"""
        is_empty: bool = not bool(infos)
        for config in (
            CONF_USE_MAIN_CENTRAL_CONFIG,
            CONF_USE_TPI_CENTRAL_CONFIG,
            CONF_USE_WINDOW_CENTRAL_CONFIG,
            CONF_USE_MOTION_CENTRAL_CONFIG,
            CONF_USE_POWER_CENTRAL_CONFIG,
            CONF_USE_PRESETS_CENTRAL_CONFIG,
            CONF_USE_PRESENCE_CENTRAL_CONFIG,
            CONF_USE_ADVANCED_CENTRAL_CONFIG,
            CONF_USE_LOCK_CENTRAL_CONFIG,
            CONF_USE_CENTRAL_MODE,
        ):
            if not is_empty:
                current_config = self._infos.get(config, None)

                self._infos[config] = self._central_config is not None and (
                    current_config is True or current_config is None
                )
                # self._infos[config] = current_config is True or (
                #     current_config is None and self._central_config is not None
                # )
            else:
                self._infos[config] = self._central_config is not None

        if COMES_FROM in self._infos:
            del self._infos[COMES_FROM]

    def is_valve_regulation_selected(self, infos) -> bool:
        """True of the valve regulation mode is selected"""
        return infos.get(CONF_AUTO_REGULATION_MODE, None) == CONF_AUTO_REGULATION_VALVE

    def is_sync_device_internal_temp_selected(self, infos) -> bool:
        """True if the synchronize device internal temperature mode is selected"""
        return infos.get(CONF_SYNC_DEVICE_INTERNAL_TEMP, False) is True

    def check_valve_regulation_nb_entities(self, data: dict, step_id=None) -> bool:
        """Check the number of entities for Valve regulation"""
        if step_id not in ["type", "valve_regulation", "check_complete"]:
            return True

        underlyings_to_check = data if step_id == "type" else self._infos
        # underlyings_to_check = self._infos  # data if step_id == "type" else self._infos
        regulation_infos_to_check = (
            data if step_id == "valve_regulation" else self._infos
        )

        ret = True
        if (
            self.is_valve_regulation_selected(underlyings_to_check)
            and step_id != "type"
        ):
            nb_unders = len(underlyings_to_check.get(CONF_UNDERLYING_LIST))
            nb_opening = len(
                regulation_infos_to_check.get(CONF_OPENING_DEGREE_LIST, [])
            )
            nb_closing = len(
                regulation_infos_to_check.get(CONF_CLOSING_DEGREE_LIST, [])
            )
            if nb_unders != nb_opening or (nb_unders != nb_closing and nb_closing > 0):
                ret = False
        return ret

    def check_sync_device_internal_temp_nb_entities(self, data: dict, step_id=None) -> bool:
        """Check the number of entities for synchronize device internal temperature"""
        if step_id not in ["type", "sync_device_internal_temp", "check_complete"]:
            return True

        underlyings_to_check = data if step_id == "type" else self._infos
        # underlyings_to_check = self._infos  # data if step_id == "type" else self._infos
        regulation_infos_to_check = data if step_id == "sync_device_internal_temp" else self._infos

        ret = True
        if self.is_sync_device_internal_temp_selected(underlyings_to_check) and step_id != "type":
            nb_unders = len(underlyings_to_check.get(CONF_UNDERLYING_LIST))
            nb_sync = len(regulation_infos_to_check.get(CONF_SYNC_ENTITY_LIST, []))
            if nb_unders != nb_sync:
                ret = False
        return ret

    async def validate_input(self, data: dict, step_id) -> None:
        """Validate the user input allows us to connect.

        Data has the keys from STEP_*_DATA_SCHEMA with values provided by the user.
        """

        # check the entity_ids
        for conf in [
            CONF_UNDERLYING_LIST,
            CONF_TEMP_SENSOR,
            CONF_EXTERNAL_TEMP_SENSOR,
            CONF_WINDOW_SENSOR,
            CONF_MOTION_SENSOR,
            CONF_POWER_SENSOR,
            CONF_MAX_POWER_SENSOR,
            CONF_PRESENCE_SENSOR,
            CONF_OFFSET_CALIBRATION_LIST,
            CONF_OPENING_DEGREE_LIST,
            CONF_CLOSING_DEGREE_LIST,
        ]:
            d = data.get(conf, None)  # pylint: disable=invalid-name
            if not isinstance(d, list):
                d = [d]
            for e in d:
                if e is not None and self.hass.states.get(e) is None:
                    _LOGGER.error(
                        "Entity id %s doesn't have any state. We cannot use it in the Versatile Thermostat configuration",  # pylint: disable=line-too-long
                        e,
                    )
                    raise UnknownEntity(conf)

        # Check that only one window feature is used
        ws = self._infos.get(CONF_WINDOW_SENSOR)  # pylint: disable=invalid-name
        waot = data.get(CONF_WINDOW_AUTO_OPEN_THRESHOLD)
        wact = data.get(CONF_WINDOW_AUTO_CLOSE_THRESHOLD)
        wamd = data.get(CONF_WINDOW_AUTO_MAX_DURATION)
        if ws is not None and (
            waot is not None or wact is not None or wamd is not None
        ):
            _LOGGER.error(
                "Only one window detection method should be used. Use window_sensor or auto window open detection but not both"
            )
            raise WindowOpenDetectionMethod(CONF_WINDOW_AUTO_OPEN_THRESHOLD)

        # Check that is USE_CENTRAL config is used, that a central config exists
        if self._central_config is None:
            for conf in [
                CONF_USE_MAIN_CENTRAL_CONFIG,
                CONF_USE_TPI_CENTRAL_CONFIG,
                CONF_USE_WINDOW_CENTRAL_CONFIG,
                CONF_USE_MOTION_CENTRAL_CONFIG,
                CONF_USE_POWER_CENTRAL_CONFIG,
                CONF_USE_PRESENCE_CENTRAL_CONFIG,
                CONF_USE_PRESETS_CENTRAL_CONFIG,
                CONF_USE_ADVANCED_CENTRAL_CONFIG,
                CONF_USE_CENTRAL_MODE,
                # CONF_USE_CENTRAL_BOILER_FEATURE, this is for Central Config
                CONF_USED_BY_CENTRAL_BOILER,
            ]:
                if data.get(conf) is True:
                    _LOGGER.error(
                        "The use of central configuration need a central configuration Versatile Thermostat instance"
                    )
                    raise NoCentralConfig(conf)

        # Check the service for central boiler format
        if self._infos.get(CONF_USE_CENTRAL_BOILER_FEATURE):
            for conf in [
                CONF_CENTRAL_BOILER_ACTIVATION_SRV,
                CONF_CENTRAL_BOILER_DEACTIVATION_SRV,
            ]:
                try:
                    check_and_extract_service_configuration(data.get(conf))
                except ServiceConfigurationError as err:
                    raise ServiceConfigurationError(conf) from err

        # Check that the number of offet_calibration and opening_degree and closing_degree are equals
        # to the number of underlying entities
        if not self.check_valve_regulation_nb_entities(data, step_id):
            raise ValveRegulationNbEntitiesIncorrect()

        if not self.check_sync_device_internal_temp_nb_entities(data, step_id):
            raise SyncDeviceInternalTempNbEntitiesIncorrect()

        # Check that the min_opening_degrees is correctly set
        raw_list = data.get(CONF_MIN_OPENING_DEGREES, None)
        min_opening_degrees_list = []
        if raw_list:
            try:
                # Validation : Convertir la liste saisie
                min_opening_degrees_list = [int(x.strip()) for x in raw_list.split(",")]

                # Optionnel : Vérifiez des conditions supplémentaires sur la liste
                if any(x < 0 for x in min_opening_degrees_list):
                    raise ValueError
            except ValueError as exc:
                raise ValveRegulationMinOpeningDegreesIncorrect(
                    CONF_MIN_OPENING_DEGREES
                ) from exc

        # Check that the max_opening_degrees is correctly set
        raw_list = data.get(CONF_MAX_OPENING_DEGREES, None)
        max_opening_degrees_list = []
        if raw_list:
            try:
                # Validation : Convertir la liste saisie
                max_opening_degrees_list = [int(x.strip()) for x in raw_list.split(",")]

                # Check that max opening degrees are <= the underlying valve max opening and > 0
                valves_entities = data.get(CONF_OPENING_DEGREE_LIST, [])
                for valve_idx, valve_max in enumerate(max_opening_degrees_list):
                    if valve_max <= 0 or valve_max > self.hass.states.get(valves_entities[valve_idx]).attributes.get("max", 100):
                        raise ValueError
            except ValueError as exc:
                raise ValveRegulationMaxOpeningDegreesIncorrect(
                    CONF_MAX_OPENING_DEGREES
                ) from exc

        # Check that max_opening_degrees > min_opening_degrees for each underlying
        # If both lists exist, check that max > min for each index
        if min_opening_degrees_list and max_opening_degrees_list:
            # Get the number of underlyings to know how many values to check
            nb_underlyings = len(self._infos.get(CONF_UNDERLYING_LIST, []))
            for idx in range(nb_underlyings):
                min_val = min_opening_degrees_list[idx] if idx < len(min_opening_degrees_list) else 0
                max_val = max_opening_degrees_list[idx] if idx < len(max_opening_degrees_list) else 100

                if max_val <= min_val:
                    raise ValveRegulationMinMaxOpeningDegreesIncorrect(
                        CONF_MAX_OPENING_DEGREES
                    )

        # Check the VSWITCH configuration. There should be the same number of vswitch_on (resp. vswitch_off) than the number of underlying entity
        if self._infos.get(CONF_THERMOSTAT_TYPE) == CONF_THERMOSTAT_SWITCH and step_id == "type":
            if not self.check_vswitch_configuration(data):
                raise VirtualSwitchConfigurationIncorrect(CONF_VSWITCH_ON_CMD_LIST)

        # Check the lock code format
        if data.get(CONF_LOCK_CODE) is not None:
            if not re.match(r"^\d{4}$", str(data.get(CONF_LOCK_CODE))):
                raise LockCodeIncorrect()

    def check_vswitch_configuration(self, data) -> bool:
        """Check the Virtual switch configuration and return True if the configuration is correct"""
        nb_under = len(data.get(CONF_UNDERLYING_LIST, []))

        # check format of each command_on
        for command in data.get(CONF_VSWITCH_ON_CMD_LIST, []) + data.get(CONF_VSWITCH_OFF_CMD_LIST, []):
            pattern = r"^(?P<command>[^\s/]+)(?:/(?P<argument>[^\s:]+)(?::(?P<value>[^\s]+))?)?$"
            if not re.match(pattern, command):
                return False

        nb_command_on = len(data.get(CONF_VSWITCH_ON_CMD_LIST, []))
        nb_command_off = len(data.get(CONF_VSWITCH_OFF_CMD_LIST, []))
        if (nb_command_on == nb_under or nb_command_on == 0) and (nb_command_off == nb_under or nb_command_off == 0):
            # There is enough command_on and off
            # Check if one under is not a switch (which have default command).
            if any(
                not thermostat_type.startswith(SWITCH_DOMAIN) and not thermostat_type.startswith(INPUT_BOOLEAN_DOMAIN) for thermostat_type in data.get(CONF_UNDERLYING_LIST, [])
            ):
                if nb_command_on != nb_under or nb_command_off != nb_under:
                    return False
            return True
        return False

    def check_config_complete(self, infos) -> bool:
        """True if the config is now complete (ie all mandatory attributes are set)"""
        is_central_config = (
            infos.get(CONF_THERMOSTAT_TYPE) == CONF_THERMOSTAT_CENTRAL_CONFIG
        )
        if is_central_config:
            if (
                infos.get(CONF_NAME) is None
                or infos.get(CONF_EXTERNAL_TEMP_SENSOR) is None
            ):
                return False

            if infos.get(CONF_USE_POWER_FEATURE, False) is True and (
                infos.get(CONF_POWER_SENSOR, None) is None
                or infos.get(CONF_MAX_POWER_SENSOR, None) is None
            ):
                return False

            if (
                infos.get(CONF_USE_PRESENCE_FEATURE, False) is True
                and infos.get(CONF_PRESENCE_SENSOR, None) is None
            ):
                return False

            if self._infos[CONF_USE_CENTRAL_BOILER_FEATURE] and (
                not self._infos.get(CONF_CENTRAL_BOILER_ACTIVATION_SRV, False)
                or len(self._infos.get(CONF_CENTRAL_BOILER_ACTIVATION_SRV)) <= 0
                or not self._infos.get(CONF_CENTRAL_BOILER_DEACTIVATION_SRV, False)
                or len(self._infos.get(CONF_CENTRAL_BOILER_DEACTIVATION_SRV)) <= 0
            ):
                return False
        else:
            if (
                infos.get(CONF_NAME) is None
                or infos.get(CONF_TEMP_SENSOR) is None
                or infos.get(CONF_CYCLE_MIN) is None
            ):
                return False

            if (
                infos.get(CONF_USE_MAIN_CENTRAL_CONFIG, False) is False
                and infos.get(CONF_EXTERNAL_TEMP_SENSOR) is None
            ):
                return False

            # checks that at least one underlying is set but not it central configuration
            if len(infos.get(CONF_UNDERLYING_LIST, [])) < 1:
                return False

            if (
                infos.get(CONF_USE_MOTION_FEATURE, False) is True
                and infos.get(CONF_MOTION_SENSOR, None) is None
            ):
                return False

            if infos.get(CONF_USE_POWER_FEATURE, False) is True and infos.get(CONF_USE_POWER_CENTRAL_CONFIG, False) is False and infos.get(CONF_PRESET_POWER, None) is None:
                return False

            if (
                infos.get(CONF_USE_PRESENCE_FEATURE, False) is True
                and infos.get(CONF_USE_PRESENCE_CENTRAL_CONFIG, False) is False
                and infos.get(CONF_PRESENCE_SENSOR, None) is None
            ):
                return False

            if infos.get(CONF_USE_ADVANCED_CENTRAL_CONFIG, False) is False and (
                infos.get(CONF_SAFETY_DELAY_MIN, -1) == -1 or infos.get(CONF_SAFETY_MIN_ON_PERCENT, -1) == -1 or infos.get(CONF_SAFETY_DEFAULT_ON_PERCENT, -1) == -1
            ):
                return False

            if (
                infos.get(CONF_PROP_FUNCTION, None) == PROPORTIONAL_FUNCTION_TPI
                and infos.get(CONF_USE_TPI_CENTRAL_CONFIG, False) is False
                and (
                    infos.get(CONF_TPI_COEF_INT, None) is None
                    or infos.get(CONF_TPI_COEF_EXT) is None
                )
            ):
                return False

            if (
                infos.get(CONF_USE_PRESETS_CENTRAL_CONFIG, False) is True
                and self._central_config is None
            ):
                return False

            if not self.check_valve_regulation_nb_entities(infos, "check_complete"):
                return False

            if not self.check_sync_device_internal_temp_nb_entities(infos, "check_complete"):
                return False

        return True

    def merge_user_input(self, data_schema: vol.Schema, user_input: dict):
        """For each schema entry not in user_input, set or remove values in infos"""
        self._infos.update(user_input)
        for key, _ in data_schema.schema.items():
            if key not in user_input and isinstance(key, vol.Marker):
                _LOGGER.debug(
                    "add_empty_values_to_user_input: %s is not in user_input", key
                )
                if key in self._infos:
                    self._infos.pop(key)
            # else:  This don't work but I don't know why. _infos seems broken after this (Not serializable exactly)
            #     self._infos[key] = user_input[key]

        _LOGGER.debug("merge_user_input: infos is now %s", self._infos)

    async def generic_step(self, step_id, data_schema, user_input, next_step_function):
        """A generic method step"""
        _LOGGER.debug(
            "Into ConfigFlow.async_step_%s user_input=%s", step_id, user_input
        )

        defaults = self._infos.copy()
        errors = {}

        if user_input is not None:
            defaults.update(user_input or {})
            try:
                await self.validate_input(user_input, step_id)
            except UnknownEntity as err:
                errors[str(err)] = "unknown_entity"
            except WindowOpenDetectionMethod as err:
                errors[str(err)] = "window_open_detection_method"
            except NoCentralConfig as err:
                errors[str(err)] = "no_central_config"
            except ServiceConfigurationError as err:
                errors[str(err)] = "service_configuration_format"
            except ConfigurationNotCompleteError as err:
                errors["base"] = "configuration_not_complete"
            except ValveRegulationNbEntitiesIncorrect as err:
                errors["base"] = "valve_regulation_nb_entities_incorrect"
            except SyncDeviceInternalTempNbEntitiesIncorrect as err:
                errors["base"] = "sync_device_internal_temp_nb_entities_incorrect"
            except ValveRegulationMinOpeningDegreesIncorrect as err:
                errors[str(err)] = "min_opening_degrees_format"
            except ValveRegulationMaxOpeningDegreesIncorrect as err:
                errors[str(err)] = "max_opening_degrees_format"
            except ValveRegulationMinMaxOpeningDegreesIncorrect as err:
                errors[str(err)] = "min_max_opening_degrees_inconsistent"
            except VirtualSwitchConfigurationIncorrect as err:
                errors["base"] = "vswitch_configuration_incorrect"
            except LockCodeIncorrect:
                errors["base"] = "lock_code_incorrect"
            except Exception:  # pylint: disable=broad-except
                _LOGGER.exception("Unexpected exception")
                errors["base"] = "unknown"
            else:
                self.merge_user_input(data_schema, user_input)
                # Add default values for central config flags
                self._init_central_config_flags(self._infos)
                _LOGGER.debug("_info is now: %s", self._infos)
                return await next_step_function()

        # ds = schema_defaults(data_schema, **defaults)  # pylint: disable=invalid-name
        ds = add_suggested_values_to_schema(
            data_schema=data_schema, suggested_values=defaults
        )  # pylint: disable=invalid-name

        return self.async_show_form(
            step_id=step_id,
            data_schema=ds,
            errors=errors,
            description_placeholders=self._placeholders,
        )

    async def async_step_user(self, user_input: dict | None = None) -> FlowResult:
        """Handle the flow steps"""
        _LOGGER.debug("Into ConfigFlow.async_step_user user_input=%s", user_input)

        # Always do a fresh lookup (not from __init__ cache) to handle same-session deletions
        vtherm_api = VersatileThermostatAPI.get_vtherm_api()
        central_config = vtherm_api.find_central_configuration() if vtherm_api else None

        # Exclude the central config type if one already exists (it must be unique)
        if central_config is not None:
            available_types = [t for t in CONF_THERMOSTAT_TYPES if t != CONF_THERMOSTAT_CENTRAL_CONFIG]
            schema = vol.Schema(
                {
                    vol.Required(CONF_THERMOSTAT_TYPE, default=CONF_THERMOSTAT_SWITCH): selector.SelectSelector(
                        selector.SelectSelectorConfig(
                            options=available_types,
                            translation_key="thermostat_type",
                            mode="list",
                        )
                    )
                }
            )
        else:
            schema = STEP_USER_DATA_SCHEMA

        return await self.generic_step("user", schema, user_input, self.async_step_menu)

    async def async_step_configuration_not_complete(
        self, user_input: dict | None = None
    ) -> FlowResult:
        """A fake step to handle the incomplete configuration flow"""
        return await self.async_step_menu(user_input)

    async def async_step_menu(self, user_input: dict | None = None) -> FlowResult:
        """Handle the flow steps"""
        _LOGGER.debug("Into ConfigFlow.async_step_menu user_input=%s", user_input)

        is_central_config = self._infos.get(CONF_THERMOSTAT_TYPE) == CONF_THERMOSTAT_CENTRAL_CONFIG

        menu_options = ["main", "features"]
        if not is_central_config:
            menu_options.append("type")

        if (
            self._infos.get(CONF_PROP_FUNCTION) == PROPORTIONAL_FUNCTION_TPI
            or is_central_config
            or self.is_valve_regulation_selected(self._infos)
        ):
            menu_options.append("tpi")

        if self._infos.get(CONF_THERMOSTAT_TYPE) in [
            CONF_THERMOSTAT_SWITCH,
            CONF_THERMOSTAT_VALVE,
            CONF_THERMOSTAT_CLIMATE,
        ]:
            menu_options.append("presets")

        if is_central_config and self._infos.get(CONF_USE_CENTRAL_BOILER_FEATURE, False) is True:
            menu_options.append("central_boiler")

        if self._infos.get(CONF_USE_WINDOW_FEATURE, False) is True:
            menu_options.append("window")

        if self._infos.get(CONF_USE_MOTION_FEATURE, False) is True:
            menu_options.append("motion")

        if self._infos.get(CONF_USE_POWER_FEATURE, False) is True:
            menu_options.append("power")

        if self._infos.get(CONF_USE_PRESENCE_FEATURE, False) is True:
            menu_options.append("presence")

        if (
            self._infos.get(CONF_USE_AUTO_START_STOP_FEATURE, False) is True
            and self._infos[CONF_THERMOSTAT_TYPE]
            in [
                CONF_THERMOSTAT_CLIMATE,
            ]
            and not self.is_valve_regulation_selected(self._infos)
        ):
            menu_options.append("auto_start_stop")

        if self.is_valve_regulation_selected(self._infos):
            menu_options.append("valve_regulation")

        if self._infos.get(CONF_SYNC_DEVICE_INTERNAL_TEMP, False) is True:
            menu_options.append("sync_device_internal_temp")

        menu_options.append("advanced")
        menu_options.append("lock")

        # Add heating failure detection menu if feature is enabled
        if self._infos.get(CONF_USE_HEATING_FAILURE_DETECTION_FEATURE, False) is True:
            menu_options.append("heating_failure_detection")

        if self.check_config_complete(self._infos):
            menu_options.append("finalize")
        else:
            _LOGGER.info("The configuration is not terminated")
            menu_options.append("configuration_not_complete")

        return self.async_show_menu(
            step_id="menu",
            menu_options=menu_options,
            description_placeholders=self._placeholders,
        )

    async def async_step_main(self, user_input: dict | None = None) -> FlowResult:
        """Handle the flow steps"""
        _LOGGER.debug("Into ConfigFlow.async_step_main user_input=%s", user_input)

        next_step = self.async_step_menu
        if self._infos[CONF_THERMOSTAT_TYPE] == CONF_THERMOSTAT_CENTRAL_CONFIG:
            self._infos[CONF_NAME] = CENTRAL_CONFIG_NAME
            schema = STEP_CENTRAL_MAIN_DATA_SCHEMA
        else:
            schema = STEP_MAIN_DATA_SCHEMA

            if (
                user_input
                and user_input.get(CONF_USE_MAIN_CENTRAL_CONFIG, False) is False
            ):
                if user_input and self._infos.get(COMES_FROM) == "async_step_spec_main":
                    schema = STEP_CENTRAL_MAIN_DATA_SCHEMA
                    del self._infos[COMES_FROM]
                else:
                    next_step = self.async_step_spec_main

        # Add default values for temperature if not set
        if self._infos.get(CONF_TEMP_MIN) is None:
            # We use the system default unit
            unit = self.hass.config.units.temperature_unit
            if unit == UnitOfTemperature.FAHRENHEIT:
                self._infos[CONF_TEMP_MIN] = 45
                self._infos[CONF_TEMP_MAX] = 95
                self._infos[CONF_STEP_TEMPERATURE] = 1.0
            else:
                self._infos[CONF_TEMP_MIN] = 7
                self._infos[CONF_TEMP_MAX] = 35
                self._infos[CONF_STEP_TEMPERATURE] = 0.1

        return await self.generic_step("main", schema, user_input, next_step)

    async def async_step_spec_main(self, user_input: dict | None = None) -> FlowResult:
        """Handle the specific main flow steps"""
        _LOGGER.debug("Into ConfigFlow.async_step_spec_main user_input=%s", user_input)

        if self._infos[CONF_THERMOSTAT_TYPE] == CONF_THERMOSTAT_CENTRAL_CONFIG:
            schema = STEP_CENTRAL_MAIN_DATA_SCHEMA
        else:
            schema = STEP_CENTRAL_SPEC_MAIN_DATA_SCHEMA
        next_step = self.async_step_menu

        self._infos[COMES_FROM] = "async_step_spec_main"

        # This will return to async_step_main (to keep the "main" step)
        return await self.generic_step("main", schema, user_input, next_step)

    async def async_step_central_boiler(
        self, user_input: dict | None = None
    ) -> FlowResult:
        """Handle the central boiler flow steps"""
        _LOGGER.debug(
            "Into ConfigFlow.async_step_central_boiler user_input=%s", user_input
        )

        schema = STEP_CENTRAL_BOILER_SCHEMA
        next_step = self.async_step_menu

        return await self.generic_step("central_boiler", schema, user_input, next_step)

    async def async_step_type(self, user_input: dict | None = None) -> FlowResult:
        """Handle the Type flow steps"""
        _LOGGER.debug("Into ConfigFlow.async_step_type user_input=%s", user_input)

        if (
            self._infos[CONF_THERMOSTAT_TYPE] == CONF_THERMOSTAT_CLIMATE
            and user_input is not None
            and not self.is_valve_regulation_selected(user_input)
        ):
            # Remove TPI info
            for key in [
                CONF_PROP_FUNCTION,
                CONF_TPI_COEF_INT,
                CONF_TPI_COEF_EXT,
                CONF_OFFSET_CALIBRATION_LIST,
                CONF_OPENING_DEGREE_LIST,
                CONF_CLOSING_DEGREE_LIST,
            ]:
                if self._infos.get(key):
                    del self._infos[key]

        if self._infos[CONF_THERMOSTAT_TYPE] == CONF_THERMOSTAT_SWITCH:
            return await self.generic_step(
                "type", build_step_thermostat_switch_schema(), user_input, self.async_step_menu
            )
        elif self._infos[CONF_THERMOSTAT_TYPE] == CONF_THERMOSTAT_VALVE:
            return await self.generic_step(
                "type", build_step_thermostat_valve_schema(), user_input, self.async_step_menu
            )
        else:
            return await self.generic_step(
                "type",
                STEP_THERMOSTAT_CLIMATE,
                user_input,
                self.async_step_menu,
            )

    async def async_step_features(self, user_input: dict | None = None) -> FlowResult:
        """Handle the Type flow steps"""
        _LOGGER.debug("Into ConfigFlow.async_step_features user_input=%s", user_input)

        schema = STEP_FEATURES_DATA_SCHEMA
        if self._infos[CONF_THERMOSTAT_TYPE] == CONF_THERMOSTAT_CENTRAL_CONFIG:
            schema = STEP_CENTRAL_FEATURES_DATA_SCHEMA
        elif self._infos[CONF_THERMOSTAT_TYPE] == CONF_THERMOSTAT_CLIMATE and not self.is_valve_regulation_selected(self._infos):
            schema = STEP_CLIMATE_FEATURES_DATA_SCHEMA
        elif self._infos[CONF_THERMOSTAT_TYPE] == CONF_THERMOSTAT_CLIMATE and self.is_valve_regulation_selected(self._infos):
            schema = STEP_CLIMATE_VALVE_FEATURES_DATA_SCHEMA

        return await self.generic_step(
            "features",
            schema,
            user_input,
            self.async_step_menu,
        )

    async def async_step_auto_start_stop(self, user_input: dict | None = None) -> FlowResult:
        """ Handle the Auto start stop step"""
        _LOGGER.debug("Into ConfigFlow.async_step_auto_start_stop user_input=%s", user_input)

        schema = STEP_AUTO_START_STOP
        self._infos[COMES_FROM] = None
        next_step = self.async_step_menu

        return await self.generic_step("auto_start_stop", schema, user_input, next_step)

    async def async_step_valve_regulation(
        self, user_input: dict | None = None
    ) -> FlowResult:
        """Handle the valve regulation configuration step"""
        _LOGGER.debug(
            "Into ConfigFlow.async_step_valve_regulation user_input=%s", user_input
        )

        schema = build_step_valve_regulation_schema()
        self._infos[COMES_FROM] = None
        next_step = self.async_step_menu

        return await self.generic_step(
            "valve_regulation", schema, user_input, next_step
        )

    async def async_step_sync_device_internal_temp(self, user_input: dict | None = None) -> FlowResult:
        """Handle the synchronize device internal temperature configuration step"""
        _LOGGER.debug("Into ConfigFlow.async_step_sync_device_internal_temp user_input=%s", user_input)

        schema = STEP_SYNC_DEVICE_INTERNAL_TEMP
        self._infos[COMES_FROM] = None
        next_step = self.async_step_menu

        return await self.generic_step("sync_device_internal_temp", schema, user_input, next_step)

    async def async_step_tpi(self, user_input: dict | None = None) -> FlowResult:
        """Handle the TPI flow steps"""
        _LOGGER.debug("Into ConfigFlow.async_step_tpi user_input=%s", user_input)

        next_step = self.async_step_menu
        if self._infos[CONF_THERMOSTAT_TYPE] == CONF_THERMOSTAT_CENTRAL_CONFIG:
            schema = STEP_CENTRAL_TPI_DATA_SCHEMA_CENTRAL
        else:
            schema = STEP_TPI_DATA_SCHEMA

            if user_input:
                if user_input.get(CONF_USE_TPI_CENTRAL_CONFIG, False) is False:
                    if self._infos.get(COMES_FROM) == "async_step_spec_tpi":
                        schema = STEP_CENTRAL_TPI_DATA_SCHEMA
                        del self._infos[COMES_FROM]
                        if user_input.get(CONF_AUTO_TPI_MODE) is True:
                            next_step = self.async_step_auto_tpi_configuration
                    else:
                        next_step = self.async_step_spec_tpi
                elif user_input.get(CONF_AUTO_TPI_MODE) is True:
                    next_step = self.async_step_auto_tpi_configuration

        return await self.generic_step("tpi", schema, user_input, next_step)

    async def async_step_spec_tpi(self, user_input: dict | None = None) -> FlowResult:
        """Handle the specific TPI flow steps"""
        _LOGGER.debug("Into ConfigFlow.async_step_spec_tpi user_input=%s", user_input)

        schema = STEP_CENTRAL_TPI_DATA_SCHEMA
        self._infos[COMES_FROM] = "async_step_spec_tpi"
        next_step = self.async_step_menu

        if user_input and user_input.get(CONF_AUTO_TPI_MODE) is True:
            next_step = self.async_step_auto_tpi_configuration

        return await self.generic_step("tpi", schema, user_input, next_step)

    async def async_step_auto_tpi_configuration(self, user_input: dict | None = None) -> FlowResult:
        """Handle the Auto TPI configuration step"""
        _LOGGER.debug(
            "Into ConfigFlow.async_step_auto_tpi_configuration user_input=%s", user_input
        )
        schema = STEP_AUTO_TPI_CONFIGURATION_SCHEMA

        # Logic for next step
        next_step = self._step_auto_tpi_after_configuration

        # Update placeholders with unit
        self._placeholders["temperature_unit"] = self.hass.config.units.temperature_unit
        self._placeholders["unit"] = self.hass.config.units.temperature_unit

        if user_input is not None:
            new_type = user_input.get(CONF_AUTO_TPI_LEARNING_TYPE)
            old_type = self._infos.get(CONF_AUTO_TPI_LEARNING_TYPE)
            if new_type != old_type:
                self._learning_type_changed = True

        return await self.generic_step("auto_tpi_configuration", schema, user_input, next_step)

    async def _step_auto_tpi_after_configuration(self, user_input: dict | None = None) -> FlowResult:
        """Logic after step 1"""
        # Apply defaults if learning type changed or method not set
        if getattr(self, "_learning_type_changed", False) or self._infos.get(CONF_AUTO_TPI_CALCULATION_METHOD) is None:
            self._apply_learning_type_defaults()
            self._learning_type_changed = False

        if self._infos.get(CONF_AUTO_TPI_ENABLE_ADVANCED_SETTINGS, False):
            # Direct jump to method step
            if self._infos.get(CONF_AUTO_TPI_CALCULATION_METHOD) == AUTO_TPI_METHOD_EMA:
                return await self.async_step_auto_tpi_ema_settings()
            else:
                return await self.async_step_auto_tpi_avg_settings()
        else:
            return await self.async_step_menu()

    def _apply_learning_type_defaults(self):
        """Apply defaults based on learning type"""
        learning_type = self._infos.get(CONF_AUTO_TPI_LEARNING_TYPE)

        if learning_type == AUTO_TPI_LEARNING_TYPE_DISCOVERY:
            # Discovery -> Weighted Average, Weight 1
            self._infos[CONF_AUTO_TPI_CALCULATION_METHOD] = AUTO_TPI_METHOD_AVG
            self._infos[CONF_AUTO_TPI_AVG_INITIAL_WEIGHT] = 1
        elif learning_type == AUTO_TPI_LEARNING_TYPE_FINE_TUNING:
            # Fine Tuning -> EMA, Alpha 0.08, Decay 0.12
            self._infos[CONF_AUTO_TPI_CALCULATION_METHOD] = AUTO_TPI_METHOD_EMA
            self._infos[CONF_AUTO_TPI_EMA_ALPHA] = 0.08
            self._infos[CONF_AUTO_TPI_EMA_DECAY_RATE] = 0.12

    async def async_step_auto_tpi_avg_settings(
        self, user_input: dict | None = None
    ) -> FlowResult:
        """Handle the Auto TPI average settings step"""
        _LOGGER.debug(
            "Into ConfigFlow.async_step_auto_tpi_avg_settings user_input=%s", user_input
        )
        schema = STEP_AUTO_TPI_AVG_SETTINGS_SCHEMA
        next_step = self.async_step_menu

        # Update placeholders with unit
        self._placeholders["temperature_unit"] = self.hass.config.units.temperature_unit
        self._placeholders["unit"] = self.hass.config.units.temperature_unit

        return await self.generic_step("auto_tpi_avg_settings", schema, user_input, next_step)

    async def async_step_auto_tpi_ema_settings(
        self, user_input: dict | None = None
    ) -> FlowResult:
        """Handle the Auto TPI EMA settings step"""
        _LOGGER.debug(
            "Into ConfigFlow.async_step_auto_tpi_ema_settings user_input=%s", user_input
        )
        schema = STEP_AUTO_TPI_EMA_SETTINGS_SCHEMA
        next_step = self.async_step_menu
        return await self.generic_step("auto_tpi_ema_settings", schema, user_input, next_step)

    async def async_step_presets(self, user_input: dict | None = None) -> FlowResult:
        """Handle the presets flow steps"""
        _LOGGER.debug("Into ConfigFlow.async_step_presets user_input=%s", user_input)

        next_step = self.async_step_menu  # advanced
        schema = STEP_PRESETS_DATA_SCHEMA

        # In Central config -> display the next step immedialty
        if self._infos[CONF_THERMOSTAT_TYPE] == CONF_THERMOSTAT_CENTRAL_CONFIG:
            # Call directly the next step, we have nothing to display here
            return await self.async_step_window()  #  = self.async_step_window

        return await self.generic_step("presets", schema, user_input, next_step)

    async def async_step_window(self, user_input: dict | None = None) -> FlowResult:
        """Handle the window  sensor flow steps"""
        _LOGGER.debug("Into ConfigFlow.async_step_window user_input=%s", user_input)

        next_step = self.async_step_menu
        if self._infos[CONF_THERMOSTAT_TYPE] == CONF_THERMOSTAT_CENTRAL_CONFIG:
            schema = STEP_CENTRAL_WINDOW_DATA_SCHEMA
        else:
            schema = STEP_WINDOW_DATA_SCHEMA

            if (
                user_input
                and user_input.get(CONF_USE_WINDOW_CENTRAL_CONFIG, False) is False
            ):
                if (
                    user_input
                    and self._infos.get(COMES_FROM) == "async_step_spec_window"
                ):
                    if self._infos.get(CONF_WINDOW_SENSOR) is not None:
                        schema = STEP_CENTRAL_WINDOW_WO_AUTO_DATA_SCHEMA
                    else:
                        schema = STEP_CENTRAL_WINDOW_DATA_SCHEMA
                    del self._infos[COMES_FROM]
                else:
                    next_step = self.async_step_spec_window

        return await self.generic_step("window", schema, user_input, next_step)

    async def async_step_spec_window(
        self, user_input: dict | None = None
    ) -> FlowResult:
        """Handle the specific window flow steps"""
        _LOGGER.debug(
            "Into ConfigFlow.async_step_spec_window user_input=%s", user_input
        )

        schema = STEP_CENTRAL_WINDOW_DATA_SCHEMA
        if self._infos.get(CONF_WINDOW_SENSOR) is not None:
            schema = STEP_CENTRAL_WINDOW_WO_AUTO_DATA_SCHEMA

        self._infos[COMES_FROM] = "async_step_spec_window"

        next_step = self.async_step_motion

        # This will return to async_step_main (to keep the "main" step)
        return await self.generic_step("window", schema, user_input, next_step)

    async def async_step_motion(self, user_input: dict | None = None) -> FlowResult:
        """Handle the window and motion sensor flow steps"""
        _LOGGER.debug("Into ConfigFlow.async_step_motion user_input=%s", user_input)

        next_step = self.async_step_menu
        if self._infos[CONF_THERMOSTAT_TYPE] == CONF_THERMOSTAT_CENTRAL_CONFIG:
            schema = STEP_CENTRAL_MOTION_DATA_SCHEMA
        else:
            schema = STEP_MOTION_DATA_SCHEMA

            if (
                user_input
                and user_input.get(CONF_USE_MOTION_CENTRAL_CONFIG, False) is False
            ):
                if (
                    user_input
                    and self._infos.get(COMES_FROM) == "async_step_spec_motion"
                ):
                    schema = STEP_CENTRAL_MOTION_DATA_SCHEMA
                    del self._infos[COMES_FROM]
                else:
                    next_step = self.async_step_spec_motion

        return await self.generic_step("motion", schema, user_input, next_step)

    async def async_step_spec_motion(
        self, user_input: dict | None = None
    ) -> FlowResult:
        """Handle the specific motion flow steps"""
        _LOGGER.debug(
            "Into ConfigFlow.async_step_spec_motion user_input=%s", user_input
        )

        schema = STEP_CENTRAL_MOTION_DATA_SCHEMA

        self._infos[COMES_FROM] = "async_step_spec_motion"

        next_step = self.async_step_menu

        # This will return to async_step_main (to keep the "main" step)
        return await self.generic_step("motion", schema, user_input, next_step)

    async def async_step_power(self, user_input: dict | None = None) -> FlowResult:
        """Handle the power management flow steps"""
        _LOGGER.debug("Into ConfigFlow.async_step_power user_input=%s", user_input)

        next_step = self.async_step_menu
        if self._infos[CONF_THERMOSTAT_TYPE] == CONF_THERMOSTAT_CENTRAL_CONFIG:
            schema = STEP_CENTRAL_POWER_DATA_SCHEMA
        else:
            schema = STEP_POWER_DATA_SCHEMA

            if (
                user_input
                and user_input.get(CONF_USE_POWER_CENTRAL_CONFIG, False) is False
            ):
                if (
                    user_input
                    and self._infos.get(COMES_FROM) == "async_step_spec_power"
                ):
                    schema = STEP_CENTRAL_POWER_DATA_SCHEMA
                    del self._infos[COMES_FROM]
                else:
                    next_step = self.async_step_spec_power

        return await self.generic_step("power", schema, user_input, next_step)

    async def async_step_spec_power(self, user_input: dict | None = None) -> FlowResult:
        """Handle the specific power flow steps"""
        _LOGGER.debug("Into ConfigFlow.async_step_spec_power user_input=%s", user_input)

        schema = STEP_NON_CENTRAL_POWER_DATA_SCHEMA

        self._infos[COMES_FROM] = "async_step_spec_power"

        next_step = self.async_step_menu

        # This will return to async_step_power (to keep the "power" step)
        return await self.generic_step("power", schema, user_input, next_step)

    async def async_step_presence(self, user_input: dict | None = None) -> FlowResult:
        """Handle the presence management flow steps"""
        _LOGGER.debug("Into ConfigFlow.async_step_presence user_input=%s", user_input)

        next_step = self.async_step_menu
        if self._infos[CONF_THERMOSTAT_TYPE] == CONF_THERMOSTAT_CENTRAL_CONFIG:
            schema = STEP_CENTRAL_PRESENCE_DATA_SCHEMA
        else:
            schema = STEP_PRESENCE_DATA_SCHEMA

            if (
                user_input
                and user_input.get(CONF_USE_PRESENCE_CENTRAL_CONFIG, False) is False
            ):
                if (
                    user_input
                    and self._infos.get(COMES_FROM) == "async_step_spec_presence"
                ):
                    schema = STEP_CENTRAL_PRESENCE_DATA_SCHEMA
                    del self._infos[COMES_FROM]
                else:
                    next_step = self.async_step_spec_presence

        return await self.generic_step("presence", schema, user_input, next_step)

    async def async_step_spec_presence(
        self, user_input: dict | None = None
    ) -> FlowResult:
        """Handle the specific power flow steps"""
        _LOGGER.debug(
            "Into ConfigFlow.async_step_spec_presence user_input=%s", user_input
        )

        schema = STEP_CENTRAL_PRESENCE_DATA_SCHEMA

        self._infos[COMES_FROM] = "async_step_spec_presence"

        next_step = self.async_step_menu

        # This will return to async_step_power (to keep the "power" step)
        return await self.generic_step("presence", schema, user_input, next_step)

    async def async_step_advanced(self, user_input: dict | None = None) -> FlowResult:
        """Handle the advanced parameter flow steps"""
        _LOGGER.debug("Into ConfigFlow.async_step_advanced user_input=%s", user_input)

        next_step = self.async_step_menu
        if self._infos[CONF_THERMOSTAT_TYPE] == CONF_THERMOSTAT_CENTRAL_CONFIG:
            schema = STEP_CENTRAL_ADVANCED_DATA_SCHEMA
        else:
            schema = STEP_ADVANCED_DATA_SCHEMA

            if (
                user_input
                and user_input.get(CONF_USE_ADVANCED_CENTRAL_CONFIG, False) is False
            ):
                if (
                    user_input
                    and self._infos.get(COMES_FROM) == "async_step_spec_advanced"
                ):
                    schema = STEP_CENTRAL_ADVANCED_DATA_SCHEMA
                    del self._infos[COMES_FROM]
                else:
                    next_step = self.async_step_spec_advanced

        return await self.generic_step("advanced", schema, user_input, next_step)

    async def async_step_spec_advanced(
        self, user_input: dict | None = None
    ) -> FlowResult:
        """Handle the specific advanced flow steps"""
        _LOGGER.debug(
            "Into ConfigFlow.async_step_spec_advanced user_input=%s", user_input
        )

        schema = STEP_CENTRAL_ADVANCED_DATA_SCHEMA

        self._infos[COMES_FROM] = "async_step_spec_advanced"

        next_step = self.async_step_advanced

        # This will return to async_step_presence (to keep the "presence" step)
        return await self.generic_step("advanced", schema, user_input, next_step)

    async def async_step_lock(self, user_input: dict | None = None) -> FlowResult:
        """Handle the lock flow steps"""
        _LOGGER.debug("Into ConfigFlow.async_step_lock user_input=%s", user_input)

        next_step = self.async_step_menu
        if self._infos[CONF_THERMOSTAT_TYPE] == CONF_THERMOSTAT_CENTRAL_CONFIG:
            schema = STEP_CENTRAL_LOCK_DATA_SCHEMA
        else:
            schema = STEP_LOCK_DATA_SCHEMA

            if (
                user_input
                and user_input.get(CONF_USE_LOCK_CENTRAL_CONFIG, False) is False
            ):
                if (
                    user_input
                    and self._infos.get(COMES_FROM) == "async_step_spec_lock"
                ):
                    schema = STEP_CENTRAL_LOCK_DATA_SCHEMA
                    del self._infos[COMES_FROM]
                else:
                    next_step = self.async_step_spec_lock

        return await self.generic_step("lock", schema, user_input, next_step)

    async def async_step_spec_lock(
        self, user_input: dict | None = None
    ) -> FlowResult:
        """Handle the specific lock flow steps"""
        _LOGGER.debug(
            "Into ConfigFlow.async_step_spec_lock user_input=%s", user_input
        )

        schema = STEP_CENTRAL_LOCK_DATA_SCHEMA

        self._infos[COMES_FROM] = "async_step_spec_lock"

        next_step = self.async_step_menu

        return await self.generic_step("lock", schema, user_input, next_step)

    async def async_step_heating_failure_detection(self, user_input: dict | None = None) -> FlowResult:
        """Handle the heating failure detection flow steps"""
        _LOGGER.debug("Into ConfigFlow.async_step_heating_failure_detection user_input=%s", user_input)

        next_step = self.async_step_menu
        if self._infos[CONF_THERMOSTAT_TYPE] == CONF_THERMOSTAT_CENTRAL_CONFIG:
            schema = STEP_CENTRAL_HEATING_FAILURE_DETECTION_SCHEMA
        else:
            schema = STEP_HEATING_FAILURE_DETECTION_SCHEMA

            if user_input and user_input.get(CONF_USE_HEATING_FAILURE_DETECTION_CENTRAL_CONFIG, False) is False:
                if user_input and self._infos.get(COMES_FROM) == "async_step_spec_heating_failure_detection":
                    schema = STEP_CENTRAL_HEATING_FAILURE_DETECTION_SCHEMA
                    del self._infos[COMES_FROM]
                else:
                    next_step = self.async_step_spec_heating_failure_detection

        return await self.generic_step("heating_failure_detection", schema, user_input, next_step)

    async def async_step_spec_heating_failure_detection(self, user_input: dict | None = None) -> FlowResult:
        """Handle the specific heating failure detection flow steps"""
        _LOGGER.debug("Into ConfigFlow.async_step_spec_heating_failure_detection user_input=%s", user_input)

        # here we reuse the central schema because it is the same for non central config
        schema = STEP_CENTRAL_HEATING_FAILURE_DETECTION_SCHEMA

        self._infos[COMES_FROM] = "async_step_spec_heating_failure_detection"

        next_step = self.async_step_heating_failure_detection

        return await self.generic_step("heating_failure_detection", schema, user_input, next_step)

    async def async_step_finalize(self, _):
        """Finalize the creation. Should be overriden by underlyings"""
        if not self._infos[CONF_USE_WINDOW_FEATURE]:
            self._infos[CONF_USE_WINDOW_CENTRAL_CONFIG] = False
            if CONF_WINDOW_SENSOR in self._infos:
                del self._infos[CONF_WINDOW_SENSOR]
            if CONF_WINDOW_AUTO_CLOSE_THRESHOLD in self._infos:
                del self._infos[CONF_WINDOW_AUTO_CLOSE_THRESHOLD]
            if CONF_WINDOW_AUTO_OPEN_THRESHOLD in self._infos:
                del self._infos[CONF_WINDOW_AUTO_OPEN_THRESHOLD]
            if CONF_WINDOW_AUTO_MAX_DURATION in self._infos:
                del self._infos[CONF_WINDOW_AUTO_MAX_DURATION]
        if not self._infos[CONF_USE_MOTION_FEATURE]:
            self._infos[CONF_USE_MOTION_CENTRAL_CONFIG] = False
            if CONF_MOTION_SENSOR in self._infos:
                del self._infos[CONF_MOTION_SENSOR]
        if not self._infos[CONF_USE_POWER_FEATURE]:
            self._infos[CONF_USE_POWER_CENTRAL_CONFIG] = False
            if CONF_POWER_SENSOR in self._infos:
                del self._infos[CONF_POWER_SENSOR]
            if CONF_MAX_POWER_SENSOR in self._infos:
                del self._infos[CONF_MAX_POWER_SENSOR]
        if not self._infos[CONF_USE_PRESENCE_FEATURE]:
            self._infos[CONF_USE_PRESENCE_CENTRAL_CONFIG] = False
            if CONF_PRESENCE_SENSOR in self._infos:
                del self._infos[CONF_PRESENCE_SENSOR]
        if not self._infos[CONF_USE_CENTRAL_BOILER_FEATURE]:
            if CONF_CENTRAL_BOILER_ACTIVATION_SRV in self._infos:
                del self._infos[CONF_CENTRAL_BOILER_ACTIVATION_SRV]
            if CONF_CENTRAL_BOILER_DEACTIVATION_SRV in self._infos:
                del self._infos[CONF_CENTRAL_BOILER_DEACTIVATION_SRV]
        if not self._infos[CONF_USE_AUTO_START_STOP_FEATURE]:
            self._infos[CONF_AUTO_START_STOP_LEVEL] = AUTO_START_STOP_LEVEL_NONE

        # Removes temporary value
        if COMES_FROM in self._infos:
            del self._infos[COMES_FROM]


class VersatileThermostatConfigFlow(  # pylint: disable=abstract-method
    VersatileThermostatBaseConfigFlow, HAConfigFlow, domain=DOMAIN
):
    """Handle a config flow for Versatile Thermostat."""

    def __init__(self) -> None:
        # self._info = dict()
        super().__init__(dict())
        _LOGGER.debug("CTOR ConfigFlow")

    @staticmethod
    @callback
    def async_get_options_flow(config_entry: ConfigEntry):
        """Get options flow for this handler"""
        # #713 doesn't work as explained here:https://developers.home-assistant.io/blog/2024/11/12/options-flow
        #  should be - return VersatileThermostatOptionsFlowHandler() but hass is not initialized
        return VersatileThermostatOptionsFlowHandler(config_entry)

    async def async_step_finalize(self, _):
        """Finalization of the ConfigEntry creation"""
        _LOGGER.debug("ConfigFlow.async_finalize")
        await super().async_step_finalize(_)

        return self.async_create_entry(title=self._infos[CONF_NAME], data=self._infos)


class VersatileThermostatOptionsFlowHandler(
    VersatileThermostatBaseConfigFlow, OptionsFlow
):
    """Handle options flow for Versatile Thermostat integration."""

    def __init__(self, config_entry: ConfigEntry) -> None:
        """Initialize options flow."""

        self._conf_app_id: str | None = None

        super().__init__(config_entry.data.copy())
        # #713
        # self.config_entry = config_entry
        _LOGGER.debug(
            "CTOR VersatileThermostatOptionsFlowHandler info: %s, entry_id: %s",
            self._infos,
            config_entry.entry_id,
        )

    async def async_step_init(self, user_input=None):
        """Manage basic options."""
        _LOGGER.debug(
            "Into OptionsFlowHandler.async_step_init user_input =%s",
            user_input,
        )

        self._placeholders = {
            CONF_NAME: self._infos[CONF_NAME],
            PLUGINS_LINK_PLACEHOLDER: PLUGINS_LINK,
        }

        return await self.async_step_menu(user_input)

    async def async_step_finalize(self, _):
        """Finalization of the ConfigEntry creation"""

        _LOGGER.info(
            "Recreating entry %s due to configuration change. New config is now: %s",
            self.config_entry.entry_id,
            self._infos,
        )
        await super().async_step_finalize(_)

        self.hass.config_entries.async_update_entry(self.config_entry, data=self._infos)
        return self.async_create_entry(title=None, data=None)
