/*
 * Copyright (C) 2024 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_ble_centralmanager_impl.h"

#import "BluetoothCentralManager.h"
#include "bluetooth_log.h"

using namespace OHOS::bluetooth;

namespace OHOS {
namespace Bluetooth {
BluetoothBleCentralManagerImpl::BluetoothBleCentralManagerImpl()
{
    [BluetoothCentralManager sharedInstance];
    scannerId_ = 0;
}

BluetoothBleCentralManagerImpl::~BluetoothBleCentralManagerImpl() {}

void BluetoothBleCentralManagerImpl::RegisterBleCentralManagerCallback(
    int32_t& scannerId, bool enableRandomAddrMode, const sptr<IBluetoothBleCentralManagerCallback>& callback)
{
    if (callback == nullptr) {
        HILOGE("RegisterBleCentralManagerCallback callback is nullptr");
        return;
    }
    std::lock_guard<std::mutex> lock(scanMutex_);
    scannerId = getCallBackScannerId();
    profileIdScanMap_.insert({ scannerId, callback });
}

void BluetoothBleCentralManagerImpl::DeregisterBleCentralManagerCallback(
    int32_t scannerId, const sptr<IBluetoothBleCentralManagerCallback>& callback)
{
    std::lock_guard<std::mutex> lock(scanMutex_);
    auto mapCallback = profileIdScanMap_.find(scannerId);
    if (mapCallback != profileIdScanMap_.end()) {
        profileIdScanMap_.erase(mapCallback);
    }
}

std::string changeTypeWithData(NSDictionary* dic)
{
    NSMutableString* resultString = [NSMutableString stringWithFormat:@"{"];
    BOOL isFirstEntry = YES;
    for (NSString* key in dic.allKeys) {
        if (!isFirstEntry) {
            [resultString appendString:@","];
        } else {
            isFirstEntry = NO;
        }

        [resultString appendFormat:@"%@:%@", key, dic[key]];
    }
    [resultString appendString:@"}"];
    return resultString.UTF8String;
}

void onSetScanResults(BluetoothBleScanResult& bleScanResult_, CBPeripheral* peripheral,
    NSDictionary<NSString*, id>* advertisementData, NSNumber* RSSI)
{
    if (peripheral.name.length) {
        bleScanResult_.SetName(peripheral.name.UTF8String);
    }
    if (RSSI.integerValue >= INT8_MIN && RSSI.integerValue <= INT8_MAX) {
        bleScanResult_.SetRssi((int8_t)RSSI.integerValue);
    }
    if (advertisementData) {
        bleScanResult_.SetPayload(changeTypeWithData(advertisementData));
        bleScanResult_.SetConnectable([[advertisementData objectForKey:CBAdvertisementDataIsConnectable] boolValue]);
    }
    bleScanResult_.SetPeripheralDevice(OHOS::bluetooth::RawAddress(peripheral.identifier.UUIDString.UTF8String));
}

bool isConditionFilters(NSString* string, NSString* strFilter)
{
    if ([string containsString:strFilter] || [strFilter containsString:@"null"] || strFilter.length == 0) {
        return true;
    }
    return false;
}

int BluetoothBleCentralManagerImpl::StartScan(int32_t scannerId, const BluetoothBleScanSettings& settings,
    const std::vector<BluetoothBleScanFilter>& filters, bool isNewApi)
{
    NSMutableArray<CBUUID*>* arrUuid = [NSMutableArray array];
    NSMutableArray* arrFilter = [NSMutableArray array];
    for (BluetoothBleScanFilter item : filters) {
        NSString* strName = [NSString stringWithFormat:@"%s", item.GetName().c_str()];
        NSString* strDeviceId = [NSString stringWithFormat:@"%s", item.GetDeviceId().c_str()];
        NSString* strSSU = [NSString stringWithFormat:@"%s", item.GetServiceSolicitationUuid().ToString().c_str()];
        strSSU = item.GetServiceSolicitationUuid().ToString() == BLUETOOTH_UUID_BASE_UUID ? @"" : strSSU;
        NSDictionary* dic = @ { @"name" : strName, @"deviceId" : strDeviceId, @"ssu" : strSSU };
        [arrFilter addObject:dic];
        std::string serviceUUID = item.GetServiceUuid().ToString();
        if (serviceUUID == BLUETOOTH_UUID_BASE_UUID || serviceUUID.empty()) {
            continue;
        }
        NSString* strUuid = [NSString stringWithFormat:@"%s", serviceUUID.c_str()];
        [arrUuid addObject:[CBUUID UUIDWithString:strUuid]];
    }
    BluetoothCentralManager* centralManager = [BluetoothCentralManager sharedInstance];
    centralManager.scanDataBlock =
        ^(CBPeripheral* peripheral, NSDictionary<NSString*, id>* advertisementData, NSNumber* RSSI) {
          sptr<IBluetoothBleCentralManagerCallback>& callback = profileIdScanMap_[scannerId];
          if (callback == nullptr) {
              return;
          }
          BluetoothBleScanResult bleSR;
          onSetScanResults(bleSR, peripheral, advertisementData, RSSI);
          if (arrFilter.count == 0) {
              callback->OnScanCallback(bleSR, OHOS::bluetooth::BLE_SCAN_CALLBACK_TYPE_ALL_MATCH);
              return;
          }
          NSString* strAdvDataDeviceUuid = [NSString stringWithFormat:@"%@", peripheral.identifier.UUIDString];
          NSString* strAdvDataName =
              [NSString stringWithFormat:@"%@", [advertisementData objectForKey:CBAdvertisementDataLocalNameKey]];
          NSString* strAdvDataSD =
              [NSString stringWithFormat:@"%@", [advertisementData objectForKey:CBAdvertisementDataServiceDataKey]];
          NSString* strAdvDataSSU = [NSString
              stringWithFormat:@"%@", [advertisementData objectForKey:CBAdvertisementDataSolicitedServiceUUIDsKey]];
          for (NSDictionary* dic in arrFilter) {
              if (isConditionFilters(peripheral.name, dic[@"name"]) &&
                  isConditionFilters(strAdvDataDeviceUuid, dic[@"deviceId"]) &&
                  isConditionFilters(strAdvDataSSU, dic[@"ssu"])) {
                  callback->OnScanCallback(bleSR, OHOS::bluetooth::BLE_SCAN_CALLBACK_TYPE_ALL_MATCH);
                  break;
              }
          }
        };
    return [centralManager startBLEScanWithId:arrUuid];
}

int BluetoothBleCentralManagerImpl::StopScan(int32_t scannerId)
{
    [[BluetoothCentralManager sharedInstance] stopBLEScan];
    return BT_NO_ERROR;
}

void BluetoothBleCentralManagerImpl::RemoveScanFilter(int32_t scannerId) {}

bool BluetoothBleCentralManagerImpl::FreezeByRss(std::set<int> pidSet, bool isProxy, uint8_t freezeType)
{
    return BT_NO_ERROR;
}

bool BluetoothBleCentralManagerImpl::ResetAllProxy()
{
    return BT_NO_ERROR;
}

int BluetoothBleCentralManagerImpl::SetLpDeviceAdvParam(
    int duration, int maxExtAdvEvents, int window, int interval, int advHandle)
{
    return BT_NO_ERROR;
}

int BluetoothBleCentralManagerImpl::SetScanReportChannelToLpDevice(int32_t scannerId, bool enable)
{
    return BT_NO_ERROR;
}

int BluetoothBleCentralManagerImpl::EnableSyncDataToLpDevice()
{
    return BT_NO_ERROR;
}

int BluetoothBleCentralManagerImpl::DisableSyncDataToLpDevice()
{
    return BT_NO_ERROR;
}

int BluetoothBleCentralManagerImpl::SendParamsToLpDevice(const std::vector<uint8_t>& dataValue, int32_t type)
{
    return BT_NO_ERROR;
}

bool BluetoothBleCentralManagerImpl::IsLpDeviceAvailable()
{
    return BT_NO_ERROR;
}

int BluetoothBleCentralManagerImpl::SetLpDeviceParam(const BluetoothLpDeviceParamSet& paramSet)
{
    return BT_NO_ERROR;
}

int BluetoothBleCentralManagerImpl::RemoveLpDeviceParam(const bluetooth::Uuid& uuid)
{
    return BT_NO_ERROR;
}

int BluetoothBleCentralManagerImpl::ChangeScanParams(int32_t scannerId, const BluetoothBleScanSettings& settings,
    const std::vector<BluetoothBleScanFilter>& filters, uint32_t filterAction)
{
    return BT_NO_ERROR;
}

int BluetoothBleCentralManagerImpl::IsValidScannerId(int32_t scannerId, bool &isValid)
{
    return BT_NO_ERROR;
}

int BluetoothBleCentralManagerImpl::FlushBatchScanResults(int32_t scannerId)
{
    HILOGE("Not Supported");
    return BT_NO_ERROR;
}

int BluetoothBleCentralManagerImpl::getCallBackScannerId()
{
    scannerId_ += 1;
    return scannerId_;
}
} // namespace Bluetooth
} // namespace OHOS