/*
 * Copyright (c) 2022-2025 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 "daudio_manager_callback.h"

#include <string>
#include <hdf_base.h>
#include <cstdlib>
#include "iservice_registry.h"
#include "iservmgr_hdi.h"
#include "iproxy_broker.h"

#include "daudio_constants.h"
#include "daudio_errorcode.h"
#include "daudio_hdi_handler.h"
#include "daudio_hitrace.h"
#include "daudio_log.h"
#include "daudio_radar.h"
#include "daudio_util.h"

#undef DH_LOG_TAG
#define DH_LOG_TAG "DAudioHdiHandler"

namespace OHOS {
namespace DistributedHardware {
FWK_IMPLEMENT_SINGLE_INSTANCE(DAudioHdiHandler);

DAudioHdiHandler::DAudioHdiHandler()
{
    DHLOGD("Distributed audio hdi handler construct.");
    audioHdiRecipient_ = sptr<AudioHdiRecipient>(new AudioHdiRecipient());
}

DAudioHdiHandler::~DAudioHdiHandler()
{
    DHLOGD("Distributed audio hdi handler deconstructed.");
}

int32_t DAudioHdiHandler::InitHdiHandler()
{
    DHLOGI("Init hdi handler.");
    if (audioSrvHdf_ != nullptr) {
        return DH_SUCCESS;
    }

    DHLOGD("Load hdf driver start.");
    auto dHFwkKit = GetDHFwkKit();
    CHECK_NULL_RETURN(dHFwkKit, ERR_DH_AUDIO_NULLPTR);
    int32_t ret = dHFwkKit->LoadDistributedHDF(DHType::AUDIO);
    DaudioRadar::GetInstance().ReportDaudioInit("LoadDaudioHDFImpl", AudioInit::LOAD_HDF_DRIVER,
        BizState::BIZ_STATE_END, ret);
    if (ret != DH_SUCCESS) {
        DHLOGE("Load hdf driver failed, ret: %{public}d", ret);
        return ret;
    }
    DHLOGI("Load hdf driver end.");

    audioSrvHdf_ = IDAudioManager::Get(HDF_AUDIO_SERVICE_NAME.c_str(), false);
    CHECK_NULL_RETURN(audioSrvHdf_, ERR_DH_AUDIO_NULLPTR);
    remote_ = OHOS::HDI::hdi_objcast<IDAudioManager>(audioSrvHdf_);
    CHECK_NULL_RETURN(remote_, ERR_DH_AUDIO_NULLPTR);
    remote_->AddDeathRecipient(audioHdiRecipient_);
    DHLOGD("Init hdi handler success.");
    return DH_SUCCESS;
}

int32_t DAudioHdiHandler::UninitHdiHandler()
{
    DHLOGI("Unload hdf driver start.");
    CHECK_NULL_RETURN(remote_, ERR_DH_AUDIO_NULLPTR);
    remote_->RemoveDeathRecipient(audioHdiRecipient_);
    CHECK_NULL_RETURN(audioSrvHdf_, DH_SUCCESS);

    auto dHFwkKit = GetDHFwkKit();
    CHECK_NULL_RETURN(dHFwkKit, ERR_DH_AUDIO_NULLPTR);
    int32_t ret = dHFwkKit->UnLoadDistributedHDF(DHType::AUDIO);
    if (ret != DH_SUCCESS) {
        DHLOGE("Unload hdf driver failed, ret: %{public}d", ret);
        return ret;
    }
    DHLOGD("Uninit hdi handler success.");
    return DH_SUCCESS;
}

int32_t DAudioHdiHandler::RegisterAudioDevice(const std::string &devId, const int32_t dhId,
    const std::string &capability, const std::shared_ptr<IDAudioHdiCallback> &callbackObjParam)
{
    DHLOGI("Register audio device, adpname: %{public}s, dhId: %{public}d", GetAnonyString(devId).c_str(), dhId);
    CHECK_NULL_RETURN(audioSrvHdf_, ERR_DH_AUDIO_NULLPTR);
    std::string searchKey;
    switch (GetDevTypeByDHId(dhId)) {
        case AUDIO_DEVICE_TYPE_SPEAKER:
            searchKey = devId + "Speaker" + std::to_string(dhId);
            break;
        case AUDIO_DEVICE_TYPE_MIC:
            searchKey = devId + "Mic" + std::to_string(dhId);
            break;
        case AUDIO_DEVICE_TYPE_UNKNOWN:
        default:
            DHLOGE("Unknown audio device.");
            return ERR_DH_AUDIO_NOT_SUPPORT;
    }
    {
        std::lock_guard<std::mutex> devLck(devMapMtx_);
        auto call = mapAudioMgrCallback_.find(searchKey);
        if (call == mapAudioMgrCallback_.end()) {
            const sptr<DAudioManagerCallback> callbackptr(new DAudioManagerCallback(callbackObjParam));
            mapAudioMgrCallback_.emplace(searchKey, callbackptr);
        }
        auto dhIds = mapAudioMgrDhIds_.find(devId);
        if (dhIds != mapAudioMgrDhIds_.end()) {
            dhIds->second.insert(dhId);
        } else {
            std::set<int32_t> newDhIds;
            newDhIds.insert(dhId);
            mapAudioMgrDhIds_.emplace(devId, newDhIds);
        }
    }

    auto iter = mapAudioMgrCallback_.find(searchKey);
    if (iter != mapAudioMgrCallback_.end()) {
        int32_t res = audioSrvHdf_->RegisterAudioDevice(devId, dhId, capability, iter->second);
        if (res != HDF_SUCCESS) {
            DHLOGE("Call hdf proxy register failed, res: %{public}d", res);
            return ERR_DH_AUDIO_HDI_CALL_FAILED;
        }
    }
    return DH_SUCCESS;
}

int32_t DAudioHdiHandler::UnRegisterAudioDevice(const std::string &devId, const int32_t dhId)
{
    DHLOGI("Unregister audio device, adpname: %{public}s, dhId: %{public}d", GetAnonyString(devId).c_str(), dhId);
    CHECK_NULL_RETURN(audioSrvHdf_, ERR_DH_AUDIO_NULLPTR);
    int32_t res = audioSrvHdf_->UnRegisterAudioDevice(devId, dhId);
    DaudioRadar::GetInstance().ReportDaudioUnInitProgress("UnRegisterAudioDevice",
        AudioUnInit::UNLOAD_HDF_DRIVER, res);
    if (res != HDF_SUCCESS) {
        DHLOGE("Call hdf proxy unregister failed, res: %{public}d", res);
        return ERR_DH_AUDIO_HDI_CALL_FAILED;
    }

    {
        std::lock_guard<std::mutex> devLck(devMapMtx_);
        auto iter = mapAudioMgrDhIds_.find(devId);
        if (iter == mapAudioMgrDhIds_.end()) {
            DHLOGE("Can not find register devId. devId: %{public}s", GetAnonyString(devId).c_str());
            return ERR_DH_AUDIO_SA_UNREGISTERCALLBACK_NOT_FOUND;
        }

        iter->second.erase(dhId);
        if (iter->second.empty()) {
            mapAudioMgrDhIds_.erase(devId);
        }
    }
    return DH_SUCCESS;
}

void DAudioHdiHandler::ProcessEventMsg(const AudioEvent &audioEvent, DAudioEvent &newEvent)
{
    switch (audioEvent.type) {
        case AudioEventType::NOTIFY_OPEN_SPEAKER_RESULT:
            newEvent.type = AUDIO_EVENT_OPEN_SPK_RESULT;
            break;
        case AudioEventType::NOTIFY_CLOSE_SPEAKER_RESULT:
            newEvent.type = AUDIO_EVENT_CLOSE_SPK_RESULT;
            break;
        case AudioEventType::NOTIFY_OPEN_MIC_RESULT:
            newEvent.type = AUDIO_EVENT_OPEN_MIC_RESULT;
            break;
        case AudioEventType::NOTIFY_CLOSE_MIC_RESULT:
            newEvent.type = AUDIO_EVENT_CLOSE_MIC_RESULT;
            break;
        case AudioEventType::VOLUME_CHANGE:
            newEvent.type = AUDIO_EVENT_VOLUME_CHANGE;
            break;
        case AudioEventType::SPEAKER_CLOSED:
            newEvent.type = AUDIO_EVENT_SPK_CLOSED;
            break;
        case AudioEventType::MIC_CLOSED:
            newEvent.type = AUDIO_EVENT_MIC_CLOSED;
            break;
        case AudioEventType::AUDIO_FOCUS_CHANGE:
            newEvent.type = AUDIO_EVENT_FOCUS_CHANGE;
            break;
        case AudioEventType::AUDIO_RENDER_STATE_CHANGE:
            newEvent.type = AUDIO_EVENT_RENDER_STATE_CHANGE;
            break;
        case AudioEventType::NOTIFY_HDF_SPK_DUMP:
            newEvent.type = AUDIO_EVENT_SPK_DUMP;
            break;
        case AudioEventType::NOTIFY_HDF_MIC_DUMP:
            newEvent.type = AUDIO_EVENT_MIC_DUMP;
            break;
        default:
            DHLOGE("Unsupport audio event.");
            break;
    }
}

int32_t DAudioHdiHandler::NotifyEvent(const std::string &devId, const int32_t dhId,
    const int32_t streamId, const AudioEvent &audioEvent)
{
    DHLOGD("Notify event adpname: %{public}s, dhId: %{public}d, event type: %{public}d, event content: %{public}s.",
        GetAnonyString(devId).c_str(), dhId, audioEvent.type, audioEvent.content.c_str());
    DAudioEvent newEvent = {AUDIO_EVENT_UNKNOWN, audioEvent.content};
    ProcessEventMsg(audioEvent, newEvent);

    CHECK_NULL_RETURN(audioSrvHdf_, ERR_DH_AUDIO_NULLPTR);
    if (audioSrvHdf_->NotifyEvent(devId, dhId, streamId, newEvent) != HDF_SUCCESS) {
        DHLOGE("Call hdf proxy NotifyEvent failed.");
        return ERR_DH_AUDIO_HDI_CALL_FAILED;
    }
    return DH_SUCCESS;
}

std::shared_ptr<DistributedHardwareFwkKit> DAudioHdiHandler::GetDHFwkKit()
{
    if (dHFwkKit_ == nullptr) {
        std::lock_guard<std::mutex> lock(dHFwkKitMutex_);
        if (dHFwkKit_ == nullptr) {
            dHFwkKit_ = std::make_shared<DistributedHardwareFwkKit>();
        }
    }
    return dHFwkKit_;
}

void DAudioHdiHandler::AudioHdiRecipient::OnRemoteDied(const wptr<IRemoteObject> &remote)
{
    DHLOGE("Exit the current process remote died.");
    _Exit(0);
}
} // namespace DistributedHardware
} // namespace OHOS