// Copyright 2024 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <inttypes.h>
#include <esp_matter_delegate_callbacks.h>
#include <esp_matter_core.h>
#include <esp_matter_feature.h>
#include <esp_matter_data_model_priv.h>
#include <app/clusters/mode-base-server/mode-base-server.h>
#include <app/clusters/energy-evse-server/energy-evse-server.h>
#include <app/clusters/microwave-oven-control-server/microwave-oven-control-server.h>
#include <app/clusters/operational-state-server/operational-state-server.h>
#include <app/clusters/resource-monitoring-server/resource-monitoring-server.h>
#include <app/clusters/fan-control-server/fan-control-server.h>
#include <app/clusters/laundry-dryer-controls-server/laundry-dryer-controls-server.h>
#include <app/clusters/valve-configuration-and-control-server/valve-configuration-and-control-cluster.h>
#include <app/clusters/door-lock-server/door-lock-server.h>
#include <app/clusters/boolean-state-configuration-server/boolean-state-configuration-server.h>
#include <app/clusters/application-basic-server/application-basic-server.h>
#include <app/clusters/laundry-washer-controls-server/laundry-washer-controls-server.h>
#include <app/clusters/window-covering-server/window-covering-server.h>
#include <app/clusters/dishwasher-alarm-server/dishwasher-alarm-server.h>
#include <app/clusters/keypad-input-server/keypad-input-server.h>
#include <app/clusters/mode-select-server/supported-modes-manager.h>
#include <app/clusters/thread-border-router-management-server/thread-border-router-management-server.h>
#include <app/clusters/water-heater-management-server/water-heater-management-server.h>
#include <app/clusters/energy-preference-server/energy-preference-server.h>
#include <app/clusters/commissioner-control-server/commissioner-control-server.h>
#include <app/clusters/actions-server/actions-server.h>
#include <app/clusters/thermostat-server/thermostat-server.h>
#include <app/clusters/diagnostic-logs-server/diagnostic-logs-server.h>
#include <app/clusters/closure-control-server/closure-control-server.h>
#include <app/clusters/closure-dimension-server/closure-dimension-server.h>
#include <app/clusters/application-launcher-server/application-launcher-server.h>
#include <app/clusters/account-login-server/account-login-server.h>
#include <app/clusters/audio-output-server/audio-output-server.h>
#include <app/clusters/channel-server/channel-server.h>
#include <app/clusters/content-app-observer/content-app-observer.h>
#include <app/clusters/content-control-server/content-control-server.h>
#include <app/clusters/low-power-server/low-power-server.h>
#include <app/clusters/messages-server/messages-server.h>
#include <app/clusters/media-input-server/media-input-server.h>
#include <app/clusters/media-playback-server/media-playback-server.h>
#include <app/clusters/target-navigator-server/target-navigator-server.h>
#include <app/clusters/wake-on-lan-server/wake-on-lan-server.h>
#include <app/clusters/commodity-tariff-server/commodity-tariff-server.h>
#include <app/clusters/commodity-price-server/commodity-price-server.h>
#include <app/clusters/electrical-grid-conditions-server/electrical-grid-conditions-server.h>
#include <app/clusters/meter-identification-server/meter-identification-server.h>
#include <unordered_map>

#include <clusters/ota_software_update_provider/integration.h>
#include <clusters/push_av_stream_transport/integration.h>
#include <clusters/power_topology/integration.h>
#include <clusters/device_energy_management/integration.h>
#include <clusters/diagnostic_logs/integration.h>
#include <clusters/electrical_power_measurement/integration.h>
#include <clusters/time_synchronization/integration.h>
#include <clusters/resource_monitor/integration.h>
#include <clusters/chime/integration.h>

using namespace chip::app::Clusters;
namespace esp_matter {
namespace cluster {

static std::unordered_map<chip::EndpointId, ModeBase::Instance*> s_microwave_oven_mode_instances;
static std::unordered_map<chip::EndpointId, OperationalState::Instance*> s_operational_state_instances;

static uint32_t get_feature_map_value(uint16_t endpoint_id, uint32_t cluster_id)
{
    uint32_t attribute_id = Globals::Attributes::FeatureMap::Id;
    attribute_t *attribute = attribute::get(endpoint_id, cluster_id, attribute_id);
    VerifyOrReturnError(attribute, 0);

    esp_matter_attr_val_t val = esp_matter_invalid(nullptr);
    VerifyOrReturnError(attribute::get_val_internal(attribute, &val) == ESP_OK, 0);
    return val.val.u32;
}

// Cluster-specific optional attributes handlers
chip::BitMask<EnergyEvse::OptionalAttributes> get_energy_evse_enabled_optional_attributes(uint16_t endpoint_id)
{
    chip::BitMask<EnergyEvse::OptionalAttributes> optional_attrs = 0;

    if (endpoint::is_attribute_enabled(endpoint_id, EnergyEvse::Id, EnergyEvse::Attributes::UserMaximumChargeCurrent::Id)) {
        optional_attrs.Set(EnergyEvse::OptionalAttributes::kSupportsUserMaximumChargingCurrent);
    }

    if (endpoint::is_attribute_enabled(endpoint_id, EnergyEvse::Id, EnergyEvse::Attributes::RandomizationDelayWindow::Id)) {
        optional_attrs.Set(EnergyEvse::OptionalAttributes::kSupportsRandomizationWindow);
    }

    if (endpoint::is_attribute_enabled(endpoint_id, EnergyEvse::Id, EnergyEvse::Attributes::ApproximateEVEfficiency::Id)) {
        optional_attrs.Set(EnergyEvse::OptionalAttributes::kSupportsApproximateEvEfficiency);
    }

    return optional_attrs;
}

chip::BitMask<ElectricalPowerMeasurement::OptionalAttributes> get_electrical_power_measurement_enabled_optional_attributes(uint16_t endpoint_id)
{
    chip::BitMask<ElectricalPowerMeasurement::OptionalAttributes> optional_attrs = 0;

    // Check for various optional attributes
    if (endpoint::is_attribute_enabled(endpoint_id, ElectricalPowerMeasurement::Id, ElectricalPowerMeasurement::Attributes::Ranges::Id)) {
        optional_attrs.Set(ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributeRanges);
    }

    if (endpoint::is_attribute_enabled(endpoint_id, ElectricalPowerMeasurement::Id, ElectricalPowerMeasurement::Attributes::Voltage::Id)) {
        optional_attrs.Set(ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributeVoltage);
    }

    if (endpoint::is_attribute_enabled(endpoint_id, ElectricalPowerMeasurement::Id, ElectricalPowerMeasurement::Attributes::ActiveCurrent::Id)) {
        optional_attrs.Set(ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributeActiveCurrent);
    }

    if (endpoint::is_attribute_enabled(endpoint_id, ElectricalPowerMeasurement::Id, ElectricalPowerMeasurement::Attributes::ReactiveCurrent::Id)) {
        optional_attrs.Set(ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributeReactiveCurrent);
    }

    if (endpoint::is_attribute_enabled(endpoint_id, ElectricalPowerMeasurement::Id, ElectricalPowerMeasurement::Attributes::ApparentCurrent::Id)) {
        optional_attrs.Set(ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributeApparentCurrent);
    }

    if (endpoint::is_attribute_enabled(endpoint_id, ElectricalPowerMeasurement::Id, ElectricalPowerMeasurement::Attributes::ReactivePower::Id)) {
        optional_attrs.Set(ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributeReactivePower);
    }

    if (endpoint::is_attribute_enabled(endpoint_id, ElectricalPowerMeasurement::Id, ElectricalPowerMeasurement::Attributes::ApparentPower::Id)) {
        optional_attrs.Set(ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributeApparentPower);
    }

    if (endpoint::is_attribute_enabled(endpoint_id, ElectricalPowerMeasurement::Id, ElectricalPowerMeasurement::Attributes::RMSVoltage::Id)) {
        optional_attrs.Set(ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributeRMSVoltage);
    }

    if (endpoint::is_attribute_enabled(endpoint_id, ElectricalPowerMeasurement::Id, ElectricalPowerMeasurement::Attributes::RMSCurrent::Id)) {
        optional_attrs.Set(ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributeRMSCurrent);
    }

    if (endpoint::is_attribute_enabled(endpoint_id, ElectricalPowerMeasurement::Id, ElectricalPowerMeasurement::Attributes::RMSPower::Id)) {
        optional_attrs.Set(ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributeRMSPower);
    }

    if (endpoint::is_attribute_enabled(endpoint_id, ElectricalPowerMeasurement::Id, ElectricalPowerMeasurement::Attributes::Frequency::Id)) {
        optional_attrs.Set(ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributeFrequency);
    }

    if (endpoint::is_attribute_enabled(endpoint_id, ElectricalPowerMeasurement::Id, ElectricalPowerMeasurement::Attributes::PowerFactor::Id)) {
        optional_attrs.Set(ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributePowerFactor);
    }

    if (endpoint::is_attribute_enabled(endpoint_id, ElectricalPowerMeasurement::Id, ElectricalPowerMeasurement::Attributes::NeutralCurrent::Id)) {
        optional_attrs.Set(ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributeNeutralCurrent);
    }

    return optional_attrs;
}

// Cluster-specific optional commands handlers
chip::BitMask<EnergyEvse::OptionalCommands> get_energy_evse_enabled_optional_commands(uint16_t endpoint_id)
{
    chip::BitMask<EnergyEvse::OptionalCommands> optional_cmds = 0;

    if (endpoint::is_command_enabled(endpoint_id, EnergyEvse::Id, EnergyEvse::Commands::StartDiagnostics::Id)) {
        optional_cmds.Set(EnergyEvse::OptionalCommands::kSupportsStartDiagnostics);
    }

    return optional_cmds;
}

namespace delegate_cb {

void InitModeDelegate(void *delegate, uint16_t endpoint_id, uint32_t cluster_id)
{
    VerifyOrReturn(delegate != nullptr);
    static ModeBase::Instance * modeInstance = nullptr;
    ModeBase::Delegate *mode_delegate = static_cast<ModeBase::Delegate*>(delegate);
    uint32_t feature_map = get_feature_map_value(endpoint_id, cluster_id);
    modeInstance = new ModeBase::Instance(mode_delegate, endpoint_id, cluster_id, feature_map);
    (void)modeInstance->Init();
}

void LaundryWasherModeDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    InitModeDelegate(delegate, endpoint_id, LaundryWasherMode::Id);
}

void DishWasherModeDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    InitModeDelegate(delegate, endpoint_id, DishwasherMode::Id);
}

void RefrigeratorAndTCCModeDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    InitModeDelegate(delegate, endpoint_id, RefrigeratorAndTemperatureControlledCabinetMode::Id);
}

void RvcRunModeDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    InitModeDelegate(delegate, endpoint_id, RvcRunMode::Id);
}

void RvcCleanModeDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    InitModeDelegate(delegate, endpoint_id, RvcCleanMode::Id);
}

void WaterHeaterModeDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    InitModeDelegate(delegate, endpoint_id, WaterHeaterMode::Id);
}

void EnergyEvseModeDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    InitModeDelegate(delegate, endpoint_id, EnergyEvseMode::Id);
}

void MicrowaveOvenModeDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    VerifyOrReturn(delegate != nullptr);
    ModeBase::Delegate *mode_delegate = static_cast<ModeBase::Delegate*>(delegate);
    ModeBase::Instance * modeInstance = nullptr;
    // Create new instance of MicrowaveOvenMode if not found in the map, otherwise use existing instance.
    if (s_microwave_oven_mode_instances.find(endpoint_id) == s_microwave_oven_mode_instances.end()) {
        uint32_t feature_map = get_feature_map_value(endpoint_id, MicrowaveOvenMode::Id);
        modeInstance = new ModeBase::Instance(mode_delegate, endpoint_id, MicrowaveOvenMode::Id, feature_map);
        s_microwave_oven_mode_instances[endpoint_id] = modeInstance;
    } else {
        modeInstance = s_microwave_oven_mode_instances[endpoint_id];
    }
    (void)modeInstance->Init();
}

void DeviceEnergyManagementModeDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    ModeBase::Delegate *device_energy_management_mode_delegate = static_cast<ModeBase::Delegate*>(delegate);
    InitModeDelegate(device_energy_management_mode_delegate, endpoint_id, DeviceEnergyManagementMode::Id);
}

void EnergyEvseDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    VerifyOrReturn(delegate != nullptr);
    static EnergyEvse::Instance * energyEvseInstance = nullptr;
    EnergyEvse::Delegate *energy_evse_delegate = static_cast<EnergyEvse::Delegate*>(delegate);
    uint32_t feature_map = get_feature_map_value(endpoint_id, EnergyEvse::Id);
    chip::BitMask<EnergyEvse::OptionalAttributes> optional_attrs = get_energy_evse_enabled_optional_attributes(endpoint_id);
    chip::BitMask<EnergyEvse::OptionalCommands> optional_cmds = get_energy_evse_enabled_optional_commands(endpoint_id);
    energyEvseInstance = new EnergyEvse::Instance(endpoint_id, *energy_evse_delegate, chip::BitMask<EnergyEvse::Feature, uint32_t>(feature_map),
                                                  optional_attrs, optional_cmds);
    (void)energyEvseInstance->Init();
}

void MicrowaveOvenControlDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    // Get delegates of MicrowaveOvenMode and OperationalState clusters.
    cluster_t *cluster = cluster::get(endpoint_id, MicrowaveOvenMode::Id);
    ModeBase::Delegate *microwave_oven_mode_delegate = static_cast<ModeBase::Delegate*>(get_delegate_impl(cluster));
    cluster = cluster::get(endpoint_id, OperationalState::Id);
    OperationalState::Delegate *operational_state_delegate = static_cast<OperationalState::Delegate*>(get_delegate_impl(cluster));
    VerifyOrReturn(delegate != nullptr && microwave_oven_mode_delegate != nullptr && operational_state_delegate != nullptr);
    ModeBase::Instance* microwaveOvenModeInstance = nullptr;
    OperationalState::Instance* operationalStateInstance = nullptr;

    // Create new instance of MicrowaveOvenMode if not found in the map, otherwise use existing instance.
    if (s_microwave_oven_mode_instances.find(endpoint_id) == s_microwave_oven_mode_instances.end()) {
        uint32_t feature_map = get_feature_map_value(endpoint_id, MicrowaveOvenMode::Id);
        microwaveOvenModeInstance = new ModeBase::Instance(microwave_oven_mode_delegate, endpoint_id, MicrowaveOvenMode::Id, feature_map);
        s_microwave_oven_mode_instances[endpoint_id] = microwaveOvenModeInstance;
    } else {
        microwaveOvenModeInstance = s_microwave_oven_mode_instances[endpoint_id];
    }

    // Create new instance of OperationalState if not found in the map, otherwise use existing instance.
    if (s_operational_state_instances.find(endpoint_id) == s_operational_state_instances.end()) {
        operationalStateInstance = new OperationalState::Instance(operational_state_delegate, endpoint_id);
        s_operational_state_instances[endpoint_id] = operationalStateInstance;
    } else {
        operationalStateInstance = s_operational_state_instances[endpoint_id];
    }

    // Create MicrowaveOvenControl instance
    static MicrowaveOvenControl::Instance * microwaveOvenControlInstance = nullptr;
    MicrowaveOvenControl::Delegate *microwave_oven_control_delegate = static_cast<MicrowaveOvenControl::Delegate*>(delegate);
    uint32_t feature_map = get_feature_map_value(endpoint_id, MicrowaveOvenControl::Id);
    microwaveOvenControlInstance = new MicrowaveOvenControl::Instance(microwave_oven_control_delegate, endpoint_id, MicrowaveOvenControl::Id, feature_map,
                                                                      *operationalStateInstance, *microwaveOvenModeInstance);
    (void)microwaveOvenControlInstance->Init();
}

void OperationalStateDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    VerifyOrReturn(delegate != nullptr);
    static OperationalState::Instance * operationalStateInstance = nullptr;
    OperationalState::Delegate *operational_state_delegate = static_cast<OperationalState::Delegate*>(delegate);
    // Create new instance of OperationalState if not found in the map, otherwise use existing instance.
    if (s_operational_state_instances.find(endpoint_id) == s_operational_state_instances.end()) {
        operationalStateInstance = new OperationalState::Instance(operational_state_delegate, endpoint_id);
        s_operational_state_instances[endpoint_id] = operationalStateInstance;
    } else {
        operationalStateInstance = s_operational_state_instances[endpoint_id];
    }
    (void)operationalStateInstance->Init();
}

void FanControlDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    VerifyOrReturn(delegate != nullptr);
    FanControl::Delegate *fan_control_delegate = static_cast<FanControl::Delegate*>(delegate);
    FanControl::SetDefaultDelegate(endpoint_id, fan_control_delegate);
}

void HepaFilterMonitoringDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    VerifyOrReturn(delegate != nullptr);
    ResourceMonitoring::Delegate *resource_monitoring_delegate = static_cast<ResourceMonitoring::Delegate*>(delegate);
    (void) chip::app::Clusters::ResourceMonitoring::SetDefaultDelegate(endpoint_id, HepaFilterMonitoring::Id,
                                                                       resource_monitoring_delegate);
}

void ActivatedCarbonFilterMonitoringDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    VerifyOrReturn(delegate != nullptr);
    ResourceMonitoring::Delegate *resource_monitoring_delegate = static_cast<ResourceMonitoring::Delegate*>(delegate);
    (void) chip::app::Clusters::ResourceMonitoring::SetDefaultDelegate(endpoint_id, ActivatedCarbonFilterMonitoring::Id,
                                                                       resource_monitoring_delegate);
}

void LaundryDryerControlsDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    VerifyOrReturn(delegate != nullptr);
    LaundryDryerControls::Delegate *laundry_dryer_controls_delegate = static_cast<LaundryDryerControls::Delegate*>(delegate);
    LaundryDryerControls::LaundryDryerControlsServer::SetDefaultDelegate(endpoint_id, laundry_dryer_controls_delegate);
}

void ValveConfigurationAndControlDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    VerifyOrReturn(delegate != nullptr);
    ValveConfigurationAndControl::Delegate *valve_configuration_and_control_delegate = static_cast<ValveConfigurationAndControl::Delegate*>(delegate);
    ValveConfigurationAndControl::SetDefaultDelegate(endpoint_id, valve_configuration_and_control_delegate);
}

void DeviceEnergyManagementDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    VerifyOrReturn(delegate != nullptr);
    static DeviceEnergyManagement::Instance * deviceEnergyManagementInstance = nullptr;
    DeviceEnergyManagement::Delegate *device_energy_management_delegate = static_cast<DeviceEnergyManagement::Delegate*>(delegate);
    uint32_t feature_map = get_feature_map_value(endpoint_id, DeviceEnergyManagement::Id);
    deviceEnergyManagementInstance = new DeviceEnergyManagement::Instance(endpoint_id, *device_energy_management_delegate, chip::BitMask<DeviceEnergyManagement::Feature, uint32_t>(feature_map));
    (void)deviceEnergyManagementInstance->Init();
}

void DoorLockDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    VerifyOrReturn(delegate != nullptr);
    DoorLock::Delegate *door_lock_delegate = static_cast<DoorLock::Delegate*>(delegate);
    (void)DoorLockServer::Instance().SetDelegate(endpoint_id, door_lock_delegate);
}

void BooleanStateConfigurationDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    VerifyOrReturn(delegate != nullptr);
    BooleanStateConfiguration::Delegate *boolean_state_configuration_delegate = static_cast<BooleanStateConfiguration::Delegate*>(delegate);
    BooleanStateConfiguration::SetDefaultDelegate(endpoint_id, boolean_state_configuration_delegate);
}

void TimeSynchronizationDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    VerifyOrReturn(delegate != nullptr);
    TimeSynchronization::Delegate *time_synchronization_delegate = static_cast<TimeSynchronization::Delegate*>(delegate);
    TimeSynchronization::SetDefaultDelegate(time_synchronization_delegate);
}

void ApplicationBasicDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    VerifyOrReturn(delegate != nullptr);
    ApplicationBasic::Delegate *application_basic_delegate = static_cast<ApplicationBasic::Delegate*>(delegate);
    ApplicationBasic::SetDefaultDelegate(endpoint_id, application_basic_delegate);
}

void PowerTopologyDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    VerifyOrReturn(delegate != nullptr);
    static PowerTopology::Instance * powerTopologyInstance = nullptr;
    PowerTopology::Delegate *power_topology_delegate = static_cast<PowerTopology::Delegate*>(delegate);
    chip::BitMask<PowerTopology::Feature> feature_map(get_feature_map_value(endpoint_id, PowerTopology::Id));
    powerTopologyInstance = new PowerTopology::Instance(endpoint_id, *power_topology_delegate, feature_map);
    (void)powerTopologyInstance->Init();
}

void ElectricalPowerMeasurementDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    VerifyOrReturn(delegate != nullptr);
    static ElectricalPowerMeasurement::Instance * electricalPowerMeasurementInstance = nullptr;
    ElectricalPowerMeasurement::Delegate *electrical_power_measurement_delegate = static_cast<ElectricalPowerMeasurement::Delegate*>(delegate);
    uint32_t feature_map = get_feature_map_value(endpoint_id, ElectricalPowerMeasurement::Id);
    chip::BitMask<ElectricalPowerMeasurement::OptionalAttributes> optional_attrs = get_electrical_power_measurement_enabled_optional_attributes(endpoint_id);
    electricalPowerMeasurementInstance = new ElectricalPowerMeasurement::Instance(endpoint_id, *electrical_power_measurement_delegate,
                                                                                  chip::BitMask<ElectricalPowerMeasurement::Feature, uint32_t>(feature_map), optional_attrs);
    (void)electricalPowerMeasurementInstance->Init();
}

void LaundryWasherControlsDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    VerifyOrReturn(delegate != nullptr);
    LaundryWasherControls::Delegate *laundry_washer_controls_delegate = static_cast<LaundryWasherControls::Delegate*>(delegate);
    LaundryWasherControls::LaundryWasherControlsServer::SetDefaultDelegate(endpoint_id, laundry_washer_controls_delegate);
}

void WindowCoveringDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    VerifyOrReturn(delegate != nullptr);
    WindowCovering::Delegate *window_covering_delegate = static_cast<WindowCovering::Delegate*>(delegate);
    WindowCovering::SetDefaultDelegate(endpoint_id, window_covering_delegate);
}

void DishwasherAlarmDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    VerifyOrReturn(delegate != nullptr);
    DishwasherAlarm::Delegate *dishwasher_alarm_delegate = static_cast<DishwasherAlarm::Delegate*>(delegate);
    DishwasherAlarm::SetDefaultDelegate(endpoint_id, dishwasher_alarm_delegate);
}

void KeypadInputDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    VerifyOrReturn(delegate != nullptr);
    KeypadInput::Delegate *keypad_input_delegate = static_cast<KeypadInput::Delegate*>(delegate);
    KeypadInput::SetDefaultDelegate(endpoint_id, keypad_input_delegate);
}

void ModeSelectDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    VerifyOrReturn(delegate != nullptr);
    ModeSelect::SupportedModesManager *supported_modes_manager = static_cast<ModeSelect::SupportedModesManager*>(delegate);
    ModeSelect::setSupportedModesManager(supported_modes_manager);
}

void ThreadBorderRouterManagementDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    assert(delegate != nullptr);
    /* Get the attribute */
    attribute_t *attribute = attribute::get(endpoint_id, ThreadBorderRouterManagement::Id, Globals::Attributes::FeatureMap::Id);
    assert(attribute != nullptr);
    /* Update the value if the attribute already exists */
    esp_matter_attr_val_t val = esp_matter_invalid(nullptr);
    attribute::get_val(attribute, &val);
    bool pan_change_supported = (val.val.u32 & thread_border_router_management::feature::pan_change::get_id()) ? true : false;
    ThreadBorderRouterManagement::Delegate *thread_br_delegate = static_cast<ThreadBorderRouterManagement::Delegate *>(delegate);
    assert(thread_br_delegate->GetPanChangeSupported() == pan_change_supported);
    ThreadBorderRouterManagement::ServerInstance *server_instance =
        chip::Platform::New<ThreadBorderRouterManagement::ServerInstance>(endpoint_id, thread_br_delegate, chip::Server::GetInstance().GetFailSafeContext());
    (void)server_instance->Init();
}

void ServiceAreaDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    // TODO: This cluster has two delegates. We need to update existing delegate logic to accommodate multiple delegates.
}

void WaterHeaterManagementDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    if (delegate == nullptr) {
        return;
    }
    static WaterHeaterManagement::Instance * wHtrInstance = nullptr;
    WaterHeaterManagement::Delegate *whtr_delegate = static_cast<WaterHeaterManagement::Delegate*>(delegate);
    uint32_t feature_map = get_feature_map_value(endpoint_id, WaterHeaterManagement::Id);
    wHtrInstance = new WaterHeaterManagement::Instance(endpoint_id, *whtr_delegate, chip::BitMask<WaterHeaterManagement::Feature, uint32_t>(feature_map));
    (void)wHtrInstance->Init();
}

void EnergyPreferenceDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    if (delegate == nullptr) {
        return;
    }
    EnergyPreference::Delegate *energy_preference_delegate = static_cast<EnergyPreference::Delegate*>(delegate);
    EnergyPreference::SetDelegate(energy_preference_delegate);
}

void CommissionerControlDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    if (delegate == nullptr) {
        return;
    }
    CommissionerControl::Delegate *commissioner_control_delegate = static_cast<CommissionerControl::Delegate*>(delegate);
    CommissionerControl::CommissionerControlServer *commissioner_control_instance = nullptr;
    commissioner_control_instance =
        new CommissionerControl::CommissionerControlServer(commissioner_control_delegate, endpoint_id);
    (void)commissioner_control_instance->Init();
}

void ActionsDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    VerifyOrReturn(delegate != nullptr);
    static Actions::ActionsServer *actionsServer = nullptr;
    Actions::Delegate *actions_delegate = static_cast<Actions::Delegate*>(delegate);
    actionsServer = new Actions::ActionsServer(endpoint_id, *actions_delegate);
    (void)actionsServer->Init();
}

void ThermostatDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    VerifyOrReturn(delegate != nullptr);
    Thermostat::Delegate *thermostat_delegate = static_cast<Thermostat::Delegate*>(delegate);
    Thermostat::SetDefaultDelegate(endpoint_id, thermostat_delegate);
}

void OtaSoftwareUpdateProviderDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    VerifyOrReturn(delegate != nullptr);
    chip::app::Clusters::OTAProvider::SetDelegate(endpoint_id, static_cast<chip::app::Clusters::OTAProviderDelegate *>(delegate));
}

void DiagnosticLogsDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    VerifyOrReturn(delegate != nullptr && endpoint_id == chip::kRootEndpointId);
    DiagnosticLogs::DiagnosticLogsProviderDelegate *diagnostic_logs_delegate = static_cast<DiagnosticLogs::DiagnosticLogsProviderDelegate*>(delegate);
    DiagnosticLogs::SetDiagnosticLogsProviderDelegate(diagnostic_logs_delegate);
}

void ChimeDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    VerifyOrReturn(delegate != nullptr);
    ChimeDelegate *chime_delegate = static_cast<ChimeDelegate*>(delegate);
    Chime::ChimeServer *chime_server = new Chime::ChimeServer(endpoint_id, *chime_delegate);
    (void)chime_server->Init();
}

void ClosureControlDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    VerifyOrReturn(delegate != nullptr);
    ClosureControl::DelegateBase *closure_control_delegate = static_cast<ClosureControl::DelegateBase*>(delegate);
    ClosureControl::MatterContext *matter_context = new ClosureControl::MatterContext(endpoint_id);
    ClosureControl::ClusterLogic *cluster_logic = new ClosureControl::ClusterLogic(*closure_control_delegate, *matter_context);
    ClosureControl::Interface *server_interface = new ClosureControl::Interface(endpoint_id, *cluster_logic);
    (void)server_interface->Init();
}

void ClosureDimensionDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    VerifyOrReturn(delegate != nullptr);
    ClosureDimension::DelegateBase *closure_dimension_delegate = static_cast<ClosureDimension::DelegateBase*>(delegate);
    ClosureDimension::MatterContext *matter_context = new ClosureDimension::MatterContext(endpoint_id);
    ClosureDimension::ClusterLogic *cluster_logic = new ClosureDimension::ClusterLogic(*closure_dimension_delegate, *matter_context);
    ClosureDimension::Interface *server_interface = new ClosureDimension::Interface(endpoint_id, *cluster_logic);
    (void)server_interface->Init();
}

void PushAvStreamTransportDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    VerifyOrReturn(delegate != nullptr);
    PushAvStreamTransportDelegate *push_av_stream_transport_delegate = static_cast<PushAvStreamTransportDelegate*>(delegate);
    chip::app::Clusters::PushAvStreamTransport::SetDelegate(endpoint_id, push_av_stream_transport_delegate);
}

void CommodityTariffDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    VerifyOrReturn(delegate != nullptr);
    CommodityTariff::Delegate *commodity_tariff_delegate = static_cast<CommodityTariff::Delegate*>(delegate);
    uint32_t feature_map = get_feature_map_value(endpoint_id, CommodityTariff::Id);
    CommodityTariff::Instance *commodity_tariff_instance = new CommodityTariff::Instance(endpoint_id, *commodity_tariff_delegate, chip::BitMask<CommodityTariff::Feature, uint32_t>(feature_map));
    (void)commodity_tariff_instance->Init();
}

void CommodityPriceDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    VerifyOrReturn(delegate != nullptr);
    CommodityPrice::Delegate *commodity_price_delegate = static_cast<CommodityPrice::Delegate*>(delegate);
    uint32_t feature_map = get_feature_map_value(endpoint_id, CommodityPrice::Id);
    CommodityPrice::Instance *commodity_price_instance = new CommodityPrice::Instance(endpoint_id, *commodity_price_delegate, chip::BitMask<CommodityPrice::Feature, uint32_t>(feature_map));
    (void)commodity_price_instance->Init();
}

void ElectricalGridConditionsDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    VerifyOrReturn(delegate != nullptr);
    ElectricalGridConditions::Delegate *electrical_grid_conditions_delegate = static_cast<ElectricalGridConditions::Delegate*>(delegate);
    uint32_t feature_map = get_feature_map_value(endpoint_id, ElectricalGridConditions::Id);
    ElectricalGridConditions::Instance *electrical_grid_conditions_instance = new ElectricalGridConditions::Instance(endpoint_id, *electrical_grid_conditions_delegate, chip::BitMask<ElectricalGridConditions::Feature, uint32_t>(feature_map));
    (void)electrical_grid_conditions_instance->Init();
}

/* Not a delegate but an Initialization callback */
void MeterIdentificationDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    uint32_t feature_map = get_feature_map_value(endpoint_id, MeterIdentification::Id);
    MeterIdentification::Instance *meter_identification_instance = new MeterIdentification::Instance(endpoint_id, chip::BitMask<MeterIdentification::Feature, uint32_t>(feature_map));
    LogErrorOnFailure(meter_identification_instance->Init());
}

void ApplicationLauncherDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    VerifyOrReturn(delegate != nullptr);
    ApplicationLauncher::Delegate *application_launcher_delegate = static_cast<ApplicationLauncher::Delegate *>(delegate);
    ApplicationLauncher::SetDefaultDelegate(endpoint_id, application_launcher_delegate);
}
void AccountLoginDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    VerifyOrReturn(delegate != nullptr);
    AccountLogin::Delegate *account_login_delegate = static_cast<AccountLogin::Delegate *>(delegate);
    AccountLogin::SetDefaultDelegate(endpoint_id, account_login_delegate);
}
void AudioOutputDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    VerifyOrReturn(delegate != nullptr);
    AudioOutput::Delegate *audio_output_delegate = static_cast<AudioOutput::Delegate *>(delegate);
    AudioOutput::SetDefaultDelegate(endpoint_id, audio_output_delegate);
}
void ChannelDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    VerifyOrReturn(delegate != nullptr);
    Channel::Delegate *channel_delegate = static_cast<Channel::Delegate *>(delegate);
    Channel::SetDefaultDelegate(endpoint_id, channel_delegate);
}
void ContentAppObserverDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    VerifyOrReturn(delegate != nullptr);
    ContentAppObserver::Delegate *content_app_observer_delegate = static_cast<ContentAppObserver::Delegate *>(delegate);
    ContentAppObserver::SetDefaultDelegate(endpoint_id, content_app_observer_delegate);
}
void ContentControlDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    VerifyOrReturn(delegate != nullptr);
    ContentControl::Delegate *content_control_delegate = static_cast<ContentControl::Delegate *>(delegate);
    ContentControl::SetDefaultDelegate(endpoint_id, content_control_delegate);
}
void DishwasherModeDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    InitModeDelegate(delegate, endpoint_id, DishwasherMode::Id);
}
void LowPowerDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    VerifyOrReturn(delegate != nullptr);
    LowPower::Delegate *low_power_delegate = static_cast<LowPower::Delegate *>(delegate);
    LowPower::SetDefaultDelegate(endpoint_id, low_power_delegate);
}
void MessagesDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    VerifyOrReturn(delegate != nullptr);
    Messages::Delegate *messages_delegate = static_cast<Messages::Delegate *>(delegate);
    Messages::SetDefaultDelegate(endpoint_id, messages_delegate);
}
void MediaInputDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    VerifyOrReturn(delegate != nullptr);
    MediaInput::Delegate *media_input_delegate = static_cast<MediaInput::Delegate *>(delegate);
    MediaInput::SetDefaultDelegate(endpoint_id, media_input_delegate);
}
void MediaPlaybackDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    VerifyOrReturn(delegate != nullptr);
    MediaPlayback::Delegate *media_playback_delegate = static_cast<MediaPlayback::Delegate *>(delegate);
    MediaPlayback::SetDefaultDelegate(endpoint_id, media_playback_delegate);
}
void OvenModeDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    InitModeDelegate(delegate, endpoint_id, OvenMode::Id);
}
void OvenCavityOperationalStateDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    VerifyOrReturn(delegate != nullptr);
    OperationalState::Delegate *operational_state_delegate = static_cast<OperationalState::Delegate *>(delegate);
    OvenCavityOperationalState::Instance *instance = nullptr;
    if (s_operational_state_instances.find(endpoint_id) == s_operational_state_instances.end()) {
        instance = new OvenCavityOperationalState::Instance(operational_state_delegate, endpoint_id);
        s_operational_state_instances[endpoint_id] = static_cast<OperationalState::Instance *>(instance);
    } else {
        instance = static_cast<OvenCavityOperationalState::Instance *>(s_operational_state_instances[endpoint_id]);
    }
    (void) instance->Init();
}
void RefrigeratorAndTemperatureControlledCabinetModeDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    InitModeDelegate(delegate, endpoint_id, RefrigeratorAndTemperatureControlledCabinetMode::Id);
}
void RvcOperationalStateDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    VerifyOrReturn(delegate != nullptr);
    RvcOperationalState::Delegate *rvc_operational_state_delegate = static_cast<RvcOperationalState::Delegate *>(delegate);
    RvcOperationalState::Instance *instance = nullptr;
    if (s_operational_state_instances.find(endpoint_id) == s_operational_state_instances.end()) {
        instance = new RvcOperationalState::Instance(rvc_operational_state_delegate, endpoint_id);
        s_operational_state_instances[endpoint_id] = static_cast<OperationalState::Instance *>(instance);
    } else {
        instance = static_cast<RvcOperationalState::Instance *>(s_operational_state_instances[endpoint_id]);
    }
    (void) instance->Init();
}
void TargetNavigatorDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    VerifyOrReturn(delegate != nullptr);
    TargetNavigator::Delegate *target_navigator_delegate = static_cast<TargetNavigator::Delegate *>(delegate);
    TargetNavigator::SetDefaultDelegate(endpoint_id, target_navigator_delegate);
}
void WakeOnLanDelegateInitCB(void *delegate, uint16_t endpoint_id)
{
    VerifyOrReturn(delegate != nullptr);
    WakeOnLan::Delegate *wake_on_lan_delegate = static_cast<WakeOnLan::Delegate *>(delegate);
    WakeOnLan::SetDefaultDelegate(endpoint_id, wake_on_lan_delegate);
}
} // namespace delegate_cb
} // namespace cluster
} // namespace esp_matter
