/*
 * 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.
 */

#include "bluetooth_gatt_client_impl.h"

#include <algorithm>
#include <cctype>
#include <functional>
#include <thread>

#include "bluetooth_jni.h"
#include "bluetooth_log.h"

using namespace OHOS::bluetooth;
namespace OHOS {
namespace Bluetooth {
namespace {
constexpr uint16_t MIN_HANDLE = 1;
constexpr uint16_t MAX_HANDLE = 65535;
constexpr uint32_t DEFAULT = 0x02;
constexpr uint32_t NO_RESPONSE = 0x01;
constexpr uint32_t SIGNED = 0x04;
constexpr int32_t ONE_HUNDRED_MS = 100;
constexpr size_t BLE_ATT_HEADER_SIZE = 3;
constexpr size_t DELAY_COUNT = 5;

std::string NormalizeUuid(std::string uuid)
{
    std::transform(uuid.begin(), uuid.end(), uuid.begin(), [](unsigned char c) { return std::toupper(c); });
    return uuid;
}
}
std::map<int32_t, std::shared_ptr<GattClientData>> BluetoothGattClientImpl::gattClientDataMap_;
std::map<int32_t, std::list<std::pair<uint16_t, uint16_t>>> BluetoothGattClientImpl::gattClientHandleMap_;
std::map<int32_t, std::map<std::pair<uint16_t, uint16_t>, std::string>> BluetoothGattClientImpl::serviceHandleMap_;
std::map<int32_t, std::map<std::pair<uint16_t, uint16_t>, std::string>> BluetoothGattClientImpl::characterHandleMap_;
std::map<int32_t, std::map<uint16_t, std::string>> BluetoothGattClientImpl::descriptorHandleMap_;
int32_t BluetoothGattClientImpl::appId_ = 0;
std::mutex BluetoothGattClientImpl::gattClientMutex_;

BluetoothGattClientImpl::BluetoothGattClientImpl() {}

BluetoothGattClientImpl::~BluetoothGattClientImpl() {}

int BluetoothGattClientImpl::RegisterApplication(
    const sptr<IBluetoothGattClientCallback>& callback, const BluetoothRawAddress& addr, int32_t transport)
{
    return BT_NO_ERROR;
}

int BluetoothGattClientImpl::RegisterApplication(
    const sptr<IBluetoothGattClientCallback>& callback, const BluetoothRawAddress& addr, int32_t transport, int& appId)
{
    std::lock_guard<std::mutex> lock(gattClientMutex_);
    int result = GattStatus::DEVICE_ALREADY_BIND;
    appId_ += 1;
    appId = appId_;
    std::shared_ptr<GattClientData> gattClientData = std::make_shared<GattClientData>(callback, addr, transport);
    if (gattClientDataMap_.emplace(appId, gattClientData).second) {
        gattClientHandleMap_[appId].emplace_front(std::make_pair(MIN_HANDLE, MAX_HANDLE));
        result = GattStatus::GATT_SUCCESS;
    } else {
        HILOGE("BluetoothGattClientImpl RegisterApplication failed.");
        result = GattStatus::GATT_FAILURE;
    }
    return result;
}

int BluetoothGattClientImpl::DeregisterApplication(int32_t appId)
{
    int result = BT_NO_ERROR;
    std::lock_guard<std::mutex> lock(gattClientMutex_);
    auto it = gattClientDataMap_.find(appId);
    if (it != gattClientDataMap_.end()) {
        result = BluetoothJni::GattClientClose(appId);
    } else {
        HILOGE("BluetoothGattClientImpl DeregisterApplication failed, the appId is %{public}d", appId);
        result = INVALID_PARAMETER;
    }
    if (result == BT_NO_ERROR) {
        gattClientDataMap_.erase(appId);
        BluetoothGattClientImpl::EraseHandleByAppId(appId);
    }
    return result;
}

int BluetoothGattClientImpl::Connect(int32_t appId, bool autoConnect)
{
    int result = BT_NO_ERROR;
    auto gattClientData = BluetoothGattClientImpl::GetGattClientData(appId);
    if (gattClientData) {
        auto address = gattClientData->rawAddress_.GetAddress();
        result = BluetoothJni::GattClientConnect(appId, address, autoConnect);
    } else {
        HILOGE("BluetoothGattClientImpl Connect failed, the appId is %{public}d", appId);
        result = BT_ERR_INTERNAL_ERROR;
    }
    return result;
}

int BluetoothGattClientImpl::Disconnect(int32_t appId)
{
    return BluetoothJni::GattClientDisconnect(appId);
}

int BluetoothGattClientImpl::DiscoveryServices(int32_t appId)
{
    auto gattClientData = BluetoothGattClientImpl::GetGattClientData(appId);
    if (gattClientData && gattClientData->callback_) {
        gattClientData->callback_->OnServicesDiscovered(GattStatus::GATT_SUCCESS);
    } else {
        HILOGE("BluetoothGattClientImpl DiscoveryServices failed, the appId is %{public}d", appId);
    }
    return GattStatus::GATT_SUCCESS;
}

int BluetoothGattClientImpl::ReadCharacteristic(int32_t appId, const BluetoothGattCharacteristic& characteristic)
{
    auto gattClientData = BluetoothGattClientImpl::GetGattClientData(appId);
    int32_t result = BT_NO_ERROR;
    if (gattClientData) {
        BluetoothGattCharacteristic gattCharacteristic = BluetoothGattCharacteristic(characteristic);
        result = BluetoothJni::ClientReadCharacter(appId, gattCharacteristic);
    } else {
        HILOGE("BluetoothGattClientImpl ReadCharacteristic failed, the appId is %{public}d", appId);
        result = BT_ERR_INTERNAL_ERROR;
    }
    return result;
}

int BluetoothGattClientImpl::ReadCharacteristicByUuid(int32_t appId, const std::string& uuid,
    int32_t  startHandle, int32_t  endHandle)
{
    HILOGI("NOT SUPPORT NOW");
    return BT_NO_ERROR;
}

int BluetoothGattClientImpl::WriteCharacteristic(
    int32_t appId, BluetoothGattCharacteristic* characteristic, bool withoutRespond, bool isWithContext)
{
    int32_t result = BT_NO_ERROR;
    auto gattClientData = BluetoothGattClientImpl::GetGattClientData(appId);
    if (gattClientData) {
        BluetoothGattCharacteristic gattCharacteristic = BluetoothGattCharacteristic(*characteristic);
        size_t maxMtu = gattClientData->mtu_ - BLE_ATT_HEADER_SIZE;
        if (maxMtu < gattCharacteristic.length_) {
            HILOGE("Write data is greater than the maximum transfer rate");
            return BT_ERR_INTERNAL_ERROR;
        }
        int32_t type = withoutRespond ? NO_RESPONSE : DEFAULT;
        result = BluetoothJni::ClientWriteCharacter(appId, gattCharacteristic, type);
    } else {
        HILOGE("BluetoothGattClientImpl WriteCharacteristic failed, the appId is %{public}d", appId);
        result = BT_ERR_INTERNAL_ERROR;
    }
    return result;
}

int BluetoothGattClientImpl::SignedWriteCharacteristic(int32_t appId, BluetoothGattCharacteristic* characteristic)
{
    int32_t result = BT_NO_ERROR;
    auto gattClientData = BluetoothGattClientImpl::GetGattClientData(appId);
    if (gattClientData) {
        BluetoothGattCharacteristic gattCharacteristic = BluetoothGattCharacteristic(*characteristic);
        result = BluetoothJni::ClientWriteCharacter(appId, gattCharacteristic, SIGNED);
    } else {
        HILOGE("BluetoothGattClientImpl WriteCharacteristic failed, the appId is %{public}d", appId);
        result = BT_ERR_INTERNAL_ERROR;
    }
    return result;
}

int BluetoothGattClientImpl::ReadDescriptor(int32_t appId, const BluetoothGattDescriptor& descriptor)
{
    int32_t result = BT_NO_ERROR;
    auto gattClientData = BluetoothGattClientImpl::GetGattClientData(appId);
    if (gattClientData) {
        BluetoothGattDescriptor gattDescriptor = BluetoothGattDescriptor(descriptor);
        result = BluetoothJni::ClientReadDescriptor(appId, gattDescriptor);
    } else {
        HILOGE("BluetoothGattClientImpl ReadDescriptor failed, the appId is %{public}d", appId);
        result = BT_ERR_INTERNAL_ERROR;
    }
    return result;
}

int BluetoothGattClientImpl::WriteDescriptor(int32_t appId, BluetoothGattDescriptor* descriptor)
{
    int32_t result = BT_NO_ERROR;
    auto gattClientData = BluetoothGattClientImpl::GetGattClientData(appId);
    if (gattClientData) {
        BluetoothGattDescriptor gattDescriptor = BluetoothGattDescriptor(*descriptor);
        size_t maxMtu = gattClientData->mtu_ - BLE_ATT_HEADER_SIZE;
        if (maxMtu < gattDescriptor.length_) {
            HILOGE("Write data is greater than the maximum transfer rate");
            return BT_ERR_INTERNAL_ERROR;
        }
        result = BluetoothJni::ClientWriteDescriptor(appId, gattDescriptor);
    } else {
        HILOGE("BluetoothGattClientImpl WriteDescriptor failed, the appId is %{public}d", appId);
        result = BT_ERR_INTERNAL_ERROR;
    }
    return result;
}

int BluetoothGattClientImpl::RequestExchangeMtu(int32_t appId, int32_t mtu)
{
    return BluetoothJni::RequestExchangeMtu(appId, mtu);
}

void BluetoothGattClientImpl::GetAllDevice(std::vector<BluetoothGattDevice>& device) {}

int BluetoothGattClientImpl::RequestConnectionPriority(int32_t appId, int32_t connPriority)
{
    return BT_NO_ERROR;
}

void BluetoothGattClientImpl::CopyBluetoothGattService(
    std::vector<BluetoothGattService>& services, std::vector<BluetoothGattService>& copeServices)
{
    for (auto& iter : services) {
        copeServices.push_back(std::move(iter));
    }
}

int BluetoothGattClientImpl::GetServices(int32_t appId, std::vector<BluetoothGattService>& service)
{
    auto gattClientData = BluetoothGattClientImpl::GetGattClientData(appId);
    if (gattClientData == nullptr) {
        HILOGE("BluetoothGattClientImpl GetServices failed, the appId is %{public}d", appId);
        return BT_ERR_INTERNAL_ERROR;
    }
    std::vector<BluetoothGattService> copeServices;
    CopyBluetoothGattService(gattClientData->services_, copeServices);
    gattClientData->services_.clear();
    int32_t result = BluetoothJni::ClientDiscoverServices(appId);
    if (result == BT_NO_ERROR) {
        std::this_thread::sleep_for(std::chrono::milliseconds(ONE_HUNDRED_MS));
        int32_t checkCount = 0;
        int32_t servicesSize = -1;
        while (checkCount < DELAY_COUNT) {
            std::lock_guard<std::mutex> lock(BluetoothJni::gattClientServiceLock_);
            if (gattClientData->services_.size() == servicesSize) {
                break;
            }
            ++checkCount;
            servicesSize = gattClientData->services_.size();
        }
    } else {
        CopyBluetoothGattService(copeServices, gattClientData->services_);
    }
    CopyBluetoothGattService(gattClientData->services_, service);
    return BT_NO_ERROR;
}

int BluetoothGattClientImpl::RequestFastestConn(const BluetoothRawAddress& addr)
{
    return BT_NO_ERROR;
}

int BluetoothGattClientImpl::ReadRemoteRssiValue(int32_t appId)
{
    HILOGI("NOT SUPPORT NOW");
    return BT_NO_ERROR;
}

int BluetoothGattClientImpl::RequestNotification(int32_t appId, uint16_t characterHandle, bool enable)
{
    auto sUuidString = GetServiceUuidByHandle(appId, characterHandle);
    auto cUuidString = GetCharacterUuidByHandle(appId, characterHandle);
    if (sUuidString.empty() || cUuidString.empty()) {
        HILOGE("RequestNotification failed, appId: %{public}d, handle: %{public}u", appId, characterHandle);
        return BT_ERR_INTERNAL_ERROR;
    }
    return BluetoothJni::ClientRequestNotification(appId, sUuidString, cUuidString, enable);
}

int BluetoothGattClientImpl::GetConnectedState(const std::string &deviceId, int &state)
{
    HILOGI("NOT SUPPORT NOW");
    return BT_NO_ERROR;
}

int BluetoothGattClientImpl::SetPhy(int32_t appId, int32_t txPhy, int32_t rxPhy, int32_t phyOptions)
{
    HILOGI("NOT SUPPORT NOW");
    return BT_NO_ERROR;
}

int BluetoothGattClientImpl::ReadPhy(int32_t appId)
{
    HILOGI("NOT SUPPORT NOW");
    return BT_NO_ERROR;
}

std::shared_ptr<GattClientData> BluetoothGattClientImpl::GetGattClientData(int32_t appId)
{
    std::lock_guard<std::mutex> lock(gattClientMutex_);
    auto it = gattClientDataMap_.find(appId);
    if (it != gattClientDataMap_.end()) {
        return it->second;
    } else {
        HILOGE("BluetoothGattClientImpl GetGattClientData failed, the appId is %{public}d", appId);
        return nullptr;
    }
}

bool BluetoothGattClientImpl::SetHandle(const int appId, BluetoothGattService& service)
{
    uint16_t count = 1;
    std::pair<uint16_t, uint16_t> handlePair(0, 0);
    count += service.includeServices_.size();
    count += service.characteristics_.size() * 0x2;
    for (const auto& iter : service.characteristics_) {
        count += iter.descriptors_.size();
    }
    bool result = false;
    std::lock_guard<std::mutex> lock(gattClientMutex_);
    for (auto item = gattClientHandleMap_[appId].begin(); item != gattClientHandleMap_[appId].end(); item++) {
        auto availableLength = item->second - item->first + 1;
        if (availableLength >= count) {
            handlePair = std::pair<uint16_t, uint16_t>(item->first, item->first + count - 1);
            if (handlePair.second < item->second) {
                gattClientHandleMap_[appId].insert(
                    item, std::pair<uint16_t, uint16_t>(handlePair.second + 1, item->second));
                result = true;
            }
            gattClientHandleMap_[appId].erase(item);
            break;
        }
    }
    service.handle_ = handlePair.first;
    service.endHandle_ = handlePair.second;
    if (result) {
        serviceHandleMap_[appId][handlePair] = service.uuid_.ToString();
    }
    if (handlePair == std::pair<uint16_t, uint16_t>(0, 0)) {
        return false;
    }
    uint32_t currentHandle = handlePair.first + 1;
    for (auto& includeService : service.includeServices_) {
        includeService.handle_ = currentHandle++;
    }
    for (auto& character : service.characteristics_) {
        character.handle_ = currentHandle++;
        character.valueHandle_ = currentHandle++;
        for (auto& descriptor : character.descriptors_) {
            descriptor.handle_ = currentHandle++;
            descriptorHandleMap_[appId][descriptor.handle_] = descriptor.uuid_.ToString();
        }
        character.endHandle_ = currentHandle - 1;
        std::pair<uint16_t, uint16_t> value(character.handle_, character.endHandle_);
        characterHandleMap_[appId][value] = character.uuid_.ToString();
    }
    return true;
}

void BluetoothGattClientImpl::EraseHandleByAppId(const int appId)
{
    auto serviceIter = serviceHandleMap_.find(appId);
    if (serviceIter != serviceHandleMap_.end()) {
        serviceHandleMap_.erase(serviceIter);
    }
    auto characterIter = characterHandleMap_.find(appId);
    if (characterIter != characterHandleMap_.end()) {
        characterHandleMap_.erase(characterIter);
    }
    auto descriptorIter = descriptorHandleMap_.find(appId);
    if (descriptorIter != descriptorHandleMap_.end()) {
        descriptorHandleMap_.erase(descriptorIter);
    }
}

std::string BluetoothGattClientImpl::GetServiceUuidByHandle(const int appId, const int handle)
{
    auto iter = serviceHandleMap_.find(appId);
    if (iter != serviceHandleMap_.end()) {
        auto serviceUuidMap = iter->second;
        for (const auto& entry : serviceUuidMap) {
            const std::pair<uint16_t, uint16_t>& value = entry.first;
            if (handle >= value.first && handle <= value.second) {
                return entry.second;
            }
        }
    } else {
        HILOGE("Get service uuid by handle failed, the appId is %{public}d", appId);
        return std::string("");
    }
}

std::string BluetoothGattClientImpl::GetCharacterUuidByHandle(const int appId, const int handle)
{
    auto iter = characterHandleMap_.find(appId);
    if (iter != characterHandleMap_.end()) {
        auto characterUuidMap = iter->second;
        for (const auto& entry : characterUuidMap) {
            const std::pair<uint16_t, uint16_t>& value = entry.first;
            if (handle >= value.first && handle <= value.second) {
                return entry.second;
            }
        }
    } else {
        HILOGE("Get character uuid by handle failed, the appId is %{public}d", appId);
        return std::string("");
    }
}

uint16_t BluetoothGattClientImpl::GetCharacteristicHandleByUuid(const int appId, const std::string& serviceUuid,
    const std::string& characteristicUuid)
{
    auto normalizedServiceUuid = NormalizeUuid(serviceUuid);
    auto normalizedCharacteristicUuid = NormalizeUuid(characteristicUuid);
    auto iter = characterHandleMap_.find(appId);
    if (iter == characterHandleMap_.end()) {
        HILOGE("Get characteristic handle by uuid failed, the appId is %{public}d", appId);
        return 0;
    }

    for (const auto& entry : iter->second) {
        if (entry.second != normalizedCharacteristicUuid) {
            continue;
        }
        const uint16_t handle = entry.first.first;
        if (GetServiceUuidByHandle(appId, handle) == normalizedServiceUuid) {
            return handle;
        }
    }
    return 0;
}

std::string BluetoothGattClientImpl::GetDescriptorUuidByHandle(const int appId, const int handle)
{
    auto iter = descriptorHandleMap_.find(appId);
    if (iter != descriptorHandleMap_.end()) {
        auto descriptorHandleMap = iter->second;
        for (const auto& entry : descriptorHandleMap) {
            const uint16_t& value = entry.first;
            if (handle == value) {
                return entry.second;
            }
        }
    } else {
        HILOGE("Get descriptor uuid by handle failed, the appId is %{public}d", appId);
        return std::string("");
    }
}

uint16_t BluetoothGattClientImpl::GetDescriptorHandleByUuid(const int appId, const std::string& serviceUuid,
    const std::string& characteristicUuid, const std::string& descriptorUuid)
{
    auto normalizedServiceUuid = NormalizeUuid(serviceUuid);
    auto normalizedCharacteristicUuid = NormalizeUuid(characteristicUuid);
    auto normalizedDescriptorUuid = NormalizeUuid(descriptorUuid);
    auto iter = descriptorHandleMap_.find(appId);
    if (iter == descriptorHandleMap_.end()) {
        HILOGE("Get descriptor handle by uuid failed, the appId is %{public}d", appId);
        return 0;
    }

    for (const auto& entry : iter->second) {
        if (entry.second != normalizedDescriptorUuid) {
            continue;
        }
        const uint16_t handle = entry.first;
        if (GetServiceUuidByHandle(appId, handle) == normalizedServiceUuid &&
            GetCharacterUuidByHandle(appId, handle) == normalizedCharacteristicUuid) {
            return handle;
        }
    }
    return 0;
}
} // namespace Bluetooth
} // namespace OHOS