/*
 * Copyright (c) 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 "AudioRenderWrapper.h"
#include "AudioVividPlaybackManager.h"
#include <cstring>

AudioRenderWrapper::~AudioRenderWrapper()
{
    Release();
}

int32_t AudioRenderWrapper::Create(int32_t sampleRate, int32_t channelCount, int64_t channelLayout)
{
    sampleRate_ = sampleRate;
    channelCount_ = channelCount;
    channelLayout_ = channelLayout;
    int32_t ret = OH_AudioStreamBuilder_Create(&builder_, AUDIOSTREAM_TYPE_RENDERER);
    if (ret != 0 || builder_ == nullptr) {
        AVCODEC_SAMPLE_LOGE("Create AudioStreamBuilder failed");
        return -1;
    }
    OH_AudioStreamBuilder_SetLatencyMode(builder_, AUDIOSTREAM_LATENCY_MODE_NORMAL);
    OH_AudioStreamBuilder_SetSamplingRate(builder_, sampleRate_);
    OH_AudioStreamBuilder_SetChannelCount(builder_, channelCount_);
    OH_AudioStreamBuilder_SetSampleFormat(builder_, AUDIOSTREAM_SAMPLE_S24LE);
    OH_AudioStreamBuilder_SetRendererInfo(builder_, AUDIOSTREAM_USAGE_MUSIC);
    OH_AudioStreamBuilder_SetChannelLayout(builder_, static_cast<OH_AudioChannelLayout>(channelLayout_));
    OH_AudioStreamBuilder_SetEncodingType(builder_, AUDIOSTREAM_ENCODING_TYPE_AUDIOVIVID);
    ret = SetupCallbacks();
    if (ret != 0) {
        AVCODEC_SAMPLE_LOGE("SetupCallbacks failed");
        return ret;
    }
    ret = OH_AudioStreamBuilder_GenerateRenderer(builder_, &renderer_);
    if (ret != 0 || renderer_ == nullptr) {
        AVCODEC_SAMPLE_LOGE("GenerateRenderer failed");
        return -1;
    }
    return 0;
}

int32_t AudioRenderWrapper::SetupCallbacks()
{
    OH_AudioRenderer_Callbacks callbacks;
    callbacks.OH_AudioRenderer_OnWriteData = nullptr;
    callbacks.OH_AudioRenderer_OnStreamEvent = OnRenderStreamEventCallback;
    callbacks.OH_AudioRenderer_OnInterruptEvent = OnRenderInterruptEventCallback;
    callbacks.OH_AudioRenderer_OnError = OnRenderErrorCallback;
    int32_t ret = OH_AudioStreamBuilder_SetRendererCallback(builder_, callbacks, this);
    if (ret != 0) {
        AVCODEC_SAMPLE_LOGE("SetRendererCallback failed");
        return -1;
    }
    OH_AudioRenderer_WriteDataWithMetadataCallback metadataCallback = OnWriteDataWithMetadataCallback;
    ret = OH_AudioStreamBuilder_SetWriteDataWithMetadataCallback(builder_, metadataCallback, this);
    if (ret != 0) {
        AVCODEC_SAMPLE_LOGE("SetWriteDataWithMetadataCallback failed");
        return -1;
    }
    return 0;
}

int32_t AudioRenderWrapper::Start()
{
    if (renderer_ == nullptr) {
        AVCODEC_SAMPLE_LOGE("Renderer is null");
        return -1;
    }
    int32_t ret = OH_AudioRenderer_Start(renderer_);
    if (ret != 0) {
        AVCODEC_SAMPLE_LOGE("Start renderer failed, ret: %{public}d", ret);
        return -1;
    }
    context_.isStarted.store(true);
    context_.eos = false;
    AVCODEC_SAMPLE_LOGI("AudioRenderWrapper started");
    return 0;
}

int32_t AudioRenderWrapper::Stop()
{
    if (renderer_ == nullptr) {
        return -1;
    }
    context_.eos = true;
    context_.isStarted.store(false);
    int32_t ret = OH_AudioRenderer_Stop(renderer_);
    if (ret != 0) {
        AVCODEC_SAMPLE_LOGE("Stop renderer failed, ret: %{public}d", ret);
        return -1;
    }
    AVCODEC_SAMPLE_LOGI("AudioRenderWrapper stopped");
    return 0;
}

int32_t AudioRenderWrapper::Release()
{
    if (renderer_ != nullptr) {
        OH_AudioRenderer_Release(renderer_);
        renderer_ = nullptr;
    }
    if (builder_ != nullptr) {
        OH_AudioStreamBuilder_Destroy(builder_);
        builder_ = nullptr;
    }
    context_.eos = false;
    context_.errorCode = 0;
    context_.isStarted.store(false);
    return 0;
}

void AudioRenderWrapper::SetPlaybackManager(AudioVividPlaybackManager *playbackManager)
{
    playbackManager_ = playbackManager;
}

int32_t AudioRenderWrapper::OnWriteDataWithMetadataCallback(OH_AudioRenderer *renderer, void *userData, void *audioData,
    int32_t audioDataSize, void *metadata, int32_t metadataSize)
{
    (void)renderer;
    AudioRenderWrapper *wrapper = static_cast<AudioRenderWrapper *>(userData);
    if (wrapper->playbackManager_ == nullptr) {
        AVCODEC_SAMPLE_LOGE("PlaybackManager not set, cannot pull data");
        memset(audioData, 0, audioDataSize);
        if (metadata && metadataSize > 0) {
            memset(metadata, 0, metadataSize);
        }
        return 0;
    }
    uint8_t *pcmData = nullptr;
    int32_t pcmSize = 0;
    uint8_t *metadataData = nullptr;
    int32_t metadataSizeOut = 0;
    int32_t ret =
        wrapper->playbackManager_->GetDecodedDataToRender(&pcmData, &pcmSize, &metadataData, &metadataSizeOut);
    if (ret == 0 && pcmData != nullptr) {
        memcpy(audioData, pcmData, pcmSize);
        if (pcmSize < audioDataSize) {
            memset((uint8_t *)audioData + pcmSize, 0, audioDataSize - pcmSize);
        }
        if (metadata && metadataSize > 0 && metadataData != nullptr) {
            memcpy(metadata, metadataData, metadataSizeOut);
            if (metadataSizeOut < metadataSize) {
                memset((uint8_t *)metadata + metadataSizeOut, 0, metadataSize - metadataSizeOut);
            }
        }
        if (pcmData) {
            delete[] pcmData;
            pcmData = nullptr;
        }
        if (metadataData) {
            delete[] metadataData;
            metadataData = nullptr;
        }
    } else {
        memset(audioData, 0, audioDataSize);
        if (metadata && metadataSize > 0) {
            memset(metadata, 0, metadataSize);
        }
    }
    return 0;
}

int32_t AudioRenderWrapper::OnRenderStreamEventCallback(
    OH_AudioRenderer *renderer, void *userData, OH_AudioStream_Event event)
{
    (void)renderer;
    (void)userData;
    (void)event;
    return 0;
}

int32_t AudioRenderWrapper::OnRenderInterruptEventCallback(
    OH_AudioRenderer *renderer, void *userData, OH_AudioInterrupt_ForceType type, OH_AudioInterrupt_Hint hint)
{
    (void)renderer;
    (void)userData;
    (void)type;
    (void)hint;
    return 0;
}

int32_t AudioRenderWrapper::OnRenderErrorCallback(
    OH_AudioRenderer *renderer, void *userData, OH_AudioStream_Result error)
{
    (void)renderer;
    (void)userData;
    (void)error;
    return 0;
}