/*
 *
 *    Copyright (c) 2020-2021 Project CHIP Authors
 *    Copyright (c) 2018 Nest Labs, Inc.
 *
 *    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.
 */

/**
 *    @file
 *          Provides an implementation of the BLEManager singleton object
 *          for Linux platforms.
 */

/**
 * Note: BLEManager requires ConnectivityManager to be defined beforehand,
 *       otherwise we will face circular dependency between them. */
#include <platform/ConnectivityManager.h>

/**
 * Note: Use public include for BLEManager which includes our local
 *       platform/<PLATFORM>/BLEManagerImpl.h after defining interface class. */
#include "platform/internal/BLEManager.h"

#include <type_traits>
#include <utility>

#include <ble/Ble.h>
#include <lib/support/CHIPMemString.h>
#include <lib/support/CodeUtils.h>
#include <lib/support/SafeInt.h>
#include <platform/CHIPDeviceLayer.h>
#include <platform/CommissionableDataProvider.h>

#include "bluez/BluezEndpoint.h"

#if !CHIP_DEVICE_CONFIG_SUPPORTS_CONCURRENT_CONNECTION
#include <platform/DeviceControlServer.h>
#endif

using namespace ::nl;
using namespace ::chip::Ble;

namespace chip {
namespace DeviceLayer {
namespace Internal {

namespace {

static constexpr System::Clock::Timeout kNewConnectionScanTimeout = System::Clock::Seconds16(20);
static constexpr System::Clock::Timeout kConnectTimeout           = System::Clock::Seconds16(20);
static constexpr System::Clock::Timeout kFastAdvertiseTimeout =
    System::Clock::Milliseconds32(CHIP_DEVICE_CONFIG_BLE_ADVERTISING_INTERVAL_CHANGE_TIME);
#if CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING
// The CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING_INTERVAL_CHANGE_TIME_MS specifies the transition time
// starting from advertisement commencement. Since the extended advertisement timer is started after
// the fast-to-slow transition, we have to subtract the time spent in fast advertising.
static constexpr System::Clock::Timeout kSlowAdvertiseTimeout = System::Clock::Milliseconds32(
    CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING_INTERVAL_CHANGE_TIME_MS - CHIP_DEVICE_CONFIG_BLE_ADVERTISING_INTERVAL_CHANGE_TIME);
static_assert(CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING_INTERVAL_CHANGE_TIME_MS >=
                  CHIP_DEVICE_CONFIG_BLE_ADVERTISING_INTERVAL_CHANGE_TIME,
              "The extended advertising interval change time must be greater than the fast advertising interval change time");
#endif

const ChipBleUUID ChipUUID_CHIPoBLEChar_RX = { { 0x18, 0xEE, 0x2E, 0xF5, 0x26, 0x3D, 0x45, 0x59, 0x95, 0x9F, 0x4F, 0x9C, 0x42, 0x9F,
                                                 0x9D, 0x11 } };
const ChipBleUUID ChipUUID_CHIPoBLEChar_TX = { { 0x18, 0xEE, 0x2E, 0xF5, 0x26, 0x3D, 0x45, 0x59, 0x95, 0x9F, 0x4F, 0x9C, 0x42, 0x9F,
                                                 0x9D, 0x12 } };

} // namespace

BLEManagerImpl BLEManagerImpl::sInstance;

CHIP_ERROR BLEManagerImpl::_Init()
{
    CHIP_ERROR err;

    err = BleLayer::Init(this, this, this, &DeviceLayer::SystemLayer());
    SuccessOrExit(err);

    mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Enabled;
    mFlags.ClearAll().Set(Flags::kAdvertisingEnabled, CHIP_DEVICE_CONFIG_CHIPOBLE_ENABLE_ADVERTISING_AUTOSTART && !mIsCentral);
    mFlags.Set(Flags::kFastAdvertisingEnabled, true);

    memset(mDeviceName, 0, sizeof(mDeviceName));

    DeviceLayer::SystemLayer().ScheduleLambda([this] { DriveBLEState(); });

exit:
    return err;
}

void BLEManagerImpl::_Shutdown()
{
    // Make sure that timers are stopped before shutting down the BLE layer.
    DeviceLayer::SystemLayer().CancelTimer(HandleScanTimer, this);
    DeviceLayer::SystemLayer().CancelTimer(HandleAdvertisingTimer, this);
    DeviceLayer::SystemLayer().CancelTimer(HandleConnectTimer, this);

    mDeviceScanner.Shutdown();
    mBLEAdvertisement.Shutdown();
    mEndpoint.Shutdown();

    mBluezObjectManager.Shutdown();
    mFlags.Clear(Flags::kBluezManagerInitialized);
}

CHIP_ERROR BLEManagerImpl::_SetAdvertisingEnabled(bool val)
{
    CHIP_ERROR err = CHIP_NO_ERROR;

    if (mFlags.Has(Flags::kAdvertisingEnabled) != val)
    {
        mFlags.Set(Flags::kAdvertisingEnabled, val);
    }

    DeviceLayer::SystemLayer().ScheduleLambda([this] { DriveBLEState(); });

    return err;
}

CHIP_ERROR BLEManagerImpl::_SetAdvertisingMode(BLEAdvertisingMode mode)
{
    switch (mode)
    {
    case BLEAdvertisingMode::kFastAdvertising:
        mFlags.Set(Flags::kFastAdvertisingEnabled, true);
        break;
    case BLEAdvertisingMode::kSlowAdvertising:
        mFlags.Set(Flags::kFastAdvertisingEnabled, false);
        break;
    default:
        return CHIP_ERROR_INVALID_ARGUMENT;
    }
    mFlags.Set(Flags::kAdvertisingRefreshNeeded);
    DeviceLayer::SystemLayer().ScheduleLambda([this] { DriveBLEState(); });
    return CHIP_NO_ERROR;
}

CHIP_ERROR BLEManagerImpl::_GetDeviceName(char * buf, size_t bufSize)
{
    if (strlen(mDeviceName) >= bufSize)
    {
        return CHIP_ERROR_BUFFER_TOO_SMALL;
    }
    strcpy(buf, mDeviceName);

    return CHIP_NO_ERROR;
}

CHIP_ERROR BLEManagerImpl::_SetDeviceName(const char * deviceName)
{
    CHIP_ERROR err = CHIP_NO_ERROR;

    VerifyOrExit(mServiceMode != ConnectivityManager::kCHIPoBLEServiceMode_NotSupported, err = CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE);

    if (deviceName != nullptr && deviceName[0] != 0)
    {
        VerifyOrExit(strlen(deviceName) < kMaxDeviceNameLength, err = CHIP_ERROR_INVALID_ARGUMENT);
        strcpy(mDeviceName, deviceName);
        mFlags.Set(Flags::kUseCustomDeviceName);
    }
    else
    {
        uint16_t discriminator;
        SuccessOrExit(err = GetCommissionableDataProvider()->GetSetupDiscriminator(discriminator));
        snprintf(mDeviceName, sizeof(mDeviceName), "%s%04u", CHIP_DEVICE_CONFIG_BLE_DEVICE_NAME_PREFIX, discriminator);
        mDeviceName[kMaxDeviceNameLength] = 0;
        mFlags.Clear(Flags::kUseCustomDeviceName);
    }

exit:
    return err;
}

uint16_t BLEManagerImpl::_NumConnections()
{
    uint16_t numCons = 0;
    return numCons;
}

CHIP_ERROR BLEManagerImpl::ConfigureBle(uint32_t aAdapterId, bool aIsCentral)
{
    mAdapterId   = aAdapterId;
    mIsCentral   = aIsCentral;
    mpBLEAdvUUID = "0xFFF6";
    return CHIP_NO_ERROR;
}

void BLEManagerImpl::_OnPlatformEvent(const ChipDeviceEvent * event)
{
    switch (event->Type)
    {
    case DeviceEventType::kCHIPoBLESubscribe:
        HandleSubscribeReceived(event->CHIPoBLESubscribe.ConId, &CHIP_BLE_SVC_ID, &ChipUUID_CHIPoBLEChar_TX);
        {
            ChipDeviceEvent connectionEvent;
            connectionEvent.Type = DeviceEventType::kCHIPoBLEConnectionEstablished;
            PlatformMgr().PostEventOrDie(&connectionEvent);
        }
        break;

    case DeviceEventType::kCHIPoBLEUnsubscribe:
        HandleUnsubscribeReceived(event->CHIPoBLEUnsubscribe.ConId, &CHIP_BLE_SVC_ID, &ChipUUID_CHIPoBLEChar_TX);
        break;

    case DeviceEventType::kCHIPoBLEWriteReceived:
        HandleWriteReceived(event->CHIPoBLEWriteReceived.ConId, &CHIP_BLE_SVC_ID, &ChipUUID_CHIPoBLEChar_RX,
                            PacketBufferHandle::Adopt(event->CHIPoBLEWriteReceived.Data));
        break;

    case DeviceEventType::kCHIPoBLEIndicateConfirm:
        HandleIndicationConfirmation(event->CHIPoBLEIndicateConfirm.ConId, &CHIP_BLE_SVC_ID, &ChipUUID_CHIPoBLEChar_TX);
        break;

    case DeviceEventType::kCHIPoBLEConnectionError:
        HandleConnectionError(event->CHIPoBLEConnectionError.ConId, event->CHIPoBLEConnectionError.Reason);
        break;
    case DeviceEventType::kServiceProvisioningChange:
        // Force the advertising configuration to be refreshed to reflect new provisioning state.
        mFlags.Clear(Flags::kAdvertisingConfigured);

        DriveBLEState();
        break;
    default:
        HandlePlatformSpecificBLEEvent(event);
        break;
    }
}

void BLEManagerImpl::HandlePlatformSpecificBLEEvent(const ChipDeviceEvent * apEvent)
{
    CHIP_ERROR err = CHIP_NO_ERROR;
    ChipLogDetail(DeviceLayer, "HandlePlatformSpecificBLEEvent %d", apEvent->Type);
    switch (apEvent->Type)
    {
    case DeviceEventType::kPlatformLinuxBLEAdapterAdded:
        ChipLogDetail(DeviceLayer, "BLE adapter added: id=%u address=%s", apEvent->Platform.BLEAdapter.mAdapterId,
                      apEvent->Platform.BLEAdapter.mAdapterAddress);
        if (apEvent->Platform.BLEAdapter.mAdapterId == mAdapterId)
        {
            mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Enabled;
            DriveBLEState();
        }
        break;
    case DeviceEventType::kPlatformLinuxBLEAdapterRemoved:
        ChipLogDetail(DeviceLayer, "BLE adapter removed: id=%u address=%s", apEvent->Platform.BLEAdapter.mAdapterId,
                      apEvent->Platform.BLEAdapter.mAdapterAddress);
        if (apEvent->Platform.BLEAdapter.mAdapterId == mAdapterId)
        {
            // Shutdown all BLE operations and release resources
            mDeviceScanner.Shutdown();
            mBLEAdvertisement.Shutdown();
            mEndpoint.Shutdown();
            // Drop reference to the adapter
            mAdapter.reset();
            // Clear all flags related to BlueZ BLE operations
            mFlags.Clear(Flags::kBluezAdapterAvailable);
            mFlags.Clear(Flags::kBluezBLELayerInitialized);
            mFlags.Clear(Flags::kAdvertisingConfigured);
            mFlags.Clear(Flags::kAppRegistered);
            mFlags.Clear(Flags::kAdvertising);
            CleanScanConfig();
            // Indicate that the adapter is no longer available
            err = BLE_ERROR_ADAPTER_UNAVAILABLE;
        }
        break;
    case DeviceEventType::kPlatformLinuxBLECentralConnected:
        if (mBLEScanConfig.mBleScanState == BleScanState::kConnecting)
        {
            BleConnectionDelegate::OnConnectionComplete(mBLEScanConfig.mAppState,
                                                        apEvent->Platform.BLECentralConnected.mConnection);
            CleanScanConfig();
        }
        break;
    case DeviceEventType::kPlatformLinuxBLECentralConnectFailed:
        if (mBLEScanConfig.mBleScanState == BleScanState::kConnecting)
        {
            BleConnectionDelegate::OnConnectionError(mBLEScanConfig.mAppState, apEvent->Platform.BLECentralConnectFailed.mError);
            CleanScanConfig();
        }
        break;
    case DeviceEventType::kPlatformLinuxBLEWriteComplete:
        HandleWriteConfirmation(apEvent->Platform.BLEWriteComplete.mConnection, &CHIP_BLE_SVC_ID, &ChipUUID_CHIPoBLEChar_RX);
        break;
    case DeviceEventType::kPlatformLinuxBLESubscribeOpComplete:
        if (apEvent->Platform.BLESubscribeOpComplete.mIsSubscribed)
            HandleSubscribeComplete(apEvent->Platform.BLESubscribeOpComplete.mConnection, &CHIP_BLE_SVC_ID,
                                    &ChipUUID_CHIPoBLEChar_TX);
        else
            HandleUnsubscribeComplete(apEvent->Platform.BLESubscribeOpComplete.mConnection, &CHIP_BLE_SVC_ID,
                                      &ChipUUID_CHIPoBLEChar_TX);
        break;
    case DeviceEventType::kPlatformLinuxBLEIndicationReceived:
        HandleIndicationReceived(apEvent->Platform.BLEIndicationReceived.mConnection, &CHIP_BLE_SVC_ID, &ChipUUID_CHIPoBLEChar_TX,
                                 PacketBufferHandle::Adopt(apEvent->Platform.BLEIndicationReceived.mData));
        break;
    case DeviceEventType::kPlatformLinuxBLEPeripheralAdvStartComplete:
        SuccessOrExit(err = apEvent->Platform.BLEPeripheralAdvStartComplete.mError);
        mFlags.Clear(Flags::kControlOpInProgress).Clear(Flags::kAdvertisingRefreshNeeded);
        // Do not restart the timer if it is still active. This is to avoid the timer from being restarted
        // if the advertising is stopped due to a premature release.
        if (!DeviceLayer::SystemLayer().IsTimerActive(HandleAdvertisingTimer, this))
        {
            // Start a timer to make sure that the fast advertising is stopped after specified timeout.
            SuccessOrExit(err = DeviceLayer::SystemLayer().StartTimer(kFastAdvertiseTimeout, HandleAdvertisingTimer, this));
        }
        mFlags.Set(Flags::kAdvertising);
        break;
    case DeviceEventType::kPlatformLinuxBLEPeripheralAdvStopComplete:
        SuccessOrExit(err = apEvent->Platform.BLEPeripheralAdvStopComplete.mError);
        mFlags.Clear(Flags::kControlOpInProgress).Clear(Flags::kAdvertisingRefreshNeeded);
        DeviceLayer::SystemLayer().CancelTimer(HandleAdvertisingTimer, this);
        // Transition to the not Advertising state...
        if (mFlags.Has(Flags::kAdvertising))
        {
            mFlags.Clear(Flags::kAdvertising);
            ChipLogProgress(DeviceLayer, "CHIPoBLE advertising stopped");
        }
        break;
    case DeviceEventType::kPlatformLinuxBLEPeripheralAdvReleased:
        // If the advertising was stopped due to a premature release, check if it needs to be restarted.
        mFlags.Clear(Flags::kAdvertising);
        DriveBLEState();
        break;
    case DeviceEventType::kPlatformLinuxBLEPeripheralRegisterAppComplete:
        SuccessOrExit(err = apEvent->Platform.BLEPeripheralRegisterAppComplete.mError);
        mFlags.Clear(Flags::kControlOpInProgress);
        mFlags.Set(Flags::kAppRegistered);
        DriveBLEState();
        break;
    default:
        break;
    }

exit:
    if (err != CHIP_NO_ERROR)
    {
        DisableBLEService(err);
        mFlags.Clear(Flags::kControlOpInProgress);
    }
}

uint16_t BLEManagerImpl::GetMTU(BLE_CONNECTION_OBJECT conId) const
{
    uint16_t mtu = 0;
    VerifyOrExit(conId != BLE_CONNECTION_UNINITIALIZED,
                 ChipLogError(DeviceLayer, "BLE connection is not initialized in %s", __func__));
    mtu = conId->GetMTU();
exit:
    return mtu;
}

bool BLEManagerImpl::SubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId)
{
    bool result = false;

    VerifyOrExit(conId != BLE_CONNECTION_UNINITIALIZED,
                 ChipLogError(DeviceLayer, "BLE connection is not initialized in %s", __func__));
    VerifyOrExit(Ble::UUIDsMatch(svcId, &CHIP_BLE_SVC_ID),
                 ChipLogError(DeviceLayer, "SubscribeCharacteristic() called with invalid service ID"));
    VerifyOrExit(Ble::UUIDsMatch(charId, &ChipUUID_CHIPoBLEChar_TX),
                 ChipLogError(DeviceLayer, "SubscribeCharacteristic() called with invalid characteristic ID"));

    VerifyOrExit(conId->SubscribeCharacteristic() == CHIP_NO_ERROR, ChipLogError(DeviceLayer, "SubscribeCharacteristic() failed"));
    result = true;

exit:
    return result;
}

bool BLEManagerImpl::UnsubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId)
{
    bool result = false;

    VerifyOrExit(conId != BLE_CONNECTION_UNINITIALIZED,
                 ChipLogError(DeviceLayer, "BLE connection is not initialized in %s", __func__));
    VerifyOrExit(Ble::UUIDsMatch(svcId, &CHIP_BLE_SVC_ID),
                 ChipLogError(DeviceLayer, "UnsubscribeCharacteristic() called with invalid service ID"));
    VerifyOrExit(Ble::UUIDsMatch(charId, &ChipUUID_CHIPoBLEChar_TX),
                 ChipLogError(DeviceLayer, "UnsubscribeCharacteristic() called with invalid characteristic ID"));

    VerifyOrExit(conId->UnsubscribeCharacteristic() == CHIP_NO_ERROR,
                 ChipLogError(DeviceLayer, "UnsubscribeCharacteristic() failed"));
    result = true;

exit:
    return result;
}

bool BLEManagerImpl::CloseConnection(BLE_CONNECTION_OBJECT conId)
{
    bool result = false;

    VerifyOrExit(conId != BLE_CONNECTION_UNINITIALIZED,
                 ChipLogError(DeviceLayer, "BLE connection is not initialized in %s", __func__));
    ChipLogProgress(DeviceLayer, "Closing BLE GATT connection (con %p)", conId);

    VerifyOrExit(conId->CloseConnection() == CHIP_NO_ERROR, ChipLogError(DeviceLayer, "CloseConnection() failed"));
    result = true;

exit:
    return result;
}

bool BLEManagerImpl::SendIndication(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const Ble::ChipBleUUID * charId,
                                    chip::System::PacketBufferHandle pBuf)
{
    bool result = false;

    VerifyOrExit(conId != BLE_CONNECTION_UNINITIALIZED,
                 ChipLogError(DeviceLayer, "BLE connection is not initialized in %s", __func__));
    VerifyOrExit(conId->SendIndication(std::move(pBuf)) == CHIP_NO_ERROR, ChipLogError(DeviceLayer, "SendIndication() failed"));
    result = true;

exit:
    return result;
}

bool BLEManagerImpl::SendWriteRequest(BLE_CONNECTION_OBJECT conId, const Ble::ChipBleUUID * svcId, const Ble::ChipBleUUID * charId,
                                      chip::System::PacketBufferHandle pBuf)
{
    bool result = false;

    VerifyOrExit(conId != BLE_CONNECTION_UNINITIALIZED,
                 ChipLogError(DeviceLayer, "BLE connection is not initialized in %s", __func__));
    VerifyOrExit(Ble::UUIDsMatch(svcId, &CHIP_BLE_SVC_ID),
                 ChipLogError(DeviceLayer, "SendWriteRequest() called with invalid service ID"));
    VerifyOrExit(Ble::UUIDsMatch(charId, &ChipUUID_CHIPoBLEChar_RX),
                 ChipLogError(DeviceLayer, "SendWriteRequest() called with invalid characteristic ID"));

    VerifyOrExit(conId->SendWriteRequest(std::move(pBuf)) == CHIP_NO_ERROR, ChipLogError(DeviceLayer, "SendWriteRequest() failed"));
    result = true;

exit:
    return result;
}

bool BLEManagerImpl::SendReadRequest(BLE_CONNECTION_OBJECT conId, const Ble::ChipBleUUID * svcId, const Ble::ChipBleUUID * charId,
                                     chip::System::PacketBufferHandle pBuf)
{
    ChipLogError(Ble, "SendReadRequest: Not implemented");
    return true;
}

bool BLEManagerImpl::SendReadResponse(BLE_CONNECTION_OBJECT conId, BLE_READ_REQUEST_CONTEXT requestContext,
                                      const Ble::ChipBleUUID * svcId, const Ble::ChipBleUUID * charId)
{
    ChipLogError(Ble, "SendReadRBluezonse: Not implemented");
    return true;
}

void BLEManagerImpl::HandleNewConnection(BLE_CONNECTION_OBJECT conId)
{
    if (sInstance.mIsCentral)
    {
        ChipDeviceEvent event;
        event.Type                                     = DeviceEventType::kPlatformLinuxBLECentralConnected;
        event.Platform.BLECentralConnected.mConnection = conId;
        PlatformMgr().PostEventOrDie(&event);
    }
}

void BLEManagerImpl::HandleConnectFailed(CHIP_ERROR error)
{
    if (sInstance.mIsCentral)
    {
        ChipDeviceEvent event;
        event.Type                                    = DeviceEventType::kPlatformLinuxBLECentralConnectFailed;
        event.Platform.BLECentralConnectFailed.mError = error;
        PlatformMgr().PostEventOrDie(&event);
    }
}

void BLEManagerImpl::HandleWriteComplete(BLE_CONNECTION_OBJECT conId)
{
    ChipDeviceEvent event;
    event.Type                                  = DeviceEventType::kPlatformLinuxBLEWriteComplete;
    event.Platform.BLEWriteComplete.mConnection = conId;
    PlatformMgr().PostEventOrDie(&event);
}

void BLEManagerImpl::HandleSubscribeOpComplete(BLE_CONNECTION_OBJECT conId, bool subscribed)
{
    ChipDeviceEvent event;
    event.Type                                          = DeviceEventType::kPlatformLinuxBLESubscribeOpComplete;
    event.Platform.BLESubscribeOpComplete.mConnection   = conId;
    event.Platform.BLESubscribeOpComplete.mIsSubscribed = subscribed;
    PlatformMgr().PostEventOrDie(&event);
}

void BLEManagerImpl::HandleTXCharChanged(BLE_CONNECTION_OBJECT conId, const uint8_t * value, size_t len)
{
    CHIP_ERROR err                 = CHIP_NO_ERROR;
    System::PacketBufferHandle buf = System::PacketBufferHandle::NewWithData(value, len);

    ChipLogDetail(DeviceLayer, "Indication received, conn = %p", conId);

    VerifyOrExit(!buf.IsNull(), err = CHIP_ERROR_NO_MEMORY);

    ChipDeviceEvent event;
    event.Type                                       = DeviceEventType::kPlatformLinuxBLEIndicationReceived;
    event.Platform.BLEIndicationReceived.mConnection = conId;
    event.Platform.BLEIndicationReceived.mData       = std::move(buf).UnsafeRelease();
    PlatformMgr().PostEventOrDie(&event);

exit:
    if (err != CHIP_NO_ERROR)
        ChipLogError(DeviceLayer, "HandleTXCharChanged() failed: %s", ErrorStr(err));
}

void BLEManagerImpl::HandleRXCharWrite(BLE_CONNECTION_OBJECT conId, const uint8_t * value, size_t len)
{
    CHIP_ERROR err = CHIP_NO_ERROR;
    System::PacketBufferHandle buf;

    // Copy the data to a packet buffer.
    buf = System::PacketBufferHandle::NewWithData(value, len);
    VerifyOrExit(!buf.IsNull(), err = CHIP_ERROR_NO_MEMORY);

    // Post an event to the Chip queue to deliver the data into the Chip stack.
    {
        ChipDeviceEvent event;
        event.Type = DeviceEventType::kCHIPoBLEWriteReceived;
        ChipLogProgress(Ble, "Write request received debug %p", conId);
        event.CHIPoBLEWriteReceived.ConId = conId;
        event.CHIPoBLEWriteReceived.Data  = std::move(buf).UnsafeRelease();
        PlatformMgr().PostEventOrDie(&event);
    }

exit:
    if (err != CHIP_NO_ERROR)
    {
        ChipLogError(DeviceLayer, "HandleRXCharWrite() failed: %s", ErrorStr(err));
    }
}

void BLEManagerImpl::CHIPoBluez_ConnectionClosed(BLE_CONNECTION_OBJECT conId)
{
    ChipLogProgress(DeviceLayer, "Bluez notify CHIPoBluez connection disconnected");

    // If this was a CHIPoBLE connection, post an event to deliver a connection error to the CHIPoBLE layer.
    {
        ChipDeviceEvent event;
        event.Type                           = DeviceEventType::kCHIPoBLEConnectionError;
        event.CHIPoBLEConnectionError.ConId  = conId;
        event.CHIPoBLEConnectionError.Reason = BLE_ERROR_REMOTE_DEVICE_DISCONNECTED;
        PlatformMgr().PostEventOrDie(&event);
    }
}

void BLEManagerImpl::HandleTXCharCCCDWrite(BLE_CONNECTION_OBJECT conId)
{
    VerifyOrReturn(conId != BLE_CONNECTION_UNINITIALIZED,
                   ChipLogError(DeviceLayer, "BLE connection is not initialized in %s", __func__));

    // Post an event to the Chip queue to process either a CHIPoBLE Subscribe or Unsubscribe based on
    // whether the client is enabling or disabling indications.
    ChipDeviceEvent event;
    event.Type = conId->IsNotifyAcquired() ? DeviceEventType::kCHIPoBLESubscribe : DeviceEventType::kCHIPoBLEUnsubscribe;
    event.CHIPoBLESubscribe.ConId = conId;
    PlatformMgr().PostEventOrDie(&event);

    ChipLogProgress(DeviceLayer, "CHIPoBLE %s received",
                    (event.Type == DeviceEventType::kCHIPoBLESubscribe) ? "subscribe" : "unsubscribe");
}

void BLEManagerImpl::HandleTXComplete(BLE_CONNECTION_OBJECT conId)
{
    // Post an event to the Chip queue to process the indicate confirmation.
    ChipDeviceEvent event;
    event.Type                          = DeviceEventType::kCHIPoBLEIndicateConfirm;
    event.CHIPoBLEIndicateConfirm.ConId = conId;
    PlatformMgr().PostEventOrDie(&event);
}

void BLEManagerImpl::DriveBLEState()
{
    CHIP_ERROR err = CHIP_NO_ERROR;

    // Perform any initialization actions that must occur after the Chip task is running.
    if (!mFlags.Has(Flags::kAsyncInitCompleted))
    {
        mFlags.Set(Flags::kAsyncInitCompleted);
        ExitNow();
    }

    // If there's already a control operation in progress, wait until it completes.
    VerifyOrExit(!mFlags.Has(Flags::kControlOpInProgress), /* */);

    // Initializes the BlueZ BLE layer if needed.
    if (mServiceMode == ConnectivityManager::kCHIPoBLEServiceMode_Enabled)
    {
        if (!mFlags.Has(Flags::kBluezManagerInitialized))
        {
            SuccessOrExit(err = mBluezObjectManager.Init());
            mFlags.Set(Flags::kBluezManagerInitialized);
        }
        if (!mFlags.Has(Flags::kBluezAdapterAvailable))
        {
            mAdapter.reset(mBluezObjectManager.GetAdapter(mAdapterId));
            VerifyOrExit(mAdapter, err = BLE_ERROR_ADAPTER_UNAVAILABLE);
            mFlags.Set(Flags::kBluezAdapterAvailable);
        }
        if (!mFlags.Has(Flags::kBluezBLELayerInitialized))
        {
            SuccessOrExit(err = mEndpoint.Init(mAdapter.get(), mIsCentral));
            mFlags.Set(Flags::kBluezBLELayerInitialized);
        }
    }

    // Register the CHIPoBLE application with the Bluez BLE layer if needed.
    if (!mIsCentral && mServiceMode == ConnectivityManager::kCHIPoBLEServiceMode_Enabled && !mFlags.Has(Flags::kAppRegistered))
    {
        SuccessOrExit(err = mEndpoint.RegisterGattApplication());
        mFlags.Set(Flags::kControlOpInProgress);
        ExitNow();
    }

    // If the application has enabled CHIPoBLE and BLE advertising...
    if (mServiceMode == ConnectivityManager::kCHIPoBLEServiceMode_Enabled && mFlags.Has(Flags::kAdvertisingEnabled))
    {
        // Start/re-start advertising if not already advertising, or if the advertising state of the
        // Bluez BLE layer needs to be refreshed.
        if (!mFlags.Has(Flags::kAdvertising) || mFlags.Has(Flags::kAdvertisingRefreshNeeded))
        {
            mFlags.Clear(Flags::kAdvertisingRefreshNeeded);

            // Configure advertising data if it hasn't been done yet.
            if (!mFlags.Has(Flags::kAdvertisingConfigured))
            {
                SuccessOrExit(err = mBLEAdvertisement.Init(mAdapter.get(), mpBLEAdvUUID, mDeviceName));
                mFlags.Set(Flags::kAdvertisingConfigured);
            }

            // Setup service data for advertising.
            auto serviceDataFlags = BluezAdvertisement::kServiceDataNone;
#if CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING
            if (mFlags.Has(Flags::kExtAdvertisingEnabled))
                serviceDataFlags |= BluezAdvertisement::kServiceDataExtendedAnnouncement;
#endif
            SuccessOrExit(err = mBLEAdvertisement.SetupServiceData(serviceDataFlags));

            // Set or update the advertising intervals.
            SuccessOrExit(err = mBLEAdvertisement.SetIntervals(GetAdvertisingIntervals()));

            if (!mFlags.Has(Flags::kAdvertising))
            {
                // Start advertising. This is an asynchronous step. BLE manager will be notified of
                // advertising start completion via a call to NotifyBLEPeripheralAdvStartComplete.
                SuccessOrExit(err = mBLEAdvertisement.Start());
                mFlags.Set(Flags::kControlOpInProgress);
                ExitNow();
            }
        }
    }

    // Otherwise stop advertising if needed...
    else
    {
        if (mFlags.Has(Flags::kAdvertising))
        {
            SuccessOrExit(err = mBLEAdvertisement.Stop());
            mFlags.Set(Flags::kControlOpInProgress);

            ExitNow();
        }
    }

exit:
    if (err != CHIP_NO_ERROR)
    {
        DisableBLEService(err);
    }
}

void BLEManagerImpl::DisableBLEService(CHIP_ERROR err)
{
    ChipLogError(DeviceLayer, "Disabling CHIPoBLE service due to error: %" CHIP_ERROR_FORMAT, err.Format());
    mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Disabled;
    // Stop all timers if the error is other than BLE adapter unavailable. In case of BLE adapter
    // beeing unavailable, we will keep timers running, as the adapter might become available in
    // the nearest future (e.g. BlueZ restart due to crash). By doing that we will ensure that BLE
    // adapter reappearance will not extend timeouts for the ongoing operations.
    if (err != BLE_ERROR_ADAPTER_UNAVAILABLE)
    {
        DeviceLayer::SystemLayer().CancelTimer(HandleScanTimer, this);
        DeviceLayer::SystemLayer().CancelTimer(HandleAdvertisingTimer, this);
        DeviceLayer::SystemLayer().CancelTimer(HandleConnectTimer, this);
    }
}

void BLEManagerImpl::NotifyChipConnectionClosed(BLE_CONNECTION_OBJECT conId)
{
    ChipLogProgress(Ble, "Got notification regarding chip connection closure");
#if CHIP_DEVICE_CONFIG_ENABLE_WPA && !CHIP_DEVICE_CONFIG_SUPPORTS_CONCURRENT_CONNECTION
    if (mState == kState_NotInitialized)
    {
        // Close BLE GATT connections to disconnect BlueZ
        CloseConnection(conId);
        // In Non-Concurrent mode start the Wi-Fi, as BLE has been stopped
        DeviceLayer::ConnectivityMgrImpl().StartNonConcurrentWiFiManagement();
    }
#endif // CHIP_DEVICE_CONFIG_SUPPORTS_CONCURRENT_CONNECTION
}

void BLEManagerImpl::CheckNonConcurrentBleClosing()
{
#if CHIP_DEVICE_CONFIG_ENABLE_WPA && !CHIP_DEVICE_CONFIG_SUPPORTS_CONCURRENT_CONNECTION
    if (mState == kState_Disconnecting)
    {
        DeviceLayer::DeviceControlServer::DeviceControlSvr().PostCloseAllBLEConnectionsToOperationalNetworkEvent();
    }
#endif
}

BluezAdvertisement::AdvertisingIntervals BLEManagerImpl::GetAdvertisingIntervals() const
{
    if (mFlags.Has(Flags::kFastAdvertisingEnabled))
        return { CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_INTERVAL_MIN, CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_INTERVAL_MAX };
#if CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING
    if (mFlags.Has(Flags::kExtAdvertisingEnabled))
        return { CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING_INTERVAL_MIN, CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING_INTERVAL_MAX };
#endif
    return { CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MIN, CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MAX };
}

void BLEManagerImpl::HandleAdvertisingTimer(chip::System::Layer *, void * appState)
{
    auto * self = static_cast<BLEManagerImpl *>(appState);

    if (self->mFlags.Has(Flags::kFastAdvertisingEnabled))
    {
        ChipLogDetail(DeviceLayer, "bleAdv Timeout : Start slow advertisement");
        self->_SetAdvertisingMode(BLEAdvertisingMode::kSlowAdvertising);
#if CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING
        self->mFlags.Clear(Flags::kExtAdvertisingEnabled);
        DeviceLayer::SystemLayer().StartTimer(kSlowAdvertiseTimeout, HandleAdvertisingTimer, self);
    }
    else
    {
        ChipLogDetail(DeviceLayer, "bleAdv Timeout : Start extended advertisement");
        self->mFlags.Set(Flags::kExtAdvertisingEnabled);
        // This will trigger advertising intervals update in the DriveBLEState() function.
        self->_SetAdvertisingMode(BLEAdvertisingMode::kSlowAdvertising);
#endif
    }
}

void BLEManagerImpl::InitiateScan(BleScanState scanType)
{
    CHIP_ERROR err = CHIP_ERROR_INCORRECT_STATE;

    DriveBLEState();

    VerifyOrExit(scanType != BleScanState::kNotScanning,
                 ChipLogError(Ble, "Invalid scan type requested: %d", to_underlying(scanType)));
    VerifyOrExit(!mDeviceScanner.IsScanning(), ChipLogError(Ble, "BLE scan already in progress"));
    VerifyOrExit(mFlags.Has(Flags::kBluezAdapterAvailable), err = BLE_ERROR_ADAPTER_UNAVAILABLE);

    mBLEScanConfig.mBleScanState = scanType;

    err = mDeviceScanner.Init(mAdapter.get(), this);
    VerifyOrExit(err == CHIP_NO_ERROR, {
        mBLEScanConfig.mBleScanState = BleScanState::kNotScanning;
        ChipLogError(Ble, "Failed to create BLE device scanner: %" CHIP_ERROR_FORMAT, err.Format());
    });

    err = mDeviceScanner.StartScan();
    VerifyOrExit(err == CHIP_NO_ERROR, {
        mBLEScanConfig.mBleScanState = BleScanState::kNotScanning;
        ChipLogError(Ble, "Failed to start BLE scan: %" CHIP_ERROR_FORMAT, err.Format());
    });

    err = DeviceLayer::SystemLayer().StartTimer(kNewConnectionScanTimeout, HandleScanTimer, this);
    VerifyOrExit(err == CHIP_NO_ERROR, {
        mBLEScanConfig.mBleScanState = BleScanState::kNotScanning;
        mDeviceScanner.StopScan();
        ChipLogError(Ble, "Failed to start BLE scan timeout: %" CHIP_ERROR_FORMAT, err.Format());
    });

exit:
    if (err != CHIP_NO_ERROR)
    {
        BleConnectionDelegate::OnConnectionError(mBLEScanConfig.mAppState, err);
    }
}

void BLEManagerImpl::HandleScanTimer(chip::System::Layer *, void * appState)
{
    auto * manager = static_cast<BLEManagerImpl *>(appState);
    manager->OnScanError(CHIP_ERROR_TIMEOUT);
    manager->mDeviceScanner.StopScan();
}

void BLEManagerImpl::CleanScanConfig()
{
    if (mBLEScanConfig.mBleScanState == BleScanState::kConnecting)
        DeviceLayer::SystemLayer().CancelTimer(HandleConnectTimer, this);

    mBLEScanConfig.mBleScanState = BleScanState::kNotScanning;
}

void BLEManagerImpl::NewConnection(BleLayer * bleLayer, void * appState, const SetupDiscriminator & connDiscriminator)
{
    mBLEScanConfig.mDiscriminator = connDiscriminator;
    mBLEScanConfig.mAppState      = appState;

    // Scan initiation performed async, to ensure that the BLE subsystem is initialized.
    DeviceLayer::SystemLayer().ScheduleLambda([this] { InitiateScan(BleScanState::kScanForDiscriminator); });
}

CHIP_ERROR BLEManagerImpl::CancelConnection()
{
    if (mBLEScanConfig.mBleScanState == BleScanState::kConnecting)
        mEndpoint.CancelConnect();
    // If in discovery mode, stop scan.
    else if (mBLEScanConfig.mBleScanState != BleScanState::kNotScanning)
    {
        DeviceLayer::SystemLayer().CancelTimer(HandleScanTimer, this);
        mDeviceScanner.StopScan();
    }
    return CHIP_NO_ERROR;
}

void BLEManagerImpl::NotifyBLEAdapterAdded(unsigned int aAdapterId, const char * aAdapterAddress)
{
    ChipDeviceEvent event;
    event.Type                           = DeviceEventType::kPlatformLinuxBLEAdapterAdded;
    event.Platform.BLEAdapter.mAdapterId = aAdapterId;
    Platform::CopyString(event.Platform.BLEAdapter.mAdapterAddress, aAdapterAddress);
    PlatformMgr().PostEventOrDie(&event);
}

void BLEManagerImpl::NotifyBLEAdapterRemoved(unsigned int aAdapterId, const char * aAdapterAddress)
{
    ChipDeviceEvent event;
    event.Type                           = DeviceEventType::kPlatformLinuxBLEAdapterRemoved;
    event.Platform.BLEAdapter.mAdapterId = aAdapterId;
    Platform::CopyString(event.Platform.BLEAdapter.mAdapterAddress, aAdapterAddress);
    PlatformMgr().PostEventOrDie(&event);
}

void BLEManagerImpl::NotifyBLEPeripheralRegisterAppComplete(CHIP_ERROR error)
{
    ChipDeviceEvent event;
    event.Type                                             = DeviceEventType::kPlatformLinuxBLEPeripheralRegisterAppComplete;
    event.Platform.BLEPeripheralRegisterAppComplete.mError = error;
    PlatformMgr().PostEventOrDie(&event);
}

void BLEManagerImpl::NotifyBLEPeripheralAdvStartComplete(CHIP_ERROR error)
{
    ChipDeviceEvent event;
    event.Type                                          = DeviceEventType::kPlatformLinuxBLEPeripheralAdvStartComplete;
    event.Platform.BLEPeripheralAdvStartComplete.mError = error;
    PlatformMgr().PostEventOrDie(&event);
}

void BLEManagerImpl::NotifyBLEPeripheralAdvStopComplete(CHIP_ERROR error)
{
    ChipDeviceEvent event;
    event.Type                                         = DeviceEventType::kPlatformLinuxBLEPeripheralAdvStopComplete;
    event.Platform.BLEPeripheralAdvStopComplete.mError = error;
    PlatformMgr().PostEventOrDie(&event);
}

void BLEManagerImpl::NotifyBLEPeripheralAdvReleased()
{
    ChipDeviceEvent event;
    event.Type = DeviceEventType::kPlatformLinuxBLEPeripheralAdvReleased;
    PlatformMgr().PostEventOrDie(&event);
}

void BLEManagerImpl::OnDeviceScanned(BluezDevice1 & device, const chip::Ble::ChipBLEDeviceIdentificationInfo & info)
{
    const char * address = bluez_device1_get_address(&device);
    ChipLogProgress(Ble, "New device scanned: %s", address);

    if (mBLEScanConfig.mBleScanState == BleScanState::kScanForDiscriminator)
    {
        auto isMatch = mBLEScanConfig.mDiscriminator.MatchesLongDiscriminator(info.GetDeviceDiscriminator());
        VerifyOrReturn(
            isMatch,
            ChipLogError(Ble, "Skip connection: Device discriminator does not match: %u != %u", info.GetDeviceDiscriminator(),
                         mBLEScanConfig.mDiscriminator.IsShortDiscriminator() ? mBLEScanConfig.mDiscriminator.GetShortValue()
                                                                              : mBLEScanConfig.mDiscriminator.GetLongValue()));
        ChipLogProgress(Ble, "Device discriminator match. Attempting to connect.");
    }
    else if (mBLEScanConfig.mBleScanState == BleScanState::kScanForAddress)
    {
        auto isMatch = strcmp(address, mBLEScanConfig.mAddress.c_str()) == 0;
        VerifyOrReturn(isMatch,
                       ChipLogError(Ble, "Skip connection: Device address does not match: %s != %s", address,
                                    mBLEScanConfig.mAddress.c_str()));
        ChipLogProgress(Ble, "Device address match. Attempting to connect.");
    }
    else
    {
        // Internal consistency error
        ChipLogError(Ble, "Unknown discovery type. Ignoring scanned device.");
        return;
    }

    mBLEScanConfig.mBleScanState = BleScanState::kConnecting;

    chip::DeviceLayer::PlatformMgr().LockChipStack();
    // We StartScan in the ChipStack thread.
    // StopScan should also be performed in the ChipStack thread.
    // At the same time, the scan timer also needs to be canceled in the ChipStack thread.
    DeviceLayer::SystemLayer().CancelTimer(HandleScanTimer, this);
    mDeviceScanner.StopScan();
    // Stop scanning and then start connecting timer
    DeviceLayer::SystemLayer().StartTimer(kConnectTimeout, HandleConnectTimer, this);
    chip::DeviceLayer::PlatformMgr().UnlockChipStack();

    CHIP_ERROR err = mEndpoint.ConnectDevice(device);
    VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Ble, "Device connection failed: %" CHIP_ERROR_FORMAT, err.Format()));

    ChipLogProgress(Ble, "New device connected: %s", address);
}

void BLEManagerImpl::HandleConnectTimer(chip::System::Layer *, void * appState)
{
    auto * manager = static_cast<BLEManagerImpl *>(appState);
    manager->mEndpoint.CancelConnect();
    BLEManagerImpl::HandleConnectFailed(CHIP_ERROR_TIMEOUT);
}

void BLEManagerImpl::OnScanComplete()
{
    switch (mBLEScanConfig.mBleScanState)
    {
    case BleScanState::kNotScanning:
        ChipLogProgress(Ble, "Scan complete notification without an active scan.");
        break;
    case BleScanState::kScanForAddress:
    case BleScanState::kScanForDiscriminator:
        mBLEScanConfig.mBleScanState = BleScanState::kNotScanning;
        ChipLogProgress(Ble, "Scan complete. No matching device found.");
        break;
    case BleScanState::kConnecting:
        break;
    }
}

void BLEManagerImpl::OnScanError(CHIP_ERROR err)
{
    BleConnectionDelegate::OnConnectionError(mBLEScanConfig.mAppState, err);
    ChipLogError(Ble, "BLE scan error: %" CHIP_ERROR_FORMAT, err.Format());
}

} // namespace Internal
} // namespace DeviceLayer
} // namespace chip
