/*
 *
 *    Copyright (c) 2022 Project CHIP Authors
 *    All rights reserved.
 *
 *    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 "controller/ReadInteraction.h"
#include <AppShellCommands.h>
#include <BindingHandler.h>
#include <app/clusters/bindings/bindings.h>

using namespace chip;
using namespace chip::app;

void BindingHandler::Init()
{
    DeviceLayer::PlatformMgr().ScheduleWork(InitInternal);
}

void BindingHandler::OnInvokeCommandFailure(BindingData & aBindingData, CHIP_ERROR aError)
{
    CHIP_ERROR error;

    if (aError == CHIP_ERROR_TIMEOUT && !BindingHandler::GetInstance().mCaseSessionRecovered)
    {
        printf("Response timeout for invoked command, trying to recover CASE session.\n");

        // Set flag to not try recover session multiple times.
        BindingHandler::GetInstance().mCaseSessionRecovered = true;
        // Allocate new object to make sure its life time will be appropriate.
        BindingHandler::BindingData * data = Platform::New<BindingHandler::BindingData>();
        *data                              = aBindingData;
        // Establish new CASE session and retrasmit command that was not applied.
        error = chip::BindingManager::GetInstance().NotifyBoundClusterChanged(aBindingData.EndpointId, aBindingData.ClusterId,
                                                                              static_cast<void *>(data));

        if (CHIP_NO_ERROR != error)
        {
            printf("NotifyBoundClusterChanged failed due to: %" CHIP_ERROR_FORMAT, error.Format());
            return;
        }
    }
    else
    {
        printf("Binding command was not applied! Reason: %" CHIP_ERROR_FORMAT, aError.Format());
    }
}

void ProcessIdentifyUnicastBindingRead(BindingHandler::BindingData * data, const EmberBindingTableEntry & binding,
                                       OperationalDeviceProxy * peer_device)
{
    auto onSuccess = [](const ConcreteDataAttributePath & attributePath, const auto & dataResponse) {
        ChipLogProgress(NotSpecified, "Read Identify attribute succeeds");
    };

    auto onFailure = [](const ConcreteDataAttributePath * attributePath, CHIP_ERROR error) {
        ChipLogError(NotSpecified, "Read Identify attribute failed: %" CHIP_ERROR_FORMAT, error.Format());
    };

    VerifyOrDie(peer_device != nullptr && peer_device->ConnectionReady());

    switch (data->attributeId)
    {
    case Clusters::Identify::Attributes::AttributeList::Id:
        Controller::ReadAttribute<Clusters::Identify::Attributes::AttributeList::TypeInfo>(
            peer_device->GetExchangeManager(), peer_device->GetSecureSession().Value(), binding.remote, onSuccess, onFailure);
        break;
    case Clusters::Identify::Attributes::FeatureMap::Id:
        Controller::ReadAttribute<Clusters::Identify::Attributes::FeatureMap::TypeInfo>(
            peer_device->GetExchangeManager(), peer_device->GetSecureSession().Value(), binding.remote, onSuccess, onFailure);
        break;
    }
}

void BindingHandler::OnOffProcessCommand(CommandId aCommandId, const EmberBindingTableEntry & aBinding,
                                         OperationalDeviceProxy * aDevice, void * aContext)
{
    CHIP_ERROR ret     = CHIP_NO_ERROR;
    BindingData * data = reinterpret_cast<BindingData *>(aContext);

    auto onSuccess = [](const ConcreteCommandPath & commandPath, const StatusIB & status, const auto & dataResponse) {
        printf("Binding command applied successfully!\n");
        // If session was recovered and communication works, reset flag to the initial state.
        if (BindingHandler::GetInstance().mCaseSessionRecovered)
            BindingHandler::GetInstance().mCaseSessionRecovered = false;
    };

    auto onFailure = [dataRef = *data](CHIP_ERROR aError) mutable { BindingHandler::OnInvokeCommandFailure(dataRef, aError); };

    if (aDevice)
    {
        // We are validating connection is ready once here instead of multiple times in each case statement below.
        VerifyOrDie(aDevice->ConnectionReady());
    }

    switch (aCommandId)
    {
    case Clusters::OnOff::Commands::Toggle::Id:
        Clusters::OnOff::Commands::Toggle::Type toggleCommand;
        if (aDevice)
        {
            ret = Controller::InvokeCommandRequest(aDevice->GetExchangeManager(), aDevice->GetSecureSession().Value(),
                                                   aBinding.remote, toggleCommand, onSuccess, onFailure);
        }
        else
        {
            Messaging::ExchangeManager & exchangeMgr = Server::GetInstance().GetExchangeManager();
            ret = Controller::InvokeGroupCommandRequest(&exchangeMgr, aBinding.fabricIndex, aBinding.groupId, toggleCommand);
        }
        break;

    case Clusters::OnOff::Commands::On::Id:
        Clusters::OnOff::Commands::On::Type onCommand;
        if (aDevice)
        {
            ret = Controller::InvokeCommandRequest(aDevice->GetExchangeManager(), aDevice->GetSecureSession().Value(),
                                                   aBinding.remote, onCommand, onSuccess, onFailure);
        }
        else
        {
            Messaging::ExchangeManager & exchangeMgr = Server::GetInstance().GetExchangeManager();
            ret = Controller::InvokeGroupCommandRequest(&exchangeMgr, aBinding.fabricIndex, aBinding.groupId, onCommand);
        }
        break;

    case Clusters::OnOff::Commands::Off::Id:
        Clusters::OnOff::Commands::Off::Type offCommand;
        if (aDevice)
        {
            ret = Controller::InvokeCommandRequest(aDevice->GetExchangeManager(), aDevice->GetSecureSession().Value(),
                                                   aBinding.remote, offCommand, onSuccess, onFailure);
        }
        else
        {
            Messaging::ExchangeManager & exchangeMgr = Server::GetInstance().GetExchangeManager();
            ret = Controller::InvokeGroupCommandRequest(&exchangeMgr, aBinding.fabricIndex, aBinding.groupId, offCommand);
        }
        break;
    default:
        printf("Invalid binding command data - commandId is not supported\n");
        break;
    }
    if (CHIP_NO_ERROR != ret)
    {
        printf("Invoke OnOff Command Request ERROR: %s\n", ErrorStr(ret));
    }
}

void BindingHandler::LevelControlProcessCommand(CommandId aCommandId, const EmberBindingTableEntry & aBinding,
                                                OperationalDeviceProxy * aDevice, void * aContext)
{
    BindingData * data = reinterpret_cast<BindingData *>(aContext);

    auto onSuccess = [](const ConcreteCommandPath & commandPath, const StatusIB & status, const auto & dataResponse) {
        printf("Binding command applied successfully!\n");
        // If session was recovered and communication works, reset flag to the initial state.
        if (BindingHandler::GetInstance().mCaseSessionRecovered)
            BindingHandler::GetInstance().mCaseSessionRecovered = false;
    };

    auto onFailure = [dataRef = *data](CHIP_ERROR aError) mutable { BindingHandler::OnInvokeCommandFailure(dataRef, aError); };

    CHIP_ERROR ret = CHIP_NO_ERROR;

    if (aDevice)
    {
        // We are validating connection is ready once here instead of multiple times in each case statement below.
        VerifyOrDie(aDevice->ConnectionReady());
    }

    switch (aCommandId)
    {
    case Clusters::LevelControl::Commands::MoveToLevel::Id: {
        Clusters::LevelControl::Commands::MoveToLevel::Type moveToLevelCommand;
        moveToLevelCommand.level = data->Value;
        if (aDevice)
        {
            ret = Controller::InvokeCommandRequest(aDevice->GetExchangeManager(), aDevice->GetSecureSession().Value(),
                                                   aBinding.remote, moveToLevelCommand, onSuccess, onFailure);
        }
        else
        {
            Messaging::ExchangeManager & exchangeMgr = Server::GetInstance().GetExchangeManager();
            ret = Controller::InvokeGroupCommandRequest(&exchangeMgr, aBinding.fabricIndex, aBinding.groupId, moveToLevelCommand);
        }
    }
    break;
    default:
        printf("Invalid binding command data - commandId is not supported\n");
        break;
    }
    if (CHIP_NO_ERROR != ret)
    {
        printf("Invoke Group Command Request ERROR: %s\n", ErrorStr(ret));
    }
}

void BindingHandler::LightSwitchChangedHandler(const EmberBindingTableEntry & binding, OperationalDeviceProxy * deviceProxy,
                                               void * context)
{
    VerifyOrReturn(context != nullptr, printf("Invalid context for Light switch handler\n"););
    BindingData * data = static_cast<BindingData *>(context);

    if (binding.type == MATTER_MULTICAST_BINDING && data->IsGroup)
    {
        switch (data->ClusterId)
        {
        case Clusters::OnOff::Id:
            OnOffProcessCommand(data->CommandId, binding, nullptr, context);
            break;
        case Clusters::LevelControl::Id:
            LevelControlProcessCommand(data->CommandId, binding, nullptr, context);
            break;
        default:
            ChipLogError(NotSpecified, "Invalid binding group command data");
            break;
        }
    }
    else if (binding.type == MATTER_UNICAST_BINDING && !data->IsGroup)
    {
        switch (data->ClusterId)
        {
        case Clusters::OnOff::Id:
            OnOffProcessCommand(data->CommandId, binding, deviceProxy, context);
            break;
        case Clusters::LevelControl::Id:
            LevelControlProcessCommand(data->CommandId, binding, deviceProxy, context);
            break;
        case Clusters::Identify::Id:
            ProcessIdentifyUnicastBindingRead(data, binding, deviceProxy);
            break;
        default:
            ChipLogError(NotSpecified, "Invalid binding unicast command data");
            break;
        }
    }
}

void BindingHandler::LightSwitchContextReleaseHandler(void * context)
{
    VerifyOrReturn(context != nullptr, printf("Invalid context for Light switch context release handler\n"););

    Platform::Delete(static_cast<BindingData *>(context));
}

void BindingHandler::InitInternal(intptr_t aArg)
{
    CHIP_ERROR ret = CHIP_NO_ERROR;
    auto & server  = Server::GetInstance();

    ret = BindingManager::GetInstance().Init(
        { &server.GetFabricTable(), server.GetCASESessionManager(), &server.GetPersistentStorage() });
    if (CHIP_NO_ERROR != ret)
    {
        printf("BindingHandler::InitInternal() run fail, err_code: 0x%" CHIP_ERROR_FORMAT, ret.Format());
        printf("\n");
    }
    else
    {
        BindingManager::GetInstance().RegisterBoundDeviceChangedHandler(LightSwitchChangedHandler);
        BindingManager::GetInstance().RegisterBoundDeviceContextReleaseHandler(LightSwitchContextReleaseHandler);
        BindingHandler::GetInstance().PrintBindingTable();
    }
}

bool BindingHandler::IsGroupBound()
{
    BindingTable & bindingTable = BindingTable::GetInstance();

    for (auto & entry : bindingTable)
    {
        if (MATTER_MULTICAST_BINDING == entry.type)
        {
            return true;
        }
    }
    return false;
}

void BindingHandler::PrintBindingTable()
{
    BindingTable & bindingTable = BindingTable::GetInstance();

    printf("Binding Table size: [%d]:\n", bindingTable.Size());
    uint8_t i = 0;
    for (auto & entry : bindingTable)
    {
        switch (entry.type)
        {
        case MATTER_UNICAST_BINDING:
            printf("[%d] UNICAST:", i++);
            printf("\t\t+ Fabric: %d\n \
            \t+ LocalEndpoint %d \n \
            \t+ ClusterId %d \n \
            \t+ RemoteEndpointId %d \n \
            \t+ NodeId %d \n",
                   (int) entry.fabricIndex, (int) entry.local, (int) entry.clusterId.value_or(kInvalidClusterId),
                   (int) entry.remote, (int) entry.nodeId);
            break;
        case MATTER_MULTICAST_BINDING:
            printf("[%d] GROUP:", i++);
            printf("\t\t+ Fabric: %d\n \
            \t+ LocalEndpoint %d \n \
            \t+ RemoteEndpointId %d \n \
            \t+ GroupId %d \n",
                   (int) entry.fabricIndex, (int) entry.local, (int) entry.remote, (int) entry.groupId);
            break;
        case MATTER_UNUSED_BINDING:
            printf("[%d] UNUSED", i++);
            break;
        default:
            break;
        }
    }
}

void BindingHandler::SwitchWorkerHandler(intptr_t context)
{
    VerifyOrReturn(context != 0, printf("BindingHandler::Invalid switch work data\n"));

    BindingHandler::BindingData * data = reinterpret_cast<BindingHandler::BindingData *>(context);
    printf("Notify Bounded Cluster | endpoint: %d cluster: %ld\n", data->EndpointId, data->ClusterId);
    BindingManager::GetInstance().NotifyBoundClusterChanged(data->EndpointId, data->ClusterId, static_cast<void *>(data));

    Platform::Delete(data);
}

void BindingHandler::BindingWorkerHandler(intptr_t context)
{
    VerifyOrReturn(context != 0, ChipLogError(NotSpecified, "BindingHandler::Invalid binding work data\n"));
    EmberBindingTableEntry * entry = reinterpret_cast<EmberBindingTableEntry *>(context);
    AddBindingEntry(*entry);

    Platform::Delete(entry);
}
