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

#include "bluetooth_access_ffi.h"
#include "bluetooth_access_impl.h"
#include "bluetooth_errorcode.h"
#include "bluetooth_log.h"
#include "cj_lambda.h"

namespace OHOS {
namespace CJSystemapi {
namespace CJBluetoothAccess {
using Bluetooth::BluetoothHost;
using Bluetooth::BluetoothState;
using Bluetooth::BT_ERR_INTERNAL_ERROR;
using Bluetooth::BT_TRANSPORT_BLE;
using Bluetooth::BT_TRANSPORT_BREDR;
using Bluetooth::BTStateID;

CjBluetoothAccessObserver::CjBluetoothAccessObserver() {}

std::shared_ptr<CjBluetoothAccessObserver> g_bluetoothAccessObserver = std::make_shared<CjBluetoothAccessObserver>();
bool g_flag = false;

static void RegisterAccessObserverToHost()
{
    BluetoothHost* host = &BluetoothHost::GetDefaultHost();
    host->RegisterObserver(g_bluetoothAccessObserver);
}

void CjBluetoothAccessObserver::OnStateChanged(const int transport, const int status)
{
    BluetoothState state = BluetoothState::STATE_OFF;
    if (!DealStateChange(transport, status, state)) {
        HILOGD("No need callback");
        return;
    }

    HILOGD("state is %{public}d", state);
    std::function<void(int32_t)> stateChangeFuncCopy;
    {
        std::lock_guard<std::mutex> lock(mtx_);
        stateChangeFuncCopy = stateChangeFunc;
    }
    if (!stateChangeFuncCopy) {
        HILOGD("failed to register state change callback");
        return;
    }
    stateChangeFuncCopy(static_cast<int32_t>(state));
}

bool CjBluetoothAccessObserver::DealStateChange(const int transport, const int status, BluetoothState& state)
{
    HILOGD("transport is %{public}d, status is %{public}d", transport, status);
    bool isCallback = true;
    if (transport == BT_TRANSPORT_BREDR) {
        GetBrStateByStatus(status, state, isCallback);
    } else if (transport == BT_TRANSPORT_BLE) {
        GetBleStateByStatus(status, state);
    }
    return isCallback;
}

void CjBluetoothAccessObserver::GetBrStateByStatus(const int status, BluetoothState& state, bool& isCallback)
{
    switch (status) {
        case BTStateID::STATE_TURNING_ON:
            HILOGD("STATE_TURNING_ON(1)");
            state = BluetoothState::STATE_TURNING_ON;
            break;
        case BTStateID::STATE_TURN_ON:
            HILOGD("STATE_ON(2)");
            state = BluetoothState::STATE_ON;
            break;
        case BTStateID::STATE_TURNING_OFF:
            HILOGD("STATE_TURNING_OFF(3)");
            state = BluetoothState::STATE_TURNING_OFF;
            break;
        case BTStateID::STATE_TURN_OFF: {
            HILOGD("STATE_OFF(0)");
            break;
        }
        default:
            break;
    }
}

void CjBluetoothAccessObserver::GetBleStateByStatus(const int status, BluetoothState& state)
{
    switch (status) {
        case BTStateID::STATE_TURNING_ON:
            HILOGD("STATE_BLE_TURNING_ON(4)");
            state = BluetoothState::STATE_BLE_TURNING_ON;
            break;
        case BTStateID::STATE_TURN_ON:
            HILOGD("STATE_BLE_ON(5)");
            state = BluetoothState::STATE_BLE_ON;
            break;
        case BTStateID::STATE_TURNING_OFF:
            HILOGD("STATE_BLE_TURNING_OFF(6)");
            state = BluetoothState::STATE_BLE_TURNING_OFF;
            break;
        case BTStateID::STATE_TURN_OFF:
            HILOGD("STATE_OFF(0)");
            state = BluetoothState::STATE_OFF;
            break;
        default:
            break;
    }
}

void CjBluetoothAccessObserver::RegisterStateChangeFunc(std::function<void(int32_t)> cjCallback)
{
    [[maybe_unused]] std::function<void(int32_t)> stateChangeFuncCopy;
    {
        std::lock_guard<std::mutex> lock(mtx_);
        stateChangeFuncCopy = stateChangeFunc;
        stateChangeFunc = cjCallback;
    }
}

void AccessImpl::RegisterAccessObserver(int32_t callbackType, void (*callback)(), int32_t* errCode)
{
    if (!g_flag) {
        RegisterAccessObserverToHost();
        g_flag = true;
    }

    if (callbackType == REGISTER_STATE_CHANGE_TYPE) {
        auto AccessObserverFunc = CJLambda::Create(reinterpret_cast<void (*)(int32_t)>(callback));
        if (!AccessObserverFunc) {
            HILOGD("Register state change event failed");
            *errCode = BT_ERR_INTERNAL_ERROR;
            return;
        }
        g_bluetoothAccessObserver->RegisterStateChangeFunc(AccessObserverFunc);
    }
    return;
}

} // namespace CJBluetoothAccess
} // namespace CJSystemapi
} // namespace OHOS