/*
 *
 *    Copyright (c) 2021 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 "network-commissioning.h"

#include <app-common/zap-generated/attributes/Accessors.h>
#include <app-common/zap-generated/cluster-objects.h>
#include <app/CommandHandlerInterface.h>
#include <app/InteractionModelEngine.h>
#include <app/clusters/general-commissioning-server/general-commissioning-server.h>
#include <app/server/Server.h>
#include <app/util/attribute-storage.h>
#include <lib/support/SafeInt.h>
#include <lib/support/ThreadOperationalDataset.h>
#include <platform/DeviceControlServer.h>
#include <platform/PlatformManager.h>
#include <platform/internal/DeviceNetworkInfo.h>
#include <trace/trace.h>

using namespace chip;
using namespace chip::app;
using namespace chip::app::Clusters;
using namespace chip::app::Clusters::NetworkCommissioning;

namespace chip {
namespace app {
namespace Clusters {
namespace NetworkCommissioning {

using namespace DeviceLayer::NetworkCommissioning;

namespace {
// For WiFi and Thread scan results, each item will cose ~60 bytes in TLV, thus 15 is a safe upper bound of scan results.
constexpr size_t kMaxNetworksInScanResponse = 15;

enum ValidWiFiCredentialLength
{
    kOpen      = 0,
    kWEP64     = 5,
    kMinWPAPSK = 8,
    kMaxWPAPSK = 63,
    kWPAPSKHex = 64,
};

} // namespace

CHIP_ERROR Instance::Init()
{
    ReturnErrorOnFailure(chip::app::InteractionModelEngine::GetInstance()->RegisterCommandHandler(this));
    VerifyOrReturnError(registerAttributeAccessOverride(this), CHIP_ERROR_INCORRECT_STATE);
    ReturnErrorOnFailure(DeviceLayer::PlatformMgrImpl().AddEventHandler(OnPlatformEventHandler, reinterpret_cast<intptr_t>(this)));
    ReturnErrorOnFailure(mpBaseDriver->Init(this));
    mLastNetworkingStatusValue.SetNull();
    mLastConnectErrorValue.SetNull();
    mLastNetworkIDLen = 0;
    return CHIP_NO_ERROR;
}

void Instance::Shutdown()
{
    mpBaseDriver->Shutdown();
}

void Instance::InvokeCommand(HandlerContext & ctxt)
{
    if (mAsyncCommandHandle.Get() != nullptr)
    {
        // We have a command processing in the backend, reject all incoming commands.
        ctxt.mCommandHandler.AddStatus(ctxt.mRequestPath, Protocols::InteractionModel::Status::Busy);
        ctxt.SetCommandHandled();
        return;
    }

    // Since mPath is used for building the response command, and we have checked that we are not pending the response of another
    // command above. So it is safe to set the mPath here and not clear it when return.
    mPath = ctxt.mRequestPath;

    switch (ctxt.mRequestPath.mCommandId)
    {
    case Commands::ScanNetworks::Id:
        VerifyOrReturn(mFeatureFlags.Has(NetworkCommissioningFeature::kWiFiNetworkInterface) ||
                       mFeatureFlags.Has(NetworkCommissioningFeature::kThreadNetworkInterface));
        HandleCommand<Commands::ScanNetworks::DecodableType>(
            ctxt, [this](HandlerContext & ctx, const auto & req) { HandleScanNetworks(ctx, req); });
        return;

    case Commands::AddOrUpdateWiFiNetwork::Id:
        VerifyOrReturn(mFeatureFlags.Has(NetworkCommissioningFeature::kWiFiNetworkInterface));
        HandleCommand<Commands::AddOrUpdateWiFiNetwork::DecodableType>(
            ctxt, [this](HandlerContext & ctx, const auto & req) { HandleAddOrUpdateWiFiNetwork(ctx, req); });
        return;

    case Commands::AddOrUpdateThreadNetwork::Id:
        VerifyOrReturn(mFeatureFlags.Has(NetworkCommissioningFeature::kThreadNetworkInterface));
        HandleCommand<Commands::AddOrUpdateThreadNetwork::DecodableType>(
            ctxt, [this](HandlerContext & ctx, const auto & req) { HandleAddOrUpdateThreadNetwork(ctx, req); });
        return;

    case Commands::RemoveNetwork::Id:
        VerifyOrReturn(mFeatureFlags.Has(NetworkCommissioningFeature::kWiFiNetworkInterface) ||
                       mFeatureFlags.Has(NetworkCommissioningFeature::kThreadNetworkInterface));
        HandleCommand<Commands::RemoveNetwork::DecodableType>(
            ctxt, [this](HandlerContext & ctx, const auto & req) { HandleRemoveNetwork(ctx, req); });
        return;

    case Commands::ConnectNetwork::Id:
        VerifyOrReturn(mFeatureFlags.Has(NetworkCommissioningFeature::kWiFiNetworkInterface) ||
                       mFeatureFlags.Has(NetworkCommissioningFeature::kThreadNetworkInterface));
        HandleCommand<Commands::ConnectNetwork::DecodableType>(
            ctxt, [this](HandlerContext & ctx, const auto & req) { HandleConnectNetwork(ctx, req); });
        return;

    case Commands::ReorderNetwork::Id:
        VerifyOrReturn(mFeatureFlags.Has(NetworkCommissioningFeature::kWiFiNetworkInterface) ||
                       mFeatureFlags.Has(NetworkCommissioningFeature::kThreadNetworkInterface));
        HandleCommand<Commands::ReorderNetwork::DecodableType>(
            ctxt, [this](HandlerContext & ctx, const auto & req) { HandleReorderNetwork(ctx, req); });
        return;
    }
}

CHIP_ERROR Instance::Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder)
{
    switch (aPath.mAttributeId)
    {
    case Attributes::MaxNetworks::Id:
        return aEncoder.Encode(mpBaseDriver->GetMaxNetworks());

    case Attributes::Networks::Id:
        return aEncoder.EncodeList([this](const auto & encoder) {
            auto networks  = mpBaseDriver->GetNetworks();
            CHIP_ERROR err = CHIP_NO_ERROR;
            Structs::NetworkInfo::Type networkForEncode;
            NetworkCommissioning::Network network;
            for (; networks != nullptr && networks->Next(network);)
            {
                networkForEncode.networkID = ByteSpan(network.networkID, network.networkIDLen);
                networkForEncode.connected = network.connected;
                SuccessOrExit(err = encoder.Encode(networkForEncode));
            }
        exit:
            if (networks != nullptr)
            {
                networks->Release();
            }

            return err;
        });

    case Attributes::ScanMaxTimeSeconds::Id:
        if (mpWirelessDriver != nullptr)
        {
            return aEncoder.Encode(mpWirelessDriver->GetScanNetworkTimeoutSeconds());
        }
        return CHIP_NO_ERROR;

    case Attributes::ConnectMaxTimeSeconds::Id:
        if (mpWirelessDriver != nullptr)
        {
            return aEncoder.Encode(mpWirelessDriver->GetConnectNetworkTimeoutSeconds());
        }
        return CHIP_NO_ERROR;

    case Attributes::InterfaceEnabled::Id:
        return aEncoder.Encode(mpBaseDriver->GetEnabled());

    case Attributes::LastNetworkingStatus::Id:
        return aEncoder.Encode(mLastNetworkingStatusValue);

    case Attributes::LastNetworkID::Id:
        if (mLastNetworkIDLen == 0)
        {
            return aEncoder.EncodeNull();
        }
        else
        {
            return aEncoder.Encode(ByteSpan(mLastNetworkID, mLastNetworkIDLen));
        }

    case Attributes::LastConnectErrorValue::Id:
        return aEncoder.Encode(mLastConnectErrorValue);

    case Attributes::FeatureMap::Id:
        return aEncoder.Encode(mFeatureFlags);

    default:
        return CHIP_NO_ERROR;
    }
}

CHIP_ERROR Instance::Write(const ConcreteDataAttributePath & aPath, AttributeValueDecoder & aDecoder)
{
    switch (aPath.mAttributeId)
    {
    case Attributes::InterfaceEnabled::Id:
        bool value;
        ReturnErrorOnFailure(aDecoder.Decode(value));
        return mpBaseDriver->SetEnabled(value);
    default:
        return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
    }
}

void Instance::OnNetworkingStatusChange(NetworkCommissioning::Status aCommissioningError, Optional<ByteSpan> aNetworkId,
                                        Optional<int32_t> aConnectStatus)
{
    if (aNetworkId.HasValue() && aNetworkId.Value().size() > kMaxNetworkIDLen)
    {
        ChipLogError(DeviceLayer, "Invalid network id received when calling OnNetworkingStatusChange");
        return;
    }
    mLastNetworkingStatusValue.SetNonNull(aCommissioningError);
    if (aNetworkId.HasValue())
    {
        memcpy(mLastNetworkID, aNetworkId.Value().data(), aNetworkId.Value().size());
        mLastNetworkIDLen = static_cast<uint8_t>(aNetworkId.Value().size());
    }
    else
    {
        mLastNetworkIDLen = 0;
    }
    if (aConnectStatus.HasValue())
    {
        mLastConnectErrorValue.SetNonNull(aConnectStatus.Value());
    }
    else
    {
        mLastConnectErrorValue.SetNull();
    }
}

void Instance::HandleScanNetworks(HandlerContext & ctx, const Commands::ScanNetworks::DecodableType & req)
{
    MATTER_TRACE_EVENT_SCOPE("HandleScanNetwork", "NetworkCommissioning");
    if (mFeatureFlags.Has(NetworkCommissioningFeature::kWiFiNetworkInterface))
    {
        ByteSpan ssid;
        if (req.ssid.HasValue())
        {
            const auto & nullableSSID = req.ssid.Value();
            if (!nullableSSID.IsNull())
            {
                ssid = nullableSSID.Value();
                if (ssid.empty())
                {
                    // Normalize empty span value to null ByteSpan.
                    // Spec 7.17.1. Empty string is an equivalent of null.
                    ssid = ByteSpan();
                }
            }
        }
        if (ssid.size() > DeviceLayer::Internal::kMaxWiFiSSIDLength)
        {
            ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::InvalidCommand);
            return;
        }
        mCurrentOperationBreadcrumb = req.breadcrumb;
        mAsyncCommandHandle         = CommandHandler::Handle(&ctx.mCommandHandler);
        ctx.mCommandHandler.FlushAcksRightAwayOnSlowCommand();
        mpDriver.Get<WiFiDriver *>()->ScanNetworks(ssid, this);
    }
    else if (mFeatureFlags.Has(NetworkCommissioningFeature::kThreadNetworkInterface))
    {
        mCurrentOperationBreadcrumb = req.breadcrumb;
        mAsyncCommandHandle         = CommandHandler::Handle(&ctx.mCommandHandler);
        ctx.mCommandHandler.FlushAcksRightAwayOnSlowCommand();
        mpDriver.Get<ThreadDriver *>()->ScanNetworks(this);
    }
    else
    {
        ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::UnsupportedCommand);
    }
}

namespace {

void FillDebugTextAndNetworkIndex(Commands::NetworkConfigResponse::Type & response, MutableCharSpan debugText, uint8_t networkIndex)
{
    if (!debugText.empty())
    {
        response.debugText.SetValue(CharSpan(debugText.data(), debugText.size()));
    }
    if (response.networkingStatus == NetworkCommissioningStatus::kSuccess)
    {
        response.networkIndex.SetValue(networkIndex);
    }
}

bool CheckFailSafeArmed(CommandHandlerInterface::HandlerContext & ctx)
{
    auto & failSafeContext = chip::Server::GetInstance().GetFailSafeContext();

    if (failSafeContext.IsFailSafeArmed(ctx.mCommandHandler.GetAccessingFabricIndex()))
    {
        return true;
    }

    ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::FailsafeRequired);
    return false;
}

} // namespace

void Instance::HandleAddOrUpdateWiFiNetwork(HandlerContext & ctx, const Commands::AddOrUpdateWiFiNetwork::DecodableType & req)
{
    MATTER_TRACE_EVENT_SCOPE("HandleAddOrUpdateWiFiNetwork", "NetworkCommissioning");

    VerifyOrReturn(CheckFailSafeArmed(ctx));

    // Spec 11.8.8.4
    // Valid Credentials length are:
    // - 0 bytes: Unsecured (open) connection
    // - 5 bytes: WEP-64 passphrase
    // - 10 hexadecimal ASCII characters: WEP-64 40-bit hex raw PSK
    // - 13 bytes: WEP-128 passphrase
    // - 26 hexadecimal ASCII characters: WEP-128 104-bit hex raw PSK
    // - 8..63 bytes: WPA/WPA2/WPA3 passphrase
    // - 64 bytes: WPA/WPA2/WPA3 raw hex PSK
    // Note 10 hex WEP64 and 13 bytes / 26 hex WEP128 passphrase are covered by 8~63 bytes WPA passphrase, so we don't check WEP64
    // hex and WEP128 passphrase.
    if (req.credentials.size() == ValidWiFiCredentialLength::kOpen || req.credentials.size() == ValidWiFiCredentialLength::kWEP64 ||
        (req.credentials.size() >= ValidWiFiCredentialLength::kMinWPAPSK &&
         req.credentials.size() <= ValidWiFiCredentialLength::kMaxWPAPSK))
    {
        // Valid length, the credentials can have any characters.
    }
    else if (req.credentials.size() == ValidWiFiCredentialLength::kWPAPSKHex)
    {
        for (size_t d = 0; d < req.credentials.size(); d++)
        {
            if (!isxdigit(req.credentials.data()[d]))
            {
                ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::InvalidCommand);
                return;
            }
        }
    }
    else
    {
        // Invalid length
        ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::InvalidCommand);
        return;
    }

    Commands::NetworkConfigResponse::Type response;
    MutableCharSpan debugText;
#if CHIP_CONFIG_NETWORK_COMMISSIONING_DEBUG_TEXT_BUFFER_SIZE
    char debugTextBuffer[CHIP_CONFIG_NETWORK_COMMISSIONING_DEBUG_TEXT_BUFFER_SIZE];
    debugText = MutableCharSpan(debugTextBuffer);
#endif
    uint8_t outNetworkIndex = 0;
    response.networkingStatus =
        mpDriver.Get<WiFiDriver *>()->AddOrUpdateNetwork(req.ssid, req.credentials, debugText, outNetworkIndex);
    FillDebugTextAndNetworkIndex(response, debugText, outNetworkIndex);
    ctx.mCommandHandler.AddResponse(ctx.mRequestPath, response);
    if (response.networkingStatus == NetworkCommissioningStatus::kSuccess)
    {
        UpdateBreadcrumb(req.breadcrumb);
    }
}

void Instance::HandleAddOrUpdateThreadNetwork(HandlerContext & ctx, const Commands::AddOrUpdateThreadNetwork::DecodableType & req)
{
    MATTER_TRACE_EVENT_SCOPE("HandleAddOrUpdateThreadNetwork", "NetworkCommissioning");

    VerifyOrReturn(CheckFailSafeArmed(ctx));

    Commands::NetworkConfigResponse::Type response;
    MutableCharSpan debugText;
#if CHIP_CONFIG_NETWORK_COMMISSIONING_DEBUG_TEXT_BUFFER_SIZE
    char debugTextBuffer[CHIP_CONFIG_NETWORK_COMMISSIONING_DEBUG_TEXT_BUFFER_SIZE];
    debugText = MutableCharSpan(debugTextBuffer);
#endif
    uint8_t outNetworkIndex = 0;
    response.networkingStatus =
        mpDriver.Get<ThreadDriver *>()->AddOrUpdateNetwork(req.operationalDataset, debugText, outNetworkIndex);
    FillDebugTextAndNetworkIndex(response, debugText, outNetworkIndex);
    ctx.mCommandHandler.AddResponse(ctx.mRequestPath, response);
    if (response.networkingStatus == NetworkCommissioningStatus::kSuccess)
    {
        UpdateBreadcrumb(req.breadcrumb);
    }
}

void Instance::UpdateBreadcrumb(const Optional<uint64_t> & breadcrumb)
{
    VerifyOrReturn(breadcrumb.HasValue());
    GeneralCommissioning::SetBreadcrumb(breadcrumb.Value());
}

void Instance::CommitSavedBreadcrumb()
{
    // We rejected the command when there is another ongoing command, so mCurrentOperationBreadcrumb reflects the breadcrumb
    // argument in the only background command.
    UpdateBreadcrumb(mCurrentOperationBreadcrumb);
    mCurrentOperationBreadcrumb.ClearValue();
}

void Instance::HandleRemoveNetwork(HandlerContext & ctx, const Commands::RemoveNetwork::DecodableType & req)
{
    MATTER_TRACE_EVENT_SCOPE("HandleRemoveNetwork", "NetworkCommissioning");

    VerifyOrReturn(CheckFailSafeArmed(ctx));

    Commands::NetworkConfigResponse::Type response;
    MutableCharSpan debugText;
#if CHIP_CONFIG_NETWORK_COMMISSIONING_DEBUG_TEXT_BUFFER_SIZE
    char debugTextBuffer[CHIP_CONFIG_NETWORK_COMMISSIONING_DEBUG_TEXT_BUFFER_SIZE];
    debugText = MutableCharSpan(debugTextBuffer);
#endif
    uint8_t outNetworkIndex   = 0;
    response.networkingStatus = mpWirelessDriver->RemoveNetwork(req.networkID, debugText, outNetworkIndex);
    FillDebugTextAndNetworkIndex(response, debugText, outNetworkIndex);
    ctx.mCommandHandler.AddResponse(ctx.mRequestPath, response);
    if (response.networkingStatus == NetworkCommissioningStatus::kSuccess)
    {
        UpdateBreadcrumb(req.breadcrumb);
    }
}

void Instance::HandleConnectNetwork(HandlerContext & ctx, const Commands::ConnectNetwork::DecodableType & req)
{
    MATTER_TRACE_EVENT_SCOPE("HandleConnectNetwork", "NetworkCommissioning");
    if (req.networkID.size() > DeviceLayer::NetworkCommissioning::kMaxNetworkIDLen)
    {
        ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::InvalidValue);
        return;
    }

    VerifyOrReturn(CheckFailSafeArmed(ctx));

    mConnectingNetworkIDLen = static_cast<uint8_t>(req.networkID.size());
    memcpy(mConnectingNetworkID, req.networkID.data(), mConnectingNetworkIDLen);
    mAsyncCommandHandle         = CommandHandler::Handle(&ctx.mCommandHandler);
    mCurrentOperationBreadcrumb = req.breadcrumb;
    mpWirelessDriver->ConnectNetwork(req.networkID, this);
}

void Instance::HandleReorderNetwork(HandlerContext & ctx, const Commands::ReorderNetwork::DecodableType & req)
{
    MATTER_TRACE_EVENT_SCOPE("HandleReorderNetwork", "NetworkCommissioning");
    Commands::NetworkConfigResponse::Type response;
    MutableCharSpan debugText;
#if CHIP_CONFIG_NETWORK_COMMISSIONING_DEBUG_TEXT_BUFFER_SIZE
    char debugTextBuffer[CHIP_CONFIG_NETWORK_COMMISSIONING_DEBUG_TEXT_BUFFER_SIZE];
    debugText = MutableCharSpan(debugTextBuffer);
#endif
    response.networkingStatus = mpWirelessDriver->ReorderNetwork(req.networkID, req.networkIndex, debugText);
    FillDebugTextAndNetworkIndex(response, debugText, req.networkIndex);
    ctx.mCommandHandler.AddResponse(ctx.mRequestPath, response);
    if (response.networkingStatus == NetworkCommissioningStatus::kSuccess)
    {
        UpdateBreadcrumb(req.breadcrumb);
    }
}

void Instance::OnResult(Status commissioningError, CharSpan debugText, int32_t interfaceStatus)
{
    auto commandHandleRef = std::move(mAsyncCommandHandle);
    auto commandHandle    = commandHandleRef.Get();
    if (commandHandle == nullptr)
    {
        // When the platform shutted down, interaction model engine will invalidate all commandHandle to avoid dangling references.
        // We may receive the callback after it and should make it noop.
        return;
    }

    Commands::ConnectNetworkResponse::Type response;
    response.networkingStatus = commissioningError;
    if (!debugText.empty())
    {
        response.debugText.SetValue(debugText);
    }
    if (commissioningError == Status::kSuccess)
    {
        DeviceLayer::DeviceControlServer::DeviceControlSvr().PostConnectedToOperationalNetworkEvent(
            ByteSpan(mLastNetworkID, mLastNetworkIDLen));
        mLastConnectErrorValue.SetNull();
    }
    else
    {
        response.errorValue.SetNonNull(interfaceStatus);
        mLastConnectErrorValue.SetNonNull(interfaceStatus);
    }

    mLastNetworkIDLen = mConnectingNetworkIDLen;
    memcpy(mLastNetworkID, mConnectingNetworkID, mLastNetworkIDLen);
    mLastNetworkingStatusValue.SetNonNull(commissioningError);

    commandHandle->AddResponse(mPath, response);
    if (commissioningError == NetworkCommissioningStatus::kSuccess)
    {
        CommitSavedBreadcrumb();
    }
}

void Instance::OnFinished(Status status, CharSpan debugText, ThreadScanResponseIterator * networks)
{
    CHIP_ERROR err        = CHIP_NO_ERROR;
    auto commandHandleRef = std::move(mAsyncCommandHandle);
    auto commandHandle    = commandHandleRef.Get();
    if (commandHandle == nullptr)
    {
        // When the platform shutted down, interaction model engine will invalidate all commandHandle to avoid dangling references.
        // We may receive the callback after it and should make it noop.
        return;
    }

    mLastNetworkingStatusValue.SetNonNull(status);
    mLastConnectErrorValue.SetNull();
    mLastNetworkIDLen = 0;

    TLV::TLVWriter * writer;
    TLV::TLVType listContainerType;
    ThreadScanResponse scanResponse;
    size_t networksEncoded = 0;
    uint8_t extendedAddressBuffer[Thread::kSizeExtendedPanId];

    SuccessOrExit(err = commandHandle->PrepareCommand(
                      ConcreteCommandPath(mPath.mEndpointId, NetworkCommissioning::Id, Commands::ScanNetworksResponse::Id)));
    VerifyOrExit((writer = commandHandle->GetCommandDataIBTLVWriter()) != nullptr, err = CHIP_ERROR_INCORRECT_STATE);

    SuccessOrExit(
        err = writer->Put(TLV::ContextTag(to_underlying(Commands::ScanNetworksResponse::Fields::kNetworkingStatus)), status));
    if (debugText.size() != 0)
    {
        SuccessOrExit(err = DataModel::Encode(
                          *writer, TLV::ContextTag(to_underlying(Commands::ScanNetworksResponse::Fields::kDebugText)), debugText));
    }
    SuccessOrExit(
        err = writer->StartContainer(TLV::ContextTag(to_underlying(Commands::ScanNetworksResponse::Fields::kThreadScanResults)),
                                     TLV::TLVType::kTLVType_Array, listContainerType));

    for (; networks != nullptr && networks->Next(scanResponse) && networksEncoded < kMaxNetworksInScanResponse; networksEncoded++)
    {
        Structs::ThreadInterfaceScanResult::Type result;
        Encoding::BigEndian::Put64(extendedAddressBuffer, scanResponse.extendedAddress);
        result.panId           = scanResponse.panId;
        result.extendedPanId   = scanResponse.extendedPanId;
        result.networkName     = CharSpan(scanResponse.networkName, scanResponse.networkNameLen);
        result.channel         = scanResponse.channel;
        result.version         = scanResponse.version;
        result.extendedAddress = ByteSpan(extendedAddressBuffer);
        result.rssi            = scanResponse.rssi;
        result.lqi             = scanResponse.lqi;
        SuccessOrExit(err = DataModel::Encode(*writer, TLV::AnonymousTag(), result));
    }

    SuccessOrExit(err = writer->EndContainer(listContainerType));
    SuccessOrExit(err = commandHandle->FinishCommand());

exit:
    if (err != CHIP_NO_ERROR)
    {
        ChipLogError(Zcl, "Failed to encode response: %s", err.AsString());
    }
    if (status == NetworkCommissioningStatus::kSuccess)
    {
        CommitSavedBreadcrumb();
    }
    networks->Release();
}

void Instance::OnFinished(Status status, CharSpan debugText, WiFiScanResponseIterator * networks)
{
    CHIP_ERROR err        = CHIP_NO_ERROR;
    auto commandHandleRef = std::move(mAsyncCommandHandle);
    auto commandHandle    = commandHandleRef.Get();
    if (commandHandle == nullptr)
    {
        // When the platform shutted down, interaction model engine will invalidate all commandHandle to avoid dangling references.
        // We may receive the callback after it and should make it noop.
        return;
    }

    mLastNetworkingStatusValue.SetNonNull(status);
    mLastConnectErrorValue.SetNull();
    mLastNetworkIDLen = 0;

    TLV::TLVWriter * writer;
    TLV::TLVType listContainerType;
    WiFiScanResponse scanResponse;
    size_t networksEncoded = 0;

    SuccessOrExit(err = commandHandle->PrepareCommand(
                      ConcreteCommandPath(mPath.mEndpointId, NetworkCommissioning::Id, Commands::ScanNetworksResponse::Id)));
    VerifyOrExit((writer = commandHandle->GetCommandDataIBTLVWriter()) != nullptr, err = CHIP_ERROR_INCORRECT_STATE);

    SuccessOrExit(
        err = writer->Put(TLV::ContextTag(to_underlying(Commands::ScanNetworksResponse::Fields::kNetworkingStatus)), status));
    if (debugText.size() != 0)
    {
        SuccessOrExit(err = DataModel::Encode(
                          *writer, TLV::ContextTag(to_underlying(Commands::ScanNetworksResponse::Fields::kDebugText)), debugText));
    }
    SuccessOrExit(
        err = writer->StartContainer(TLV::ContextTag(to_underlying(Commands::ScanNetworksResponse::Fields::kWiFiScanResults)),
                                     TLV::TLVType::kTLVType_Array, listContainerType));

    for (; networks != nullptr && networks->Next(scanResponse) && networksEncoded < kMaxNetworksInScanResponse; networksEncoded++)
    {
        Structs::WiFiInterfaceScanResult::Type result;
        result.security = scanResponse.security;
        result.ssid     = ByteSpan(scanResponse.ssid, scanResponse.ssidLen);
        result.bssid    = ByteSpan(scanResponse.bssid, sizeof(scanResponse.bssid));
        result.channel  = scanResponse.channel;
        result.wiFiBand = scanResponse.wiFiBand;
        result.rssi     = scanResponse.rssi;
        SuccessOrExit(err = DataModel::Encode(*writer, TLV::AnonymousTag(), result));
    }

    SuccessOrExit(err = writer->EndContainer(listContainerType));
    SuccessOrExit(err = commandHandle->FinishCommand());

exit:
    if (err != CHIP_NO_ERROR)
    {
        ChipLogError(Zcl, "Failed to encode response: %s", err.AsString());
    }
    if (status == NetworkCommissioningStatus::kSuccess)
    {
        CommitSavedBreadcrumb();
    }
    if (networks != nullptr)
    {
        networks->Release();
    }
}

void Instance::OnPlatformEventHandler(const DeviceLayer::ChipDeviceEvent * event, intptr_t arg)
{
    Instance * this_ = reinterpret_cast<Instance *>(arg);

    if (event->Type == DeviceLayer::DeviceEventType::kCommissioningComplete)
    {
        this_->OnCommissioningComplete();
    }
    else if (event->Type == DeviceLayer::DeviceEventType::kFailSafeTimerExpired)
    {
        this_->OnFailSafeTimerExpired();
    }
}

void Instance::OnCommissioningComplete()
{
    VerifyOrReturn(mpWirelessDriver != nullptr);

    ChipLogDetail(Zcl, "Commissioning complete, notify platform driver to persist network credentials.");
    mpWirelessDriver->CommitConfiguration();
}

void Instance::OnFailSafeTimerExpired()
{
    VerifyOrReturn(mpWirelessDriver != nullptr);

    ChipLogDetail(Zcl, "Failsafe timeout, tell platform driver to revert network credentials.");
    mpWirelessDriver->RevertConfiguration();
    mAsyncCommandHandle.Release();
}

CHIP_ERROR Instance::EnumerateAcceptedCommands(const ConcreteClusterPath & cluster, CommandIdCallback callback, void * context)
{
    using namespace Clusters::NetworkCommissioning::Commands;

    constexpr CommandId acceptedCommandsListWiFi[] = {
        ScanNetworks::Id, AddOrUpdateWiFiNetwork::Id, RemoveNetwork::Id, ConnectNetwork::Id, ReorderNetwork::Id,
    };
    constexpr CommandId acceptedCommandsListThread[] = {
        ScanNetworks::Id, AddOrUpdateThreadNetwork::Id, RemoveNetwork::Id, ConnectNetwork::Id, ReorderNetwork::Id,
    };

    if (mFeatureFlags.Has(NetworkCommissioningFeature::kThreadNetworkInterface))
    {
        for (const auto & cmd : acceptedCommandsListThread)
        {
            if (callback(cmd, context) != Loop::Continue)
            {
                break;
            }
        }

        return CHIP_NO_ERROR;
    }

    if (mFeatureFlags.Has(NetworkCommissioningFeature::kWiFiNetworkInterface))
    {
        for (const auto & cmd : acceptedCommandsListWiFi)
        {
            if (callback(cmd, context) != Loop::Continue)
            {
                break;
            }
        }

        return CHIP_NO_ERROR;
    }

    return CHIP_NO_ERROR;
}

CHIP_ERROR Instance::EnumerateGeneratedCommands(const ConcreteClusterPath & cluster, CommandIdCallback callback, void * context)
{
    using namespace Clusters::NetworkCommissioning::Commands;

    constexpr CommandId generatedCommandsListWireless[] = { ScanNetworksResponse::Id, NetworkConfigResponse::Id,
                                                            ConnectNetworkResponse::Id };

    if (mFeatureFlags.HasAny(NetworkCommissioningFeature::kWiFiNetworkInterface,
                             NetworkCommissioningFeature::kThreadNetworkInterface))
    {
        for (const auto & cmd : generatedCommandsListWireless)
        {
            if (callback(cmd, context) != Loop::Continue)
            {
                break;
            }
        }
    }

    return CHIP_NO_ERROR;
}

bool NullNetworkDriver::GetEnabled()
{
    // Disable the interface and it cannot be enabled since there are no physical interfaces.
    return false;
}

uint8_t NullNetworkDriver::GetMaxNetworks()
{
    // The minimal value of MaxNetworks should be 1 per spec.
    return 1;
}

DeviceLayer::NetworkCommissioning::NetworkIterator * NullNetworkDriver::GetNetworks()
{
    // Instance::Read accepts nullptr as an empty NetworkIterator.
    return nullptr;
}

} // namespace NetworkCommissioning
} // namespace Clusters
} // namespace app
} // namespace chip

// These functions are ember interfaces, they should never be implemented since all network commissioning cluster functions are
// implemented in NetworkCommissioning::Instance.
bool emberAfNetworkCommissioningClusterAddOrUpdateThreadNetworkCallback(
    CommandHandler * commandObj, const ConcreteCommandPath & commandPath,
    const Commands::AddOrUpdateThreadNetwork::DecodableType & commandData)
{
    return false;
}

bool emberAfNetworkCommissioningClusterAddOrUpdateWiFiNetworkCallback(
    CommandHandler * commandObj, const ConcreteCommandPath & commandPath,
    const Commands::AddOrUpdateWiFiNetwork::DecodableType & commandData)
{
    return false;
}

bool emberAfNetworkCommissioningClusterConnectNetworkCallback(CommandHandler * commandObj, const ConcreteCommandPath & commandPath,
                                                              const Commands::ConnectNetwork::DecodableType & commandData)
{
    return false;
}

bool emberAfNetworkCommissioningClusterRemoveNetworkCallback(CommandHandler * commandObj, const ConcreteCommandPath & commandPath,
                                                             const Commands::RemoveNetwork::DecodableType & commandData)
{
    return false;
}

bool emberAfNetworkCommissioningClusterScanNetworksCallback(CommandHandler * commandObj, const ConcreteCommandPath & commandPath,
                                                            const Commands::ScanNetworks::DecodableType & commandData)
{
    return false;
}

bool emberAfNetworkCommissioningClusterReorderNetworkCallback(CommandHandler * commandObj, const ConcreteCommandPath & commandPath,
                                                              const Commands::ReorderNetwork::DecodableType & commandData)
{
    return false;
}

void MatterNetworkCommissioningPluginServerInitCallback()
{
    // Nothing to do, the server init routine will be done in Instance::Init()
}
