/*
 * Copyright (C) 2021-2022 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_fwk_hfp_ag"
#endif

#include "bluetooth_hfp_ag.h"
#include <unistd.h>
#include "bluetooth_device.h"
#include "bluetooth_host.h"
#include "bluetooth_profile_manager.h"
#include "bluetooth_log.h"
#include "bluetooth_utils.h"
#include "bluetooth_observer_list.h"
#include "bluetooth_phone_state.h"
#include "i_bluetooth_hfp_ag.h"
#include "bluetooth_hfp_ag_observer_stub.h"
#include "i_bluetooth_host.h"
#include "iservice_registry.h"
#include "system_ability_definition.h"
#include "bt_def.h"

namespace OHOS {
namespace Bluetooth {
std::mutex g_hfpProxyMutex;
class AgServiceObserver : public BluetoothHfpAgObserverStub {
public:
    explicit AgServiceObserver(BluetoothObserverList<HandsFreeAudioGatewayObserver> &observers) : observers_(observers)
    {
        HILOGD("enter");
    }
    ~AgServiceObserver() override
    {
        HILOGD("enter");
    };

    void OnConnectionStateChanged(const BluetoothRawAddress &device, int32_t state, int32_t cause) override
    {
        HILOGD("hfpAg conn state, device: %{public}s, state: %{public}s, cause: %{public}d",
            GET_ENCRYPT_RAW_ADDR(device), GetProfileConnStateName(state).c_str(), cause);
        BluetoothRemoteDevice remoteDevice(device.GetAddress(), 0);
        observers_.ForEach([remoteDevice, state, cause](std::shared_ptr<HandsFreeAudioGatewayObserver> observer) {
            observer->OnConnectionStateChanged(remoteDevice, state, cause);
        });
    }

    void OnScoStateChanged(const BluetoothRawAddress &device, int32_t state, int32_t reason) override
    {
        HILOGI("enter, device: %{public}s, state: %{public}u, reason: %{public}u",
            GET_ENCRYPT_RAW_ADDR(device), state, reason);
        BluetoothRemoteDevice remoteDevice(device.GetAddress(), 0);
        observers_.ForEach([remoteDevice, state, reason](std::shared_ptr<HandsFreeAudioGatewayObserver> observer) {
            observer->OnScoStateChanged(remoteDevice, state, reason);
        });
    }

    void OnActiveDeviceChanged(const BluetoothRawAddress &device) override
    {
        HILOGD("enter, device: %{public}s", GET_ENCRYPT_RAW_ADDR(device));
        BluetoothRemoteDevice remoteDevice(device.GetAddress(), 0);
        observers_.ForEach([remoteDevice](std::shared_ptr<HandsFreeAudioGatewayObserver> observer) {
            observer->OnActiveDeviceChanged(remoteDevice);
        });
    }

    void OnHfEnhancedDriverSafetyChanged(
        const BluetoothRawAddress &device, int32_t indValue) override
    {
        HILOGI("enter, device: %{public}s, indValue: %{public}d",
            GET_ENCRYPT_RAW_ADDR(device), indValue);
        BluetoothRemoteDevice remoteDevice(device.GetAddress(), 0);
        observers_.ForEach([remoteDevice, indValue](std::shared_ptr<HandsFreeAudioGatewayObserver> observer) {
            observer->OnHfEnhancedDriverSafetyChanged(remoteDevice, indValue);
        });
    }

    void OnHfpStackChanged(const BluetoothRawAddress &device, int32_t action) override
    {
        HILOGI("enter, device: %{public}s, action: %{public}s",
            GET_ENCRYPT_RAW_ADDR(device), GetUpdateOutputStackActionName(action).c_str());
        BluetoothRemoteDevice remoteDevice(device.GetAddress(), 0);
        observers_.ForEach([remoteDevice, action](std::shared_ptr<HandsFreeAudioGatewayObserver> observer) {
            observer->OnHfpStackChanged(remoteDevice, action);
        });
    }

    void OnVirtualDeviceChanged(int32_t action, std::string address) override
    {
        HILOGI("enter, device: %{public}s, action: %{public}d", GetEncryptAddr(address).c_str(), action);
        observers_.ForEach([action, address](std::shared_ptr<HandsFreeAudioGatewayObserver> observer) {
            observer->OnVirtualDeviceChanged(action, address);
        });
    }

private:
    BluetoothObserverList<HandsFreeAudioGatewayObserver> &observers_;
    BLUETOOTH_DISALLOW_COPY_AND_ASSIGN(AgServiceObserver);
};

std::string HfpAgServiceName = "bluetooth-hfp-ag-server";

struct HandsFreeAudioGateway::impl {
    impl();
    ~impl();

    int32_t GetConnectedDevices(std::vector<BluetoothRemoteDevice>& devices)
    {
        HILOGD("enter");
        sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
        CHECK_AND_RETURN_LOG_RET(proxy != nullptr, BT_ERR_SERVICE_DISCONNECTED, "failed: no proxy");
        std::vector<BluetoothRawAddress> ori;
        int32_t ret = proxy->GetConnectDevices(ori);
        if (ret != BT_NO_ERROR) {
            HILOGE("inner error.");
            return ret;
        }
        for (auto it = ori.begin(); it != ori.end(); it++) {
            devices.push_back(BluetoothRemoteDevice(it->GetAddress(), 0));
        }
        return BT_NO_ERROR;
    }

    std::vector<BluetoothRemoteDevice> GetDevicesByStates(std::vector<int> states)
    {
        HILOGD("enter");
        std::vector<BluetoothRemoteDevice> remoteDevices;
        sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
        if (proxy != nullptr) {
            std::vector<BluetoothRawAddress> rawDevices;
            std::vector<int32_t> tmpstates;
            for (int state : states) {
                int32_t value = (int32_t)state;
                tmpstates.push_back(value);
            }
            proxy->GetDevicesByStates(tmpstates, rawDevices);
            for (BluetoothRawAddress rawDevice : rawDevices) {
                BluetoothRemoteDevice remoteDevice(rawDevice.GetAddress(), 0);
                remoteDevices.push_back(remoteDevice);
            }
        }
        return remoteDevices;
    }

    int32_t GetDeviceState(const BluetoothRemoteDevice &device, int32_t &state)
    {
        HILOGD("enter, device: %{public}s", GET_ENCRYPT_ADDR(device));
        sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
        if (proxy == nullptr || !device.IsValidBluetoothRemoteDevice()) {
            HILOGE("invalid param.");
            return BT_ERR_INVALID_PARAM;
        }

        return proxy->GetDeviceState(BluetoothRawAddress(device.GetDeviceAddr()), state);
    }

    int32_t Connect(const BluetoothRemoteDevice &device)
    {
        HILOGI("hfp connect remote device: %{public}s", GET_ENCRYPT_ADDR(device));
        sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
        if (proxy == nullptr || !device.IsValidBluetoothRemoteDevice()) {
            HILOGE("invalid param.");
            return BT_ERR_INVALID_PARAM;
        }
        return proxy->Connect(BluetoothRawAddress(device.GetDeviceAddr()));
    }

    int32_t Disconnect(const BluetoothRemoteDevice &device)
    {
        HILOGI("hfp disconnect remote device: %{public}s", GET_ENCRYPT_ADDR(device));
        sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
        if (proxy == nullptr || !device.IsValidBluetoothRemoteDevice()) {
            HILOGE("invalid param.");
            return BT_ERR_INVALID_PARAM;
        }
        return proxy->Disconnect(BluetoothRawAddress(device.GetDeviceAddr()));
    }

    int GetScoState(const BluetoothRemoteDevice &device)
    {
        HILOGI("enter, device: %{public}s", GET_ENCRYPT_ADDR(device));
        sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
        if (proxy != nullptr && IS_BT_ENABLED() && device.IsValidBluetoothRemoteDevice()) {
            return proxy->GetScoState(BluetoothRawAddress(device.GetDeviceAddr()));
        }
        return HFP_AG_SCO_STATE_DISCONNECTED;
    }

    int32_t ConnectSco(uint8_t callType)
    {
        sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
        CHECK_AND_RETURN_LOG_RET(proxy != nullptr, BT_ERR_INVALID_PARAM, "failed: no proxy");
        return proxy->ConnectSco(callType);
    }

    int32_t DisconnectSco(uint8_t callType)
    {
        sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
        CHECK_AND_RETURN_LOG_RET(proxy != nullptr, BT_ERR_INVALID_PARAM, "failed: no proxy");
        return proxy->DisconnectSco(callType);
    }

    bool ConnectSco()
    {
        HILOGD("enter");
        sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
        CHECK_AND_RETURN_LOG_RET(proxy != nullptr, false, "failed: no proxy");
        return proxy->ConnectSco();
    }

    bool DisconnectSco()
    {
        HILOGD("enter");
        sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
        CHECK_AND_RETURN_LOG_RET(proxy != nullptr, false, "failed: no proxy");
        return proxy->DisconnectSco();
    }

    bool IsValidCallType(uint8_t callType)
    {
        if (callType == static_cast<uint8_t>(BTCallType::CALL_TYPE_CELLULAR) ||
            callType == static_cast<uint8_t>(BTCallType::CALL_TYPE_VIRTUAL) ||
            callType == static_cast<uint8_t>(BTCallType::CALL_TYPE_RECOGNITION)) {
            return true;
        }
        return false;
    }

    void PhoneStateChanged(BluetoothPhoneState &phoneState)
    {
        HILOG_COMM_INFO("numActive: %{public}d, numHeld: %{public}d, callState: %{public}d, type: %{public}d",
            phoneState.GetActiveNum(), phoneState.GetHeldNum(), phoneState.GetCallState(), phoneState.GetCallType());
        sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
        CHECK_AND_RETURN_LOG(proxy != nullptr, "proxy is null");
        proxy->PhoneStateChanged(phoneState);
    }

    void ClccResponse(int index, int direction, int status, int mode, bool mpty, std::string number, int type)
    {
        HILOGI("enter, index: %{public}d, direction: %{public}d, status: %{public}d, mode: %{public}d, mpty: "
            "%{public}d, type: %{public}d", index, direction, status, mode, mpty, type);
        sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
        CHECK_AND_RETURN_LOG(proxy != nullptr, "proxy is null");
        proxy->ClccResponse(index, direction, status, mode, mpty, number, type);
    }

    bool OpenVoiceRecognition(const BluetoothRemoteDevice &device)
    {
        HILOG_COMM_INFO("enter, device: %{public}s", GET_ENCRYPT_ADDR(device));
        sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
        if (proxy != nullptr && device.IsValidBluetoothRemoteDevice()) {
            return proxy->OpenVoiceRecognition(BluetoothRawAddress(device.GetDeviceAddr()));
        }
        return false;
    }

    bool CloseVoiceRecognition(const BluetoothRemoteDevice &device)
    {
        HILOG_COMM_INFO("enter, device: %{public}s", GET_ENCRYPT_ADDR(device));
        sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
        if (proxy != nullptr && device.IsValidBluetoothRemoteDevice()) {
            return proxy->CloseVoiceRecognition(BluetoothRawAddress(device.GetDeviceAddr()));
        }
        return false;
    }

    int32_t IsAudioConnected(bool &isAudioOn)
    {
        HILOGI("enter");
        sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
        CHECK_AND_RETURN_LOG_RET(proxy != nullptr, BT_ERR_UNAVAILABLE_PROXY, "proxy is null");
        return proxy->IsAudioConnected(isAudioOn);
    }

    bool SetActiveDevice(const BluetoothRemoteDevice &device)
    {
        HILOGI("enter, device: %{public}s", GET_ENCRYPT_ADDR(device));
        sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
        if (proxy != nullptr && device.IsValidBluetoothRemoteDevice()) {
            return proxy->SetActiveDevice(BluetoothRawAddress(device.GetDeviceAddr()));
        }
        return false;
    }

    bool IntoMock(const BluetoothRemoteDevice &device, int state)
    {
        HILOGD("enter");
        sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
        if (proxy != nullptr && IS_BT_ENABLED()) {
            return proxy->IntoMock(BluetoothRawAddress(device.GetDeviceAddr()), state);
        }
        return false;
    }

    bool SendNoCarrier(const BluetoothRemoteDevice &device)
    {
        HILOGD("enter");
        sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
        if (proxy != nullptr && IS_BT_ENABLED() && device.IsValidBluetoothRemoteDevice()) {
            return proxy->SendNoCarrier(BluetoothRawAddress(device.GetDeviceAddr()));
        }
        return false;
    }

    BluetoothRemoteDevice GetActiveDevice()
    {
        HILOGD("enter");
        BluetoothRemoteDevice device;
        sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
        if (proxy != nullptr) {
            std::string address = proxy->GetActiveDevice();
            BluetoothRemoteDevice remoteDevice(address, 0);
            device = remoteDevice;
        }
        return device;
    }

    int SetConnectStrategy(const BluetoothRemoteDevice &device, int strategy)
    {
        HILOGD("enter");
        sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
        CHECK_AND_RETURN_LOG_RET(proxy != nullptr, BT_ERR_UNAVAILABLE_PROXY, "proxy is null");
        return proxy->SetConnectStrategy(BluetoothRawAddress(device.GetDeviceAddr()), strategy);
    }

    int GetConnectStrategy(const BluetoothRemoteDevice &device, int &strategy) const
    {
        HILOGD("enter");
        sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
        CHECK_AND_RETURN_LOG_RET(proxy != nullptr, BT_ERR_UNAVAILABLE_PROXY, "proxy is null");
        return proxy->GetConnectStrategy(BluetoothRawAddress(device.GetDeviceAddr()), strategy);
    }

    int IsInbandRingingEnabled(bool &isEnabled) const
    {
        HILOGD("enter");
        sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
        CHECK_AND_RETURN_LOG_RET(proxy != nullptr, BT_ERR_UNAVAILABLE_PROXY, "proxy is null");
        return proxy->IsInbandRingingEnabled(isEnabled);
    }

    void CallDetailsChanged(int callId, int callState)
    {
        HILOGD("enter");
        sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
        CHECK_AND_RETURN_LOG(proxy != nullptr, "proxy is null");
        proxy->CallDetailsChanged(callId, callState);
    }

    int IsVgsSupported(const BluetoothRemoteDevice &device, bool &isSupported) const
    {
        HILOGD("enter");
        sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
        CHECK_AND_RETURN_LOG_RET(proxy != nullptr, BT_ERR_UNAVAILABLE_PROXY, "proxy is null");
        return proxy->IsHfpFeatureSupported(BluetoothRawAddress(device.GetDeviceAddr()), isSupported,
            static_cast<int>(bluetooth::HfpFeatureType::VGS));
    }

    void EnableBtCallLog(bool state)
    {
        HILOGD("enter");
        sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
        CHECK_AND_RETURN_LOG(proxy != nullptr, "proxy is null");
        proxy->EnableBtCallLog(state);
    }

    void RegisterObserver(std::shared_ptr<HandsFreeAudioGatewayObserver> observer)
    {
        HILOGD("enter");
        observers_.Register(observer);
    }

    void DeregisterObserver(std::shared_ptr<HandsFreeAudioGatewayObserver> observer)
    {
        HILOGD("enter");
        observers_.Deregister(observer);
        HILOGI("end");
    }

    int IsVoiceRecognitionSupported(const BluetoothRemoteDevice &device, bool &isSupported) const
    {
        HILOGD("enter");
        sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
        CHECK_AND_RETURN_LOG_RET(proxy != nullptr, BT_ERR_UNAVAILABLE_PROXY, "proxy is null");
        return proxy->IsHfpFeatureSupported(BluetoothRawAddress(device.GetDeviceAddr()), isSupported,
            static_cast<int>(bluetooth::HfpFeatureType::VOICE_RECOGNITION));
    }

    int GetCurrentCallType(int &callType)
    {
        HILOGD("enter");
        sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
        CHECK_AND_RETURN_LOG_RET(proxy != nullptr, BT_ERR_UNAVAILABLE_PROXY, "proxy is null");
        return proxy->GetCurrentCallType(callType);
    }

    int32_t profileRegisterId = 0;
private:
    const static int HFP_AG_SLC_STATE_DISCONNECTED = static_cast<int>(BTConnectState::DISCONNECTED);
    const static int HFP_AG_SCO_STATE_DISCONNECTED = 3;

    BluetoothObserverList<HandsFreeAudioGatewayObserver> observers_;
    sptr<AgServiceObserver> serviceObserver_;
};

HandsFreeAudioGateway::impl::impl()
{
    serviceObserver_ = new AgServiceObserver(observers_);
    profileRegisterId = BluetoothProfileManager::GetInstance().RegisterFunc(PROFILE_HFP_AG,
        [this](sptr<IRemoteObject> remote) {
        sptr<IBluetoothHfpAg> proxy = iface_cast<IBluetoothHfpAg>(remote);
        CHECK_AND_RETURN_LOG(proxy != nullptr, "failed: no proxy");
        proxy->RegisterObserver(serviceObserver_);
    });
}

HandsFreeAudioGateway::impl::~impl()
{
    HILOGD("enter");
    BluetoothProfileManager::GetInstance().DeregisterFunc(profileRegisterId);
    sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
    CHECK_AND_RETURN_LOG(proxy != nullptr, "failed: no proxy");
    proxy->DeregisterObserver(serviceObserver_);
}

HandsFreeAudioGateway *HandsFreeAudioGateway::GetProfile()
{
    HILOGD("enter");
#ifdef DTFUZZ_TEST
    static BluetoothNoDestructor<HandsFreeAudioGateway> instance;
    return instance.get();
#else
    static HandsFreeAudioGateway instance;
    return &instance;
#endif
}

HandsFreeAudioGateway::HandsFreeAudioGateway()
{
    HILOGD("enter");
    pimpl = std::make_unique<impl>();
}

HandsFreeAudioGateway::~HandsFreeAudioGateway()
{
    HILOGD("enter");
}

std::vector<BluetoothRemoteDevice> HandsFreeAudioGateway::GetConnectedDevices() const
{
    std::vector<BluetoothRemoteDevice> devices;
    if (!IS_BT_ENABLED()) {
        HILOGE("bluetooth is off.");
        return devices;
    }
    sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
    CHECK_AND_RETURN_LOG_RET(proxy != nullptr, devices, "failed: no proxy");

    pimpl->GetConnectedDevices(devices);
    return devices;
}

int32_t HandsFreeAudioGateway::GetConnectedDevices(std::vector<BluetoothRemoteDevice> &devices)
{
    if (!IS_BT_ENABLED()) {
        HILOGE("bluetooth is off.");
        return BT_ERR_INVALID_STATE;
    }

    sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
    CHECK_AND_RETURN_LOG_RET(proxy != nullptr, BT_ERR_UNAVAILABLE_PROXY, "failed: no proxy");

    return pimpl->GetConnectedDevices(devices);
}

std::vector<BluetoothRemoteDevice> HandsFreeAudioGateway::GetDevicesByStates(std::vector<int> states)
{
    if (!IS_BT_ENABLED()) {
        HILOGE("bluetooth is off.");
        return std::vector<BluetoothRemoteDevice>();
    }
    sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
    CHECK_AND_RETURN_LOG_RET(proxy != nullptr, std::vector<BluetoothRemoteDevice>(), "failed: no proxy");

    return pimpl->GetDevicesByStates(states);
}

int32_t HandsFreeAudioGateway::GetDeviceState(const BluetoothRemoteDevice &device, int32_t &state)
{
    HILOGD("enter, device: %{public}s", GET_ENCRYPT_ADDR(device));
    if (!IS_BT_ENABLED()) {
        HILOGE("bluetooth is off.");
        return BT_ERR_INVALID_STATE;
    }

    sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
    CHECK_AND_RETURN_LOG_RET(proxy != nullptr, BT_ERR_UNAVAILABLE_PROXY, "failed: no proxy");

    return pimpl->GetDeviceState(device, state);
}

int32_t HandsFreeAudioGateway::Connect(const BluetoothRemoteDevice &device)
{
    HILOGI("enter, device: %{public}s", GET_ENCRYPT_ADDR(device));
    if (!IS_BT_ENABLED()) {
        HILOGE("bluetooth is off.");
        return BT_ERR_INVALID_STATE;
    }

    sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
    CHECK_AND_RETURN_LOG_RET(proxy != nullptr, BT_ERR_UNAVAILABLE_PROXY, "failed: no proxy");

    return pimpl->Connect(device);
}

int32_t HandsFreeAudioGateway::Disconnect(const BluetoothRemoteDevice &device)
{
    HILOGI("enter, device: %{public}s", GET_ENCRYPT_ADDR(device));
    if (!IS_BT_ENABLED()) {
        HILOGE("bluetooth is off.");
        return BT_ERR_INVALID_STATE;
    }
    sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
    CHECK_AND_RETURN_LOG_RET(proxy != nullptr, BT_ERR_UNAVAILABLE_PROXY, "failed: no proxy");

    return pimpl->Disconnect(device);
}

int HandsFreeAudioGateway::GetScoState(const BluetoothRemoteDevice &device) const
{
    HILOGI("enter, device: %{public}s", GET_ENCRYPT_ADDR(device));
    if (!IS_BT_ENABLED()) {
        HILOGE("bluetooth is off.");
        return static_cast<int>(HfpScoConnectState::SCO_DISCONNECTED);
    }
    sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
    CHECK_AND_RETURN_LOG_RET(proxy != nullptr,
        static_cast<int>(HfpScoConnectState::SCO_DISCONNECTED), "failed: no proxy");

    return pimpl->GetScoState(device);
}

int32_t HandsFreeAudioGateway::ConnectSco(uint8_t callType)
{
    HILOGI("enter, callType: %{public}d", callType);
    CHECK_AND_RETURN_LOG_RET(IS_BT_ENABLED(), BT_ERR_INVALID_STATE, "bluetooth is off.");
    sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
    CHECK_AND_RETURN_LOG_RET(proxy != nullptr, BT_ERR_UNAVAILABLE_PROXY,
        "hfpAG proxy is nullptr.");
    CHECK_AND_RETURN_LOG_RET((pimpl->IsValidCallType(callType)), BT_ERR_INVALID_PARAM,
        "connect sco call type error.");
    return pimpl->ConnectSco(callType);
}

int32_t HandsFreeAudioGateway::DisconnectSco(uint8_t callType)
{
    HILOGI("enter, callType: %{public}d", callType);
    CHECK_AND_RETURN_LOG_RET(IS_BT_ENABLED(), BT_ERR_INVALID_STATE, "bluetooth is off.");
    sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
    CHECK_AND_RETURN_LOG_RET(proxy != nullptr, BT_ERR_UNAVAILABLE_PROXY,
        "hfpAG proxy is nullptr.");
    CHECK_AND_RETURN_LOG_RET((pimpl->IsValidCallType(callType)), BT_ERR_INVALID_PARAM,
        "disconnect sco call type error.");
    return pimpl->DisconnectSco(callType);
}

bool HandsFreeAudioGateway::ConnectSco()
{
    return true;
}

bool HandsFreeAudioGateway::DisconnectSco()
{
    return true;
}

void HandsFreeAudioGateway::PhoneStateChanged(
    int numActive, int numHeld, int callState, const std::string &number, int type, const std::string &name)
{
    CHECK_AND_RETURN_LOG(IS_BT_ENABLED(), "bluetooth is off.");
    sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
    CHECK_AND_RETURN_LOG(proxy != nullptr, "hfpAG proxy is nullptr.");

    BluetoothPhoneState phoneState;
    phoneState.SetActiveNum(numActive);
    phoneState.SetHeldNum(numHeld);
    phoneState.SetCallState(callState);
    phoneState.SetNumber(number);
    phoneState.SetCallType(type);
    phoneState.SetName(name);
    pimpl->PhoneStateChanged(phoneState);
}

void HandsFreeAudioGateway::ClccResponse(
    int index, int direction, int status, int mode, bool mpty, const std::string &number, int type)
{
    if (!IS_BT_ENABLED()) {
        HILOGE("bluetooth is off.");
        return;
    }

    sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
    CHECK_AND_RETURN_LOG(proxy != nullptr, "failed: no proxy");

    pimpl->ClccResponse(index, direction, status, mode, mpty, number, type);
}

bool HandsFreeAudioGateway::OpenVoiceRecognition(const BluetoothRemoteDevice &device)
{
    HILOG_COMM_INFO("OpenVoiceRecognition: %{public}s", GET_ENCRYPT_ADDR(device));
    if (!IS_BT_ENABLED()) {
        HILOGE("bluetooth is off.");
        return false;
    }

    sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
    CHECK_AND_RETURN_LOG_RET(proxy != nullptr, false, "failed: no proxy");

    return pimpl->OpenVoiceRecognition(device);
}

bool HandsFreeAudioGateway::CloseVoiceRecognition(const BluetoothRemoteDevice &device)
{
    HILOG_COMM_INFO("CloseVoiceRecognition: %{public}s", GET_ENCRYPT_ADDR(device));
    if (!IS_BT_ENABLED()) {
        HILOGE("bluetooth is off.");
        return false;
    }

    sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
    CHECK_AND_RETURN_LOG_RET(proxy != nullptr, false, "failed: no proxy");

    return pimpl->CloseVoiceRecognition(device);
}

int32_t HandsFreeAudioGateway::IsAudioConnected(bool &isAudioOn)
{
    if (!IS_BT_ENABLED()) {
        HILOGE("bluetooth is off.");
        return BT_ERR_INVALID_STATE;
    }

    sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
    CHECK_AND_RETURN_LOG_RET(proxy != nullptr, BT_ERR_UNAVAILABLE_PROXY, "failed: no proxy");

    return pimpl->IsAudioConnected(isAudioOn);
}

bool HandsFreeAudioGateway::SetActiveDevice(const BluetoothRemoteDevice &device)
{
    if (!IS_BT_ENABLED()) {
        HILOGE("bluetooth is off.");
        return false;
    }

    sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
    CHECK_AND_RETURN_LOG_RET(proxy != nullptr, false, "failed: no proxy");
    std::string currentAddress = pimpl->GetActiveDevice().GetDeviceAddr();
    std::string address = device.GetDeviceAddr();
    if (currentAddress.empty() && (address == NULL_ADDRESS || address == EMPTY_ADDRESS)) {
        HILOGD("targetDevice is nullptr");
        return true;
    }
    if (currentAddress == address) {
        HILOGD("same device: %{public}s", GET_ENCRYPT_ADDR(device));
        return true;
    }
    return pimpl->SetActiveDevice(device);
}

BluetoothRemoteDevice HandsFreeAudioGateway::GetActiveDevice() const
{
    BluetoothRemoteDevice device;
    if (!IS_BT_ENABLED()) {
        HILOGE("bluetooth is off.");
        return device;
    }

    sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
    CHECK_AND_RETURN_LOG_RET(proxy != nullptr, device, "failed: no proxy");

    device = pimpl->GetActiveDevice();
    return device;
}

int HandsFreeAudioGateway::SetConnectStrategy(const BluetoothRemoteDevice &device, int strategy)
{
    HILOGI("enter, device: %{public}s, strategy: %{public}d", GET_ENCRYPT_ADDR(device), strategy);
    if (!IS_BT_ENABLED()) {
        HILOGE("bluetooth is off.");
        return BT_ERR_INVALID_STATE;
    }

    sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
    CHECK_AND_RETURN_LOG_RET(proxy != nullptr, BT_ERR_UNAVAILABLE_PROXY, "failed: no proxy");

    if ((!device.IsValidBluetoothRemoteDevice()) || (
        (strategy != static_cast<int>(BTStrategyType::CONNECTION_ALLOWED)) &&
        (strategy != static_cast<int>(BTStrategyType::CONNECTION_FORBIDDEN)))) {
        HILOGI("input parameter error.");
        return BT_ERR_INVALID_PARAM;
    }
    return pimpl->SetConnectStrategy(device, strategy);
}

int HandsFreeAudioGateway::GetConnectStrategy(const BluetoothRemoteDevice &device, int &strategy) const
{
    HILOGI("enter, device: %{public}s", GET_ENCRYPT_ADDR(device));
    if (!IS_BT_ENABLED()) {
        HILOGE("bluetooth is off.");
        return BT_ERR_INVALID_STATE;
    }

    sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
    CHECK_AND_RETURN_LOG_RET(proxy != nullptr, BT_ERR_UNAVAILABLE_PROXY, "failed: no proxy");

    if (!device.IsValidBluetoothRemoteDevice()) {
        HILOGI("input parameter error.");
        return BT_ERR_INVALID_PARAM;
    }
    return pimpl->GetConnectStrategy(device, strategy);
}

int HandsFreeAudioGateway::IsInbandRingingEnabled(bool &isEnabled) const
{
    HILOGI("enter");
    CHECK_AND_RETURN_LOG_RET(IS_BT_ENABLED(), BT_ERR_INVALID_STATE, "bluetooth is off.");
    sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
    CHECK_AND_RETURN_LOG_RET(proxy != nullptr, BT_ERR_INTERNAL_ERROR, "hfpAG proxy is nullptr");
    return pimpl->IsInbandRingingEnabled(isEnabled);
}

void HandsFreeAudioGateway::CallDetailsChanged(int callId, int callState)
{
    HILOGI("enter, callId: %{public}d, callState: %{public}d", callId, callState);
    CHECK_AND_RETURN_LOG(IS_BT_ENABLED(), "bluetooth is off.");
    sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
    CHECK_AND_RETURN_LOG(proxy != nullptr, "hfpAG proxy is nullptr");
    pimpl->CallDetailsChanged(callId, callState);
}

void HandsFreeAudioGateway::EnableBtCallLog(bool state)
{
    HILOGI("enter");
    CHECK_AND_RETURN_LOG(IS_BT_ENABLED(), "bluetooth is off.");
    pimpl->EnableBtCallLog(state);
}

int HandsFreeAudioGateway::IsVgsSupported(const BluetoothRemoteDevice &device, bool &isSupported) const
{
    HILOGI("enter, device: %{public}s", GET_ENCRYPT_ADDR(device));
    CHECK_AND_RETURN_LOG_RET(IS_BT_ENABLED(), BT_ERR_INVALID_STATE, "bluetooth is off.");
    sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
    CHECK_AND_RETURN_LOG_RET(proxy != nullptr, BT_ERR_UNAVAILABLE_PROXY, "failed: no proxy");
    CHECK_AND_RETURN_LOG_RET(device.IsValidBluetoothRemoteDevice(), BT_ERR_INVALID_PARAM, "input parameter error.");
    return pimpl->IsVgsSupported(device, isSupported);
}

void HandsFreeAudioGateway::GetVirtualDeviceList(std::vector<std::string> &devices) const
{
    CHECK_AND_RETURN_LOG(IS_BT_ENABLED(), "bluetooth is off.");
    sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
    CHECK_AND_RETURN_LOG(proxy != nullptr, "hfpAG proxy is nullptr");
    proxy->GetVirtualDeviceList(devices);
}

void HandsFreeAudioGateway::RegisterObserver(std::shared_ptr<HandsFreeAudioGatewayObserver> observer)
{
    HILOGD("enter");
    CHECK_AND_RETURN_LOG(pimpl != nullptr, "pimpl is null.");
    CHECK_AND_RETURN_LOG(observer != nullptr, "observer is null.");
    pimpl->RegisterObserver(observer);
}

void HandsFreeAudioGateway::DeregisterObserver(std::shared_ptr<HandsFreeAudioGatewayObserver> observer)
{
    HILOGD("enter");
    CHECK_AND_RETURN_LOG(pimpl != nullptr, "pimpl is null.");
    pimpl->DeregisterObserver(observer);
}

int HandsFreeAudioGateway::GetCurrentCallType(int &callType)
{
    HILOGD("enter");
    sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
    CHECK_AND_RETURN_LOG_RET(proxy != nullptr, BT_ERR_UNAVAILABLE_PROXY, "failed: no proxy");
    return proxy->GetCurrentCallType(callType);
}

int HandsFreeAudioGateway::IsVoiceRecognitionSupported(const BluetoothRemoteDevice &device, bool &isSupported) const
{
    HILOGI("enter, device: %{public}s", GET_ENCRYPT_ADDR(device));
    CHECK_AND_RETURN_LOG_RET(IS_BT_ENABLED(), BT_ERR_INVALID_STATE, "bluetooth is off.");
    sptr<IBluetoothHfpAg> proxy = GetRemoteProxy<IBluetoothHfpAg>(PROFILE_HFP_AG);
    CHECK_AND_RETURN_LOG_RET(proxy != nullptr, BT_ERR_UNAVAILABLE_PROXY, "proxy is null");
    CHECK_AND_RETURN_LOG_RET(device.IsValidBluetoothRemoteDevice(), BT_ERR_INVALID_PARAM, "input parameter error.");
    return proxy->IsHfpFeatureSupported(BluetoothRawAddress(device.GetDeviceAddr()), isSupported,
        static_cast<int>(bluetooth::HfpFeatureType::VOICE_RECOGNITION));
}
}  // namespace Bluetooth
}  // namespace OHOS