/*
 *
 *    Copyright (c) 2020-2021 Project CHIP Authors
 *
 *    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 mbed platforms.
 */

#include <inttypes.h>
#include <stdint.h>

#include <platform/internal/CHIPDeviceLayerInternal.h>

#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE

#include <platform/mbed/BLEManagerImpl.h>

#include <ble/CHIPBleServiceData.h>
#include <lib/support/CodeUtils.h>
#include <lib/support/logging/CHIPLogging.h>
#include <platform/CommissionableDataProvider.h>
#include <platform/internal/BLEManager.h>

// Show BLE status with LEDs
#define _BLEMGRIMPL_USE_LEDS 0

// mbed-os headers
#include "ble/BLE.h"
#include "ble/Gap.h"
#include "platform/Callback.h"
#include "platform/NonCopyable.h"
#include "platform/Span.h"

#if _BLEMGRIMPL_USE_LEDS
#include "drivers/DigitalOut.h"
#endif

using namespace ::chip;
using namespace ::chip::Ble;
using namespace ::chip::System;

namespace chip {
namespace DeviceLayer {
namespace Internal {

namespace {
const UUID ShortUUID_CHIPoBLEService(0xFFF6);
// RX = BleLayer::CHIP_BLE_CHAR_1_ID
const UUID LongUUID_CHIPoBLEChar_RX("18EE2EF5-263D-4559-959F-4F9C429F9D11");
const ChipBleUUID ChipUUID_CHIPoBLEChar_RX = { { 0x18, 0xEE, 0x2E, 0xF5, 0x26, 0x3D, 0x45, 0x59, 0x95, 0x9F, 0x4F, 0x9C, 0x42, 0x9F,
                                                 0x9D, 0x11 } };
// TX = BleLayer::CHIP_BLE_CHAR_2_ID
const UUID LongUUID_CHIPoBLEChar_TX("18EE2EF5-263D-4559-959F-4F9C429F9D12");
const ChipBleUUID ChipUUID_CHIPoBLEChar_TX = { { 0x18, 0xEE, 0x2E, 0xF5, 0x26, 0x3D, 0x45, 0x59, 0x95, 0x9F, 0x4F, 0x9C, 0x42, 0x9F,
                                                 0x9D, 0x12 } };
} // namespace

#if _BLEMGRIMPL_USE_LEDS
#include "drivers/DigitalOut.h"
// LED1 -- toggle on every call to ble::BLE::processEvents()
// LED2 -- on when ble::BLE::init() callback completes
// LED3 -- on when advertising
mbed::DigitalOut led1(LED1, 1);
mbed::DigitalOut led2(LED2, 1);
mbed::DigitalOut led3(LED3, 1);
#endif

class ConnectionInfo
{
public:
    struct ConnStatus
    {
        ble::connection_handle_t connHandle;
        uint16_t attMtuSize;
    };

    ConnectionInfo()
    {
        for (size_t i = 0; i < kMaxConnections; i++)
        {
            mConnStates[i].connHandle = kInvalidHandle;
            mConnStates[i].attMtuSize = 0;
        }
    }

    CHIP_ERROR setStatus(ble::connection_handle_t conn_handle, uint16_t mtu_size)
    {
        size_t new_i = kMaxConnections;
        for (size_t i = 0; i < kMaxConnections; i++)
        {
            if (mConnStates[i].connHandle == conn_handle)
            {
                mConnStates[i].attMtuSize = mtu_size;
                return CHIP_NO_ERROR;
            }
            else if (mConnStates[i].connHandle == kInvalidHandle && i < new_i)
            {
                new_i = i;
            }
        }
        // Handle not found, has to be added.
        if (new_i == kMaxConnections)
        {
            return CHIP_ERROR_NO_MEMORY;
        }
        mConnStates[new_i].connHandle = conn_handle;
        mConnStates[new_i].attMtuSize = mtu_size;
        return CHIP_NO_ERROR;
    }

    CHIP_ERROR clearStatus(ble::connection_handle_t conn_handle)
    {
        for (size_t i = 0; i < kMaxConnections; i++)
        {
            if (mConnStates[i].connHandle == conn_handle)
            {
                mConnStates[i].connHandle = kInvalidHandle;
                mConnStates[i].attMtuSize = 0;
                return CHIP_NO_ERROR;
            }
        }
        return CHIP_ERROR_INVALID_ARGUMENT;
    }

    ConnStatus getStatus(ble::connection_handle_t conn_handle) const
    {
        for (size_t i = 0; i < kMaxConnections; i++)
        {
            if (mConnStates[i].connHandle == conn_handle)
            {
                return mConnStates[i];
            }
        }
        return { kInvalidHandle, 0 };
    }

    uint16_t getMTU(ble::connection_handle_t conn_handle) const { return getStatus(conn_handle).attMtuSize; }

private:
    const size_t kMaxConnections = BLE_LAYER_NUM_BLE_ENDPOINTS;
    ConnStatus mConnStates[BLE_LAYER_NUM_BLE_ENDPOINTS];
    const ble::connection_handle_t kInvalidHandle = 0xf00d;
};

static ConnectionInfo sConnectionInfo;

#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
class GapEventHandler : private mbed::NonCopyable<GapEventHandler>, public ble::Gap::EventHandler
{
    void onScanRequestReceived(const ble::ScanRequestEvent & event)
    {
        // Requires enable action from setScanRequestNotification(true).
        ChipLogDetail(DeviceLayer, "GAP %s", __FUNCTION__);
    }

    /* Called when advertising starts.
     */
    void onAdvertisingStart(const ble::AdvertisingStartEvent & event)
    {
#if _BLEMGRIMPL_USE_LEDS
        led3 = 0;
#endif
        ChipLogDetail(DeviceLayer, "GAP %s", __FUNCTION__);

        BLEManagerImpl & ble_manager = BLEMgrImpl();
        ble_manager.mFlags.Set(ble_manager.kFlag_Advertising);
        ble_manager.mFlags.Clear(ble_manager.kFlag_AdvertisingRefreshNeeded);

        // Post a CHIPoBLEAdvertisingChange(Started) event.
        ChipDeviceEvent chip_event;
        chip_event.Type                             = DeviceEventType::kCHIPoBLEAdvertisingChange;
        chip_event.CHIPoBLEAdvertisingChange.Result = kActivity_Started;
        PlatformMgrImpl().PostEventOrDie(&chip_event);

        PlatformMgr().ScheduleWork(ble_manager.DriveBLEState, 0);
    }

    /* Called when advertising ends.
     *
     * Advertising ends when the process timeout or if it is stopped by the
     * application or if the local device accepts a connection request.
     */
    void onAdvertisingEnd(const ble::AdvertisingEndEvent & event)
    {
#if _BLEMGRIMPL_USE_LEDS
        led3 = 1;
#endif
        ChipLogDetail(DeviceLayer, "GAP %s", __FUNCTION__);

        BLEManagerImpl & ble_manager = BLEMgrImpl();
        ble_manager.mFlags.Clear(ble_manager.kFlag_Advertising);

        // Post a CHIPoBLEAdvertisingChange(Stopped) event.
        ChipDeviceEvent chip_event;
        chip_event.Type                             = DeviceEventType::kCHIPoBLEAdvertisingChange;
        chip_event.CHIPoBLEAdvertisingChange.Result = kActivity_Stopped;
        PlatformMgrImpl().PostEventOrDie(&chip_event);

        if (event.isConnected())
        {
            ble_manager.mFlags.Set(ble_manager.kFlag_AdvertisingRefreshNeeded);
            ChipLogDetail(DeviceLayer, "Restarting advertising to allow more connections.");
        }
        PlatformMgr().ScheduleWork(ble_manager.DriveBLEState, 0);
    }

    /* Called when connection attempt ends or an advertising device has been
     * connected.
     */
    void onConnectionComplete(const ble::ConnectionCompleteEvent & event)
    {
        ChipLogDetail(DeviceLayer, "GAP %s", __FUNCTION__);

        ble_error_t mbed_err         = event.getStatus();
        BLEManagerImpl & ble_manager = BLEMgrImpl();

        if (mbed_err == BLE_ERROR_NONE)
        {
            const ble::address_t & peer_addr = event.getPeerAddress();
            ChipLogProgress(DeviceLayer, "BLE connection established with %02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX", peer_addr[5],
                            peer_addr[4], peer_addr[3], peer_addr[2], peer_addr[1], peer_addr[0]);
            ble_manager.mGAPConns++;
            CHIP_ERROR err = sConnectionInfo.setStatus(event.getConnectionHandle(), BLE_GATT_MTU_SIZE_DEFAULT);
            if (err != CHIP_NO_ERROR)
            {
                ChipLogError(DeviceLayer, "Unable to store connection status, error: %s ", ErrorStr(err));
            }
        }
        else
        {
            ChipLogError(DeviceLayer, "BLE connection failed, mbed-os error: %d", mbed_err);
        }
        ChipLogProgress(DeviceLayer, "Current number of connections: %u/%d", ble_manager.NumConnections(),
                        ble_manager.kMaxConnections);

        // The connection established event is propagated when the client has subscribed to
        // the TX characteristic.
    }

    void onUpdateConnectionParametersRequest(const ble::UpdateConnectionParametersRequestEvent & event)
    {
        ChipLogDetail(DeviceLayer, "GAP %s", __FUNCTION__);
    }

    void onConnectionParametersUpdateComplete(const ble::ConnectionParametersUpdateCompleteEvent & event)
    {
        ChipLogDetail(DeviceLayer, "GAP %s", __FUNCTION__);
    }

    void onReadPhy(ble_error_t status, ble::connection_handle_t connectionHandle, ble::phy_t txPhy, ble::phy_t rxPhy)
    {
        ChipLogDetail(DeviceLayer, "GAP %s", __FUNCTION__);
    }

    void onPhyUpdateComplete(ble_error_t status, ble::connection_handle_t connectionHandle, ble::phy_t txPhy, ble::phy_t rxPhy)
    {
        ChipLogDetail(DeviceLayer, "GAP %s", __FUNCTION__);
    }

    /* Called when a connection has been disconnected.
     */
    void onDisconnectionComplete(const ble::DisconnectionCompleteEvent & event)
    {
        ChipLogDetail(DeviceLayer, "GAP %s", __FUNCTION__);

        const ble::disconnection_reason_t & reason = event.getReason();
        BLEManagerImpl & ble_manager               = BLEMgrImpl();

        if (ble_manager.NumConnections())
        {
            ble_manager.mGAPConns--;
        }
        CHIP_ERROR err = sConnectionInfo.clearStatus(event.getConnectionHandle());
        if (err != CHIP_NO_ERROR)
        {
            ChipLogError(DeviceLayer, "Unable to clear connection status, error: %s ", ErrorStr(err));
        }

        ChipDeviceEvent chip_event;
        chip_event.Type                          = DeviceEventType::kCHIPoBLEConnectionError;
        chip_event.CHIPoBLEConnectionError.ConId = event.getConnectionHandle();
        switch (reason.value())
        {
        case ble::disconnection_reason_t::REMOTE_USER_TERMINATED_CONNECTION:
            chip_event.CHIPoBLEConnectionError.Reason = BLE_ERROR_REMOTE_DEVICE_DISCONNECTED;
            break;
        case ble::disconnection_reason_t::LOCAL_HOST_TERMINATED_CONNECTION:
            chip_event.CHIPoBLEConnectionError.Reason = BLE_ERROR_APP_CLOSED_CONNECTION;
            break;
        default:
            chip_event.CHIPoBLEConnectionError.Reason = BLE_ERROR_CHIPOBLE_PROTOCOL_ABORT;
            break;
        }
        PlatformMgrImpl().PostEventOrDie(&chip_event);

        ChipLogProgress(DeviceLayer, "BLE connection terminated, mbed-os reason: %d", reason.value());
        ChipLogProgress(DeviceLayer, "Current number of connections: %u/%d", ble_manager.NumConnections(),
                        ble_manager.kMaxConnections);

        // Force a reconfiguration of advertising in case we switched to non-connectable mode when
        // the BLE connection was established.
        ble_manager.mFlags.Set(ble_manager.kFlag_AdvertisingRefreshNeeded);
        PlatformMgr().ScheduleWork(ble_manager.DriveBLEState, 0);
    }

    void onDataLengthChange(ble::connection_handle_t connectionHandle, uint16_t txSize, uint16_t rxSize)
    {
        ChipLogDetail(DeviceLayer, "GAP %s", __FUNCTION__);
    }

    void onPrivacyEnabled() { ChipLogDetail(DeviceLayer, "GAP %s", __FUNCTION__); }
};

#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
struct CHIPService : public ble::GattServer::EventHandler
{
    CHIPService() {}
    CHIPService(const CHIPService &) = delete;
    CHIPService & operator=(const CHIPService &) = delete;

    CHIP_ERROR init(ble::BLE & ble_interface)
    {
        ChipLogDetail(DeviceLayer, "GATT %s", __FUNCTION__);

        if (mCHIPoBLEChar_RX != nullptr || mCHIPoBLEChar_TX != nullptr)
        {
            return CHIP_NO_ERROR;
        }

        mCHIPoBLEChar_RX = new GattCharacteristic(LongUUID_CHIPoBLEChar_RX, nullptr, 0, BLE_GATT_MTU_SIZE_DEFAULT,
                                                  GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE |
                                                      GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE);

        mCHIPoBLEChar_TX = new GattCharacteristic(LongUUID_CHIPoBLEChar_TX, nullptr, 0, BLE_GATT_MTU_SIZE_DEFAULT,
                                                  GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);

        // Setup callback
        mCHIPoBLEChar_RX->setWriteAuthorizationCallback(this, &CHIPService::onWriteAuth);

        GattCharacteristic * chipoble_gatt_characteristics[] = { mCHIPoBLEChar_RX, mCHIPoBLEChar_TX };
        auto num_characteristics = sizeof chipoble_gatt_characteristics / sizeof chipoble_gatt_characteristics[0];
        GattService chipoble_gatt_service(ShortUUID_CHIPoBLEService, chipoble_gatt_characteristics, num_characteristics);

        auto mbed_err = ble_interface.gattServer().addService(chipoble_gatt_service);
        if (mbed_err != BLE_ERROR_NONE)
        {
            ChipLogError(DeviceLayer, "Unable to add GATT service, mbed-os err: %d", mbed_err);
            return CHIP_ERROR_INTERNAL;
        }

        // Store the attribute handles in the class so they are reused in
        // callbacks to discriminate events.
        mRxHandle = mCHIPoBLEChar_RX->getValueHandle();
        mTxHandle = mCHIPoBLEChar_TX->getValueHandle();
        // There is a single descriptor in the characteristic, CCCD is at index 0
        mTxCCCDHandle = mCHIPoBLEChar_TX->getDescriptor(0)->getHandle();
        ChipLogDetail(DeviceLayer, "char handles: rx=%d, tx=%d, cccd=%d", mRxHandle, mTxHandle, mTxCCCDHandle);

        ble_interface.gattServer().setEventHandler(this);
        return CHIP_NO_ERROR;
    }

    // Write authorization callback
    void onWriteAuth(GattWriteAuthCallbackParams * params)
    {
        ChipLogDetail(DeviceLayer, "GATT %s, connHandle=%d, attHandle=%d", __FUNCTION__, params->connHandle, params->handle);
        if (params->handle == mRxHandle)
        {
            ChipLogDetail(DeviceLayer, "Received BLE packet on RX");

            // Allocate a buffer, copy the data. They will be passed into the event
            auto buf = System::PacketBufferHandle::NewWithData(params->data, params->len);
            if (buf.IsNull())
            {
                params->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_WRITE_REQUEST_REJECTED;
                ChipLogError(DeviceLayer, "Dropping packet, not enough memory");
                return;
            }

            params->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;

            ChipDeviceEvent chip_event;
            chip_event.Type                        = DeviceEventType::kCHIPoBLEWriteReceived;
            chip_event.CHIPoBLEWriteReceived.ConId = params->connHandle;
            chip_event.CHIPoBLEWriteReceived.Data  = std::move(buf).UnsafeRelease();
            PlatformMgrImpl().PostEventOrDie(&chip_event);
        }
        else
        {
            params->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_HANDLE;
        }
    }

    // overrides of GattServerEvent Handler
    void onAttMtuChange(ble::connection_handle_t connectionHandle, uint16_t attMtuSize) override
    {
        ChipLogDetail(DeviceLayer, "GATT %s", __FUNCTION__);
        CHIP_ERROR err = sConnectionInfo.setStatus(connectionHandle, attMtuSize);
        if (err != CHIP_NO_ERROR)
        {
            ChipLogError(DeviceLayer, "Unable to store connection status, error: %s ", ErrorStr(err));
        }
    }

    void onDataSent(const GattDataSentCallbackParams & params) override
    {
        ChipLogDetail(DeviceLayer, "GATT %s, connHandle=%d, attHandle=%d", __FUNCTION__, params.connHandle, params.attHandle);

        // Note: This is applicable to both notification and indication: If a
        // notification is sent then onDataSent is called as soon as the data
        // has been pushed into the Bluetooth controller. For indication, onDataSent
        // is called when the confirmation has been received.
        onConfirmationReceived(params);
    }

    void onDataWritten(const GattWriteCallbackParams & params) override
    {
        ChipLogDetail(DeviceLayer, "GATT %s, connHandle=%d, attHandle=%d", __FUNCTION__, params.connHandle, params.handle);
    }

    void onDataRead(const GattReadCallbackParams & params) override
    {
        ChipLogDetail(DeviceLayer, "GATT %s, connHandle=%d, attHandle=%d", __FUNCTION__, params.connHandle, params.handle);
    }

    void onShutdown(const ble::GattServer & server) override { ChipLogDetail(DeviceLayer, "GATT %s", __FUNCTION__); }

    void onUpdatesEnabled(const GattUpdatesEnabledCallbackParams & params) override
    {
        ChipLogDetail(DeviceLayer, "GATT %s, connHandle=%d, attHandle=%d", __FUNCTION__, params.connHandle, params.attHandle);
        if (params.attHandle == mTxCCCDHandle)
        {
            ChipLogDetail(DeviceLayer, "Updates enabled on TX CCCD");
            ChipDeviceEvent chip_event;
            chip_event.Type                    = DeviceEventType::kCHIPoBLESubscribe;
            chip_event.CHIPoBLESubscribe.ConId = params.connHandle;
            PlatformMgrImpl().PostEventOrDie(&chip_event);
        }
    }

    void onUpdatesDisabled(const GattUpdatesDisabledCallbackParams & params) override
    {
        ChipLogDetail(DeviceLayer, "GATT %s, connHandle=%d, attHandle=%d", __FUNCTION__, params.connHandle, params.attHandle);
        if (params.attHandle == mTxCCCDHandle)
        {
            ChipLogDetail(DeviceLayer, "Updates disabled on TX CCCD");
            ChipDeviceEvent chip_event;
            chip_event.Type                      = DeviceEventType::kCHIPoBLEUnsubscribe;
            chip_event.CHIPoBLEUnsubscribe.ConId = params.connHandle;
            PlatformMgrImpl().PostEventOrDie(&chip_event);
        }
    }

    void onConfirmationReceived(const GattConfirmationReceivedCallbackParams & params) override
    {
        ChipLogDetail(DeviceLayer, "GATT %s, connHandle=%d, attHandle=%d", __FUNCTION__, params.connHandle, params.attHandle);
        if (params.attHandle == mTxHandle)
        {
            ChipLogDetail(DeviceLayer, "Confirmation received for TX transfer");
            ChipDeviceEvent chip_event;
            chip_event.Type                          = DeviceEventType::kCHIPoBLEIndicateConfirm;
            chip_event.CHIPoBLEIndicateConfirm.ConId = params.connHandle;
            PlatformMgrImpl().PostEventOrDie(&chip_event);
        }
    }

    ble::attribute_handle_t getTxHandle() const { return mTxHandle; }
    ble::attribute_handle_t getTxCCCDHandle() const { return mTxCCCDHandle; }
    ble::attribute_handle_t getRxHandle() const { return mRxHandle; }

    GattCharacteristic * mCHIPoBLEChar_RX = nullptr;
    GattCharacteristic * mCHIPoBLEChar_TX = nullptr;
    ble::attribute_handle_t mRxHandle     = 0;
    ble::attribute_handle_t mTxCCCDHandle = 0;
    ble::attribute_handle_t mTxHandle     = 0;
};

#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
class SecurityManagerEventHandler : private mbed::NonCopyable<SecurityManagerEventHandler>,
                                    public ble::SecurityManager::EventHandler
{
    void pairingRequest(ble::connection_handle_t connectionHandle) override
    {
        ChipLogDetail(DeviceLayer, "SM %s, connHandle=%d", __FUNCTION__, connectionHandle);
        ble::SecurityManager & security_mgr = ble::BLE::Instance().securityManager();

        auto mbed_err = security_mgr.acceptPairingRequest(connectionHandle);
        if (mbed_err == BLE_ERROR_NONE)
        {
            ChipLogProgress(DeviceLayer, "Pairing request authorized.");
        }
        else
        {
            ChipLogError(DeviceLayer, "Pairing request not authorized, mbed-os err: %d", mbed_err);
        }
    }

    void pairingResult(ble::connection_handle_t connectionHandle, SecurityManager::SecurityCompletionStatus_t result) override
    {
        ChipLogDetail(DeviceLayer, "SM %s, connHandle=%d", __FUNCTION__, connectionHandle);
        if (result == SecurityManager::SEC_STATUS_SUCCESS)
        {
            ChipLogProgress(DeviceLayer, "Pairing successful.");
        }
        else
        {
            ChipLogError(DeviceLayer, "Pairing failed, status: 0x%X.", result);
        }
    }

    void linkEncryptionResult(ble::connection_handle_t connectionHandle, ble::link_encryption_t result) override
    {
        ChipLogDetail(DeviceLayer, "SM %s, connHandle=%d", __FUNCTION__, connectionHandle);
        if (result == ble::link_encryption_t::NOT_ENCRYPTED)
        {
            ChipLogDetail(DeviceLayer, "Link NOT_ENCRYPTED.");
        }
        else if (result == ble::link_encryption_t::ENCRYPTION_IN_PROGRESS)
        {
            ChipLogDetail(DeviceLayer, "Link ENCRYPTION_IN_PROGRESS.");
        }
        else if (result == ble::link_encryption_t::ENCRYPTED)
        {
            ChipLogDetail(DeviceLayer, "Link ENCRYPTED.");
        }
        else if (result == ble::link_encryption_t::ENCRYPTED_WITH_MITM)
        {
            ChipLogDetail(DeviceLayer, "Link ENCRYPTED_WITH_MITM.");
        }
        else if (result == ble::link_encryption_t::ENCRYPTED_WITH_SC_AND_MITM)
        {
            ChipLogDetail(DeviceLayer, "Link ENCRYPTED_WITH_SC_AND_MITM.");
        }
        else
        {
            ChipLogDetail(DeviceLayer, "Link encryption status UNKNOWN.");
        }
    }
};

BLEManagerImpl BLEManagerImpl::sInstance;
static GapEventHandler sMbedGapEventHandler;
static CHIPService sCHIPService;
static SecurityManagerEventHandler sSecurityManagerEventHandler;

/* Initialize the mbed-os BLE subsystem. Register the BLE event processing
 * callback to the system event queue. Register the BLE initialization complete
 * callback that handles the rest of the setup commands. Register the BLE GAP
 * event handler.
 */
CHIP_ERROR BLEManagerImpl::_Init()
{
    ble_error_t mbed_err = BLE_ERROR_NONE;

    mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Enabled;
    mFlags       = BitFlags<Flags>(CHIP_DEVICE_CONFIG_CHIPOBLE_ENABLE_ADVERTISING_AUTOSTART ? kFlag_AdvertisingEnabled : 0);
    mGAPConns    = 0;

    if (!mInitialized)
    {
        ble::BLE & ble_interface = ble::BLE::Instance();

        ble_interface.gap().setEventHandler(&sMbedGapEventHandler);
        ReturnErrorOnFailure(sCHIPService.init(ble_interface));

        ble_interface.onEventsToProcess(FunctionPointerWithContext<ble::BLE::OnEventsToProcessCallbackContext *>{
            [](ble::BLE::OnEventsToProcessCallbackContext * context) { PlatformMgr().ScheduleWork(DoBLEProcessing, 0); } });

        mbed_err = ble_interface.init([](ble::BLE::InitializationCompleteCallbackContext * context) {
            BLEMgrImpl().HandleInitComplete(context->error == BLE_ERROR_NONE);
        });
        VerifyOrReturnError(mbed_err == BLE_ERROR_NONE, CHIP_ERROR(chip::ChipError::Range::kOS, mbed_err));
        mInitialized = true;
    }

    return CHIP_NO_ERROR;
}

/* Process all the events from the mbed-os BLE subsystem.
 */
void BLEManagerImpl::DoBLEProcessing(intptr_t arg)
{
#if _BLEMGRIMPL_USE_LEDS
    led1 = !led1;
#endif
    ble::BLE::Instance().processEvents();
}

/* This is the mbed-os BLE subsystem init complete callback. Initialize the
 * BLELayer and update the state based on the flags.
 */
void BLEManagerImpl::HandleInitComplete(bool no_error)
{
    CHIP_ERROR err       = CHIP_NO_ERROR;
    ble_error_t mbed_err = BLE_ERROR_NONE;

    ble::Gap & gap                      = ble::BLE::Instance().gap();
    ble::SecurityManager & security_mgr = ble::BLE::Instance().securityManager();
    ble::own_address_type_t addr_type;
    ble::address_t addr;

    VerifyOrExit(no_error, err = CHIP_ERROR_INTERNAL);

    gap.getAddress(addr_type, addr);
    ChipLogDetail(DeviceLayer, "Device address: %02X:%02X:%02X:%02X:%02X:%02X", addr[5], addr[4], addr[3], addr[2], addr[1],
                  addr[0]);

    mbed_err = security_mgr.init(
        /*bool enableBonding             */ false,
        /*bool requireMITM               */ true,
        /*SecurityIOCapabilities_t iocaps*/ SecurityManager::IO_CAPS_NONE,
        /*const Passkey_t passkey        */ nullptr,
        /*bool signing                   */ true,
        /*const char *dbFilepath         */ nullptr);
    VerifyOrExit(mbed_err == BLE_ERROR_NONE, err = CHIP_ERROR(chip::ChipError::Range::kOS, mbed_err));

    mbed_err = security_mgr.setPairingRequestAuthorisation(true);
    VerifyOrExit(mbed_err == BLE_ERROR_NONE, err = CHIP_ERROR(chip::ChipError::Range::kOS, mbed_err));
    security_mgr.setSecurityManagerEventHandler(&sSecurityManagerEventHandler);

    err = BleLayer::Init(this, this, &DeviceLayer::SystemLayer());
    SuccessOrExit(err);
    PlatformMgr().ScheduleWork(DriveBLEState, 0);
#if _BLEMGRIMPL_USE_LEDS
    led2 = 0;
#endif

exit:
    if (err != CHIP_NO_ERROR)
    {
        ChipLogError(DeviceLayer, "BLEManager init error: %s ", ErrorStr(err));
        ChipLogError(DeviceLayer, "Disabling CHIPoBLE service.");
        mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Disabled;
        mInitialized = false;
        PlatformMgr().ScheduleWork(DriveBLEState, 0);
    }
}

void BLEManagerImpl::DriveBLEState(intptr_t arg)
{
    BLEMgrImpl().DriveBLEState();
}

/* Update the advertising state based on the flags.
 */
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(kFlag_AsyncInitCompleted))
    {
        mFlags.Set(kFlag_AsyncInitCompleted);
    }

    // If the application has enabled CHIPoBLE and BLE advertising...
    if (mServiceMode == ConnectivityManager::kCHIPoBLEServiceMode_Enabled &&
        mFlags.Has(kFlag_AdvertisingEnabled)
#if CHIP_DEVICE_CONFIG_CHIPOBLE_SINGLE_CONNECTION
        // and no connections are active...
        && (_NumConnections() == 0)
#endif
    )
    {
        // Start/re-start advertising if not already advertising, or if the
        // advertising state needs to be refreshed.
        if (!mFlags.Has(kFlag_Advertising) || mFlags.Has(kFlag_AdvertisingRefreshNeeded))
        {
            err = StartAdvertising();
            SuccessOrExit(err);
        }
    }
    // Otherwise, stop advertising if currently active.
    else
    {
        err = StopAdvertising();
        SuccessOrExit(err);
    }

exit:
    if (err != CHIP_NO_ERROR)
    {
        ChipLogError(DeviceLayer, "Disabling CHIPoBLE service due to error: %s", ErrorStr(err));
        mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Disabled;
    }
}

CHIP_ERROR BLEManagerImpl::_SetAdvertisingMode(BLEAdvertisingMode mode)
{
    switch (mode)
    {
    case BLEAdvertisingMode::kFastAdvertising:
        mFlags.Set(Flags::kFlag_FastAdvertisingEnabled, true);
        break;
    case BLEAdvertisingMode::kSlowAdvertising:
        mFlags.Set(Flags::kFlag_AdvertisingEnabled, false);
        break;
    default:
        return CHIP_ERROR_INVALID_ARGUMENT;
    }
    mFlags.Set(Flags::kFlag_AdvertisingRefreshNeeded);
    PlatformMgr().ScheduleWork(DriveBLEState, 0);
    return CHIP_NO_ERROR;
}

/* Build the advertising data and start advertising.
 */
CHIP_ERROR BLEManagerImpl::StartAdvertising(void)
{
    CHIP_ERROR err       = CHIP_NO_ERROR;
    ble_error_t mbed_err = BLE_ERROR_NONE;

    ble::Gap & gap = ble::BLE::Instance().gap();
    ble::AdvertisingDataBuilder adv_data_builder(mAdvertisingDataBuffer);

    ChipBLEDeviceIdentificationInfo dev_id_info;

    // Advertise CONNECTABLE if we haven't reached the maximum number of connections.
    uint16_t num_conns = _NumConnections();
    bool connectable   = (num_conns < kMaxConnections);
    ble::advertising_type_t adv_type =
        connectable ? ble::advertising_type_t::CONNECTABLE_UNDIRECTED : ble::advertising_type_t::SCANNABLE_UNDIRECTED;

    // Advertise in fast mode if not fully provisioned and there are no CHIPoBLE connections, or
    // if the application has expressly requested fast advertising.
    ble::adv_interval_t adv_interval = (num_conns == 0 && !ConfigurationMgr().IsFullyProvisioned())
        ? ble::adv_interval_t(CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_INTERVAL_MAX)
        : ble::adv_interval_t(CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MAX);
    // minInterval and maxInterval are equal for CHIP.
    ble::AdvertisingParameters adv_params(adv_type, adv_interval, adv_interval);

    // Restart advertising if already active.
    if (gap.isAdvertisingActive(ble::LEGACY_ADVERTISING_HANDLE))
    {
        mbed_err = gap.stopAdvertising(ble::LEGACY_ADVERTISING_HANDLE);
        VerifyOrExit(mbed_err == BLE_ERROR_NONE, err = CHIP_ERROR(chip::ChipError::Range::kOS, mbed_err));
        ChipLogDetail(DeviceLayer, "Advertising already active. Restarting.");
    }

    mbed_err = gap.setAdvertisingParameters(ble::LEGACY_ADVERTISING_HANDLE, adv_params);
    VerifyOrExit(mbed_err == BLE_ERROR_NONE, err = CHIP_ERROR(chip::ChipError::Range::kOS, mbed_err));

    mbed_err =
        adv_data_builder.setFlags(ble::adv_data_flags_t::BREDR_NOT_SUPPORTED | ble::adv_data_flags_t::LE_GENERAL_DISCOVERABLE);
    VerifyOrExit(mbed_err == BLE_ERROR_NONE, err = CHIP_ERROR(chip::ChipError::Range::kOS, mbed_err));

    if (!mFlags.Has(kFlag_UseCustomDeviceName))
    {
        uint16_t discriminator;
        SuccessOrExit(err = GetCommissionableDataProvider()->GetSetupDiscriminator(discriminator));
        memset(mDeviceName, 0, kMaxDeviceNameLength);
        snprintf(mDeviceName, kMaxDeviceNameLength, "%s%04u", CHIP_DEVICE_CONFIG_BLE_DEVICE_NAME_PREFIX, discriminator);
    }
    mbed_err = adv_data_builder.setName(mDeviceName);
    VerifyOrExit(mbed_err == BLE_ERROR_NONE, err = CHIP_ERROR(chip::ChipError::Range::kOS, mbed_err));

    dev_id_info.Init();
    SuccessOrExit(err = ConfigurationMgr().GetBLEDeviceIdentificationInfo(dev_id_info));
    mbed_err = adv_data_builder.setServiceData(
        ShortUUID_CHIPoBLEService, mbed::make_Span<const uint8_t>(reinterpret_cast<uint8_t *>(&dev_id_info), sizeof dev_id_info));
    VerifyOrExit(mbed_err == BLE_ERROR_NONE, err = CHIP_ERROR(chip::ChipError::Range::kOS, mbed_err));

    mbed_err = gap.setAdvertisingPayload(ble::LEGACY_ADVERTISING_HANDLE, adv_data_builder.getAdvertisingData());
    VerifyOrExit(mbed_err == BLE_ERROR_NONE, err = CHIP_ERROR(chip::ChipError::Range::kOS, mbed_err));

    adv_data_builder.clear();
    adv_data_builder.setLocalServiceList(mbed::make_Span<const UUID>(&ShortUUID_CHIPoBLEService, 1));
    mbed_err = gap.setAdvertisingScanResponse(ble::LEGACY_ADVERTISING_HANDLE, adv_data_builder.getAdvertisingData());
    VerifyOrExit(mbed_err == BLE_ERROR_NONE, err = CHIP_ERROR(chip::ChipError::Range::kOS, mbed_err));

    mbed_err = gap.startAdvertising(ble::LEGACY_ADVERTISING_HANDLE);
    VerifyOrExit(mbed_err == BLE_ERROR_NONE, err = CHIP_ERROR(chip::ChipError::Range::kOS, mbed_err));

    ChipLogDetail(DeviceLayer, "Advertising started, type: 0x%x (%sconnectable), interval: [%lu:%lu] ms, device name: %s)",
                  adv_params.getType().value(), connectable ? "" : "non-", adv_params.getMinPrimaryInterval().valueInMs(),
                  adv_params.getMaxPrimaryInterval().valueInMs(), mDeviceName);

exit:
    if (mbed_err != BLE_ERROR_NONE)
    {
        ChipLogError(DeviceLayer, "StartAdvertising mbed-os error: %d", mbed_err);
    }
    return err;
}

CHIP_ERROR BLEManagerImpl::StopAdvertising(void)
{
    CHIP_ERROR err       = CHIP_NO_ERROR;
    ble_error_t mbed_err = BLE_ERROR_NONE;

    ble::Gap & gap = ble::BLE::Instance().gap();

    if (!gap.isAdvertisingActive(ble::LEGACY_ADVERTISING_HANDLE))
    {
        ChipLogDetail(DeviceLayer, "No need to stop. Advertising inactive.");
        return err;
    }
    mbed_err = gap.stopAdvertising(ble::LEGACY_ADVERTISING_HANDLE);
    VerifyOrExit(mbed_err == BLE_ERROR_NONE, err = CHIP_ERROR(chip::ChipError::Range::kOS, mbed_err));

exit:
    if (mbed_err != BLE_ERROR_NONE)
    {
        ChipLogError(DeviceLayer, "StopAdvertising mbed-os error: %d", mbed_err);
    }
    return err;
}

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

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

    if (mFlags.Has(kFlag_AdvertisingEnabled) != val)
    {
        ChipLogDetail(DeviceLayer, "SetAdvertisingEnabled(%s)", val ? "true" : "false");

        mFlags.Set(kFlag_AdvertisingEnabled, val);
        PlatformMgr().ScheduleWork(DriveBLEState, 0);
    }

exit:
    return err;
}

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

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

    if (mFlags.Has(kFlag_FastAdvertisingEnabled) != val)
    {
        ChipLogDetail(DeviceLayer, "SetFastAdvertisingEnabled(%s)", val ? "true" : "false");

        mFlags.Set(kFlag_FastAdvertisingEnabled, val);
        PlatformMgr().ScheduleWork(DriveBLEState, 0);
    }

exit:
    return err;
}

CHIP_ERROR BLEManagerImpl::_GetDeviceName(char * buf, size_t bufSize)
{
    CHIP_ERROR err = CHIP_NO_ERROR;

    VerifyOrExit(strlen(mDeviceName) < bufSize, err = CHIP_ERROR_BUFFER_TOO_SMALL);
    strcpy(buf, mDeviceName);

exit:
    return err;
}

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(kFlag_UseCustomDeviceName);
        ChipLogDetail(DeviceLayer, "Device name set to: %s", deviceName);
    }
    else
    {
        mDeviceName[0] = '\0';
        mFlags.Clear(kFlag_UseCustomDeviceName);
    }

exit:
    return err;
}

uint16_t BLEManagerImpl::_NumConnections(void)
{
    return mGAPConns;
}

void BLEManagerImpl::_OnPlatformEvent(const ChipDeviceEvent * event)
{
    switch (event->Type)
    {
    case DeviceEventType::kCHIPoBLESubscribe: {
        ChipDeviceEvent connEstEvent;

        ChipLogDetail(DeviceLayer, "_OnPlatformEvent kCHIPoBLESubscribe");
        HandleSubscribeReceived(event->CHIPoBLESubscribe.ConId, &CHIP_BLE_SVC_ID, &ChipUUID_CHIPoBLEChar_TX);
        connEstEvent.Type = DeviceEventType::kCHIPoBLEConnectionEstablished;
        PlatformMgrImpl().PostEventOrDie(&connEstEvent);
    }
    break;

    case DeviceEventType::kCHIPoBLEUnsubscribe: {
        ChipLogDetail(DeviceLayer, "_OnPlatformEvent kCHIPoBLEUnsubscribe");
        HandleUnsubscribeReceived(event->CHIPoBLEUnsubscribe.ConId, &CHIP_BLE_SVC_ID, &ChipUUID_CHIPoBLEChar_TX);
    }
    break;

    case DeviceEventType::kCHIPoBLEWriteReceived: {
        ChipLogDetail(DeviceLayer, "_OnPlatformEvent kCHIPoBLEWriteReceived");
        HandleWriteReceived(event->CHIPoBLEWriteReceived.ConId, &CHIP_BLE_SVC_ID, &ChipUUID_CHIPoBLEChar_RX,
                            PacketBufferHandle::Adopt(event->CHIPoBLEWriteReceived.Data));
    }
    break;

    case DeviceEventType::kCHIPoBLEConnectionError: {
        ChipLogDetail(DeviceLayer, "_OnPlatformEvent kCHIPoBLEConnectionError");
        HandleConnectionError(event->CHIPoBLEConnectionError.ConId, event->CHIPoBLEConnectionError.Reason);
    }
    break;

    case DeviceEventType::kCHIPoBLEIndicateConfirm: {
        ChipLogDetail(DeviceLayer, "_OnPlatformEvent kCHIPoBLEIndicateConfirm");
        HandleIndicationConfirmation(event->CHIPoBLEIndicateConfirm.ConId, &CHIP_BLE_SVC_ID, &ChipUUID_CHIPoBLEChar_TX);
    }
    break;

    default:
        ChipLogDetail(DeviceLayer, "_OnPlatformEvent default:  event->Type = 0x%x", event->Type);
        break;
    }
}

void BLEManagerImpl::NotifyChipConnectionClosed(BLE_CONNECTION_OBJECT conId)
{
    // no-op
}

bool BLEManagerImpl::SubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId)
{
    ChipLogError(DeviceLayer, "%s: NOT IMPLEMENTED", __PRETTY_FUNCTION__);
    return true;
}

bool BLEManagerImpl::UnsubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId)
{
    ChipLogError(DeviceLayer, "%s: NOT IMPLEMENTED", __PRETTY_FUNCTION__);
    return true;
}

bool BLEManagerImpl::CloseConnection(BLE_CONNECTION_OBJECT conId)
{
    ChipLogProgress(DeviceLayer, "Closing BLE GATT connection, connHandle=%d", conId);

    ble::Gap & gap = ble::BLE::Instance().gap();

    ble_error_t mbed_err = gap.disconnect(conId, ble::local_disconnection_reason_t::USER_TERMINATION);
    return mbed_err == BLE_ERROR_NONE;
}

uint16_t BLEManagerImpl::GetMTU(BLE_CONNECTION_OBJECT conId) const
{
    return sConnectionInfo.getMTU(conId);
}

bool BLEManagerImpl::SendIndication(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId,
                                    PacketBufferHandle pBuf)
{
    ChipLogDetail(DeviceLayer, "BlePlatformDelegate %s", __FUNCTION__);

    CHIP_ERROR err       = CHIP_NO_ERROR;
    ble_error_t mbed_err = BLE_ERROR_NONE;

    ble::GattServer & gatt_server = ble::BLE::Instance().gattServer();
    ble::attribute_handle_t att_handle;

    // No need to do anything fancy here. Only 3 handles are used in this impl.
    if (UUIDsMatch(charId, &ChipUUID_CHIPoBLEChar_TX))
    {
        att_handle = sCHIPService.getTxHandle();
    }
    else if (UUIDsMatch(charId, &ChipUUID_CHIPoBLEChar_RX))
    {
        // TODO does this make sense?
        att_handle = sCHIPService.getRxHandle();
    }
    else
    {
        // TODO handle error with chipConnection::SendMessage as described
        // in the BlePlatformDelegate.h.
        ChipLogError(DeviceLayer, "Send indication failed, invalid charID.");
        return false;
    }

    ChipLogDetail(DeviceLayer,
                  "Sending indication for CHIPoBLE characteristic "
                  "(connHandle=%d, attHandle=%d, data_len=%u)",
                  conId, att_handle, pBuf->DataLength());

    mbed_err = gatt_server.write(att_handle, pBuf->Start(), pBuf->DataLength(), false);
    VerifyOrExit(mbed_err == BLE_ERROR_NONE, err = CHIP_ERROR(chip::ChipError::Range::kOS, mbed_err));

exit:
    if (mbed_err != BLE_ERROR_NONE)
    {
        ChipLogError(DeviceLayer, "Send indication failed, mbed-os error: %d", mbed_err);
    }
    return err == CHIP_NO_ERROR;
}

bool BLEManagerImpl::SendWriteRequest(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId,
                                      PacketBufferHandle pBuf)
{
    ChipLogError(DeviceLayer, "%s: NOT IMPLEMENTED", __PRETTY_FUNCTION__);
    return true;
}

bool BLEManagerImpl::SendReadRequest(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId,
                                     PacketBufferHandle pBuf)
{
    ChipLogError(DeviceLayer, "%s: NOT IMPLEMENTED", __PRETTY_FUNCTION__);
    return true;
}

bool BLEManagerImpl::SendReadResponse(BLE_CONNECTION_OBJECT conId, BLE_READ_REQUEST_CONTEXT requestContext,
                                      const ChipBleUUID * svcId, const ChipBleUUID * charId)
{
    ChipLogError(DeviceLayer, "%s: NOT IMPLEMENTED", __PRETTY_FUNCTION__);
    return true;
}

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

#endif // CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
