/*
 * 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 "voip_call_connection.h"

#include "bluetooth_call_connection.h"
#include "telephony_log_wrapper.h"
#include "call_control_manager.h"
#include "settings_datashare_helper.h"
#include "report_call_info_handler.h"

namespace OHOS {
namespace Telephony {
BluetoothCallConnection::BluetoothCallConnection() {}
BluetoothCallConnection::~BluetoothCallConnection() {}

int32_t BluetoothCallConnection::Dial(DialParaInfo &info)
{
    TELEPHONY_LOGI("bluetooth dial start!");
    if (!GetSupportBtCall()) {
        return CALL_ERR_BLUETOOTH_CONNECTION_FAILED;
    }
    std::string number = info.number;
    if (number.empty()) {
        TELEPHONY_LOGE("bluetooth call number is null!");
        return CALL_ERR_DIAL_FAILED;
    }
    if (info.phoneIndex == 0 && macAddress_.empty()) {
        TELEPHONY_LOGE("bluetooth call macaddress is empty");
        return CALL_ERR_DIAL_FAILED;
    }
    if (info.phoneIndex == 1 && secondaryPhoneMacAddress_.empty()) {
        TELEPHONY_LOGE("bluetooth call secondaryPhoneMacAddress_ is empty");
        return CALL_ERR_DIAL_FAILED;
    }
    Bluetooth::HandsFreeUnit *profile = Bluetooth::HandsFreeUnit::GetProfile();
    if (profile == nullptr) {
        TELEPHONY_LOGE("profile is nullptr");
        return CALL_ERR_DIAL_FAILED;
    }

    Bluetooth::BluetoothRemoteDevice device(info.phoneIndex == 1 ? secondaryPhoneMacAddress_ : macAddress_);
    profile->StartDial(device, number);
    return TELEPHONY_SUCCESS;
}

void BluetoothCallConnection::SetMacAddress(int32_t phoneIndex, const std::string &macAddress)
{
    if (phoneIndex == 1) {
        secondaryPhoneMacAddress_ = macAddress;
        if (secondaryPhoneMacAddress_.empty()) {
            TELEPHONY_LOGE("secondary phone BluetoothCallConnection macAddress is empty");
        }
    } else {
        macAddress_ = macAddress;
        if (macAddress_.empty()) {
            TELEPHONY_LOGE("BluetoothCallConnection macAddress is empty");
        }
    }
}

std::string BluetoothCallConnection::GetMacAddress(int32_t phoneIndex)
{
    if (phoneIndex == 1) {
        return secondaryPhoneMacAddress_;
    } else {
        return macAddress_;
    }
}
 
std::string BluetoothCallConnection::GetDeviceName(int32_t phoneIndex)
{
    Bluetooth::BluetoothRemoteDevice device(phoneIndex == 1 ? secondaryPhoneMacAddress_ : macAddress_);
    std::string deviceName = device.GetDeviceName();
    return deviceName;
}

int32_t BluetoothCallConnection::ConnectBtSco()
{
    TELEPHONY_LOGI("connectBtSco event");
    Bluetooth::HandsFreeUnit *profile = Bluetooth::HandsFreeUnit::GetProfile();
    if (profile != nullptr) {
        Bluetooth::BluetoothRemoteDevice device(macAddress_, 1);
        bool isOK = profile->ConnectSco(device);
        if (!isOK) {
            TELEPHONY_LOGE("connectBtSco failed!");
            return TELEPHONY_ERR_FAIL;
        }
        return TELEPHONY_SUCCESS;
    } else {
        TELEPHONY_LOGE("profile is nullptr");
    }
    return TELEPHONY_ERR_FAIL;
}

int32_t BluetoothCallConnection::DisConnectBtSco()
{
    TELEPHONY_LOGI("disconnectBtSco event");
    Bluetooth::HandsFreeUnit *profile = Bluetooth::HandsFreeUnit::GetProfile();
    if (profile != nullptr) {
        Bluetooth::BluetoothRemoteDevice device(macAddress_, 1);
        bool isOK = profile->DisconnectSco(device);
        if (!isOK) {
            TELEPHONY_LOGE("disconnectBtSco failed!");
            return TELEPHONY_ERR_FAIL;
        }
        return TELEPHONY_SUCCESS;
    } else {
        TELEPHONY_LOGE("profile is nullptr");
    }
    return TELEPHONY_ERR_FAIL;
}

bool BluetoothCallConnection::GetBtScoIsConnected()
{
    TELEPHONY_LOGI("getBtScoconnect state event");
    Bluetooth::HandsFreeUnit *profile = Bluetooth::HandsFreeUnit::GetProfile();
    if (profile != nullptr) {
        Bluetooth::BluetoothRemoteDevice device(macAddress_, 1);
        int state = profile->GetScoState(device);
        if (state == static_cast<int>(Bluetooth::HfpScoConnectState::SCO_CONNECTED)) {
            TELEPHONY_LOGE("BtScoconnect on!");
            return true;
        }
    } else {
        TELEPHONY_LOGE("profile is nullptr");
    }
    TELEPHONY_LOGI("BtScoconnect off!");
    return false;
}

void BluetoothCallConnection::SetHfpConnected(bool isHfpConnected)
{
    isHfpConnected_ = isHfpConnected;
    TELEPHONY_LOGI("Set hfpCconnectd=%{public}d", isHfpConnected_);
    if (!isHfpConnected_) {
        HfpDisConnectedEndBtCall();
    }
}

bool BluetoothCallConnection::GetSupportBtCall()
{
    Bluetooth::BluetoothRemoteDevice device(macAddress_);
    Bluetooth::BluetoothRemoteDevice secondDevice(secondaryPhoneMacAddress_);
    bool isAclConnected = device.IsAclConnected();
    bool isSecondAclConnected = secondDevice.IsAclConnected();
    if (isAclConnected || isSecondAclConnected) {
        TELEPHONY_LOGI("Watch Support Bluetooth Call.");
    } else {
        TELEPHONY_LOGE("Watch not Support Bluetooth Call.");
    }
    return isAclConnected || isSecondAclConnected;
}

void BluetoothCallConnection::SetBtCallScoConnected(bool isBtCallScoConnected)
{
    std::lock_guard<ffrt::mutex> lock(mutex_);
    isBtCallScoConnected_ = isBtCallScoConnected;
    TELEPHONY_LOGI("Set BtCallScoConnected=%{public}d", isBtCallScoConnected_);
}

bool BluetoothCallConnection::GetBtCallScoConnected()
{
    std::lock_guard<ffrt::mutex> lock(mutex_);
    TELEPHONY_LOGI("Get BtCallScoConnected=%{public}d", isBtCallScoConnected_);
    return isBtCallScoConnected_;
}

void BluetoothCallConnection::HfpDisConnectedEndBtCall()
{
    TELEPHONY_LOGI("hfp disconnected, hangup all bt call.");
    std::list<sptr<CallBase>> allCallList = CallObjectManager::GetAllCallList();
    for (auto call : allCallList) {
        if (call == nullptr || call->GetCallType() != CallType::TYPE_BLUETOOTH) {
            continue;
        }
        CallAttributeInfo info;
        (void)memset_s(&info, sizeof(CallAttributeInfo), 0, sizeof(CallAttributeInfo));
        call->GetCallAttributeBaseInfo(info);
        CallDetailInfo detailInfo;
        detailInfo.callType = info.callType;
        detailInfo.accountId = info.accountId;
        detailInfo.index = call->GetCallIndex();
        detailInfo.state = TelCallState::CALL_STATUS_DISCONNECTED;
        (void)memcpy_s(detailInfo.phoneNum, kMaxNumberLen, info.accountNumber, kMaxNumberLen);
        (void)memset_s(detailInfo.bundleName, kMaxBundleNameLen  + 1, 0, kMaxBundleNameLen + 1);
        int32_t ret = DelayedSingleton<ReportCallInfoHandler>::GetInstance()->UpdateCallReportInfo(detailInfo);
        if (ret != TELEPHONY_SUCCESS) {
            TELEPHONY_LOGE("UpdateCallReportInfo failed! errCode:%{public}d", ret);
        } else {
            TELEPHONY_LOGI("UpdateCallReportInfo success! state:%{public}d, index:%{public}d",
                detailInfo.state, detailInfo.index);
        }
    }
}

void BluetoothCallConnection::SetHfpContactName(const std::string &hfpPhoneNumber, const std::string &hfpContactName)
{
    TELEPHONY_LOGI("hfpPhoneNumber length = %{public}zu, hfpContactName length = %{public}zu",
        hfpPhoneNumber.length(), hfpContactName.length());
    hfpPhoneNumber_ = hfpPhoneNumber;
    hfpContactName_ = hfpContactName;
}

std::string BluetoothCallConnection::GetHfpContactName(const std::string &hfpPhoneNumber)
{
    if (!hfpPhoneNumber_.empty() && hfpPhoneNumber == hfpPhoneNumber_) {
        TELEPHONY_LOGI("got name.");
        return hfpContactName_;
    }
    return "";
}
} // namespace Telephony
} // namespace OHOS