/*
 * Copyright (c) 2021-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 "buffer/avbuffer_queue_producer_proxy.h"
#include "avbuffer_utils.h"
#include "common/log.h"

namespace {
constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_DOMAIN_FOUNDATION, "AVBufferQueueProducerProxy" };
constexpr int64_t MILLISECONDS_TO_MICROSECONDS = 1000;
}

namespace OHOS {
namespace Media {

#define ABQ_IPC_DEFINE_VARIABLES                                                  \
    MessageParcel arguments;                                                      \
    MessageParcel reply;                                                          \
    MessageOption option;                                                         \
    FALSE_RETURN_V(arguments.WriteInterfaceToken(GetDescriptor()),                \
        Status::ERROR_IPC_WRITE_INTERFACE_TOKEN)

#define ABQ_IPC_SEND_REQUEST(command)                                             \
    do {                                                                          \
        NZERO_RETURN_V(Remote()->SendRequest(command, arguments, reply, option),  \
            Status::ERROR_IPC_SEND_REQUEST);                                      \
        NOK_RETURN(static_cast<Status>(reply.ReadInt32()));                       \
    } while (0)


class AVBufferQueueProducerProxyImpl : public AVBufferQueueProducerProxy {
public:
    explicit AVBufferQueueProducerProxyImpl(const sptr<IRemoteObject>& object)
        : AVBufferQueueProducerProxy(object) { }
    ~AVBufferQueueProducerProxyImpl() override = default;
    AVBufferQueueProducerProxyImpl(const AVBufferQueueProducerProxyImpl&) = delete;
    AVBufferQueueProducerProxyImpl operator=(const AVBufferQueueProducerProxyImpl&) = delete;

    uint32_t GetQueueSize() override;
    Status SetQueueSize(uint32_t size) override;

    Status RequestBuffer(std::shared_ptr<AVBuffer>& outBuffer,
        const AVBufferConfig& config, int32_t timeoutMs) override;
    Status RequestBufferWaitUs(std::shared_ptr<AVBuffer>& outBuffer,
        const AVBufferConfig& config, int64_t timeoutUs) override;
    Status PushBuffer(const std::shared_ptr<AVBuffer>& inBuffer, bool available) override;
    Status ReturnBuffer(const std::shared_ptr<AVBuffer>& inBuffer, bool available) override;

    Status AttachBuffer(std::shared_ptr<AVBuffer>& inBuffer, bool isFilled) override;
    Status DetachBuffer(const std::shared_ptr<AVBuffer>& outBuffer) override;

    Status SetBufferFilledListener(sptr<IBrokerListener>& listener) override;
    Status RemoveBufferFilledListener(sptr<IBrokerListener>& listener) override;
    Status SetBufferAvailableListener(sptr<IProducerListener>& listener) override;
    Status Clear() override;
    Status ClearBufferIf(std::function<bool(const std::shared_ptr<AVBuffer> &)> pred) override;
private:
    static inline BrokerDelegator<AVBufferQueueProducerProxyImpl> delegator_;
};

std::shared_ptr<AVBufferQueueProducerProxy> AVBufferQueueProducerProxy::Create(const sptr<IRemoteObject>& object)
{
    FALSE_RETURN_V(object != nullptr, nullptr);
    return std::make_shared<AVBufferQueueProducerProxyImpl>(object);
}

AVBufferQueueProducerProxy::AVBufferQueueProducerProxy(const sptr<IRemoteObject>& object)
    : IRemoteProxy<AVBufferQueueProducer>(object) { }

uint32_t AVBufferQueueProducerProxyImpl::GetQueueSize()
{
    MessageParcel arguments;
    MessageParcel reply;
    MessageOption option;
    FALSE_RETURN_V(arguments.WriteInterfaceToken(GetDescriptor()), 0);
    NZERO_RETURN_V(Remote()->SendRequest(PRODUCER_GET_QUEUE_SIZE, arguments, reply, option), 0);

    return reply.ReadUint32();
}

Status AVBufferQueueProducerProxyImpl::SetQueueSize(uint32_t size)
{
    ABQ_IPC_DEFINE_VARIABLES;

    arguments.WriteUint32(size);

    ABQ_IPC_SEND_REQUEST(PRODUCER_SET_QUEUE_SIZE);

    return Status::OK;
}

Status AVBufferQueueProducerProxyImpl::RequestBuffer(std::shared_ptr<AVBuffer>& outBuffer,
                                                     const AVBufferConfig& config, int32_t timeoutMs)
{
    return RequestBufferWaitUs(outBuffer, config, static_cast<int64_t>(timeoutMs) * MILLISECONDS_TO_MICROSECONDS);
}

Status AVBufferQueueProducerProxyImpl::RequestBufferWaitUs(
    std::shared_ptr<AVBuffer> &outBuffer, const AVBufferConfig &config, int64_t timeoutUs)
{
    ABQ_IPC_DEFINE_VARIABLES;

    MarshallingConfig(arguments, config);

    ABQ_IPC_SEND_REQUEST(PRODUCER_REQUEST_BUFFER);

    outBuffer = AVBuffer::CreateAVBuffer();
    FALSE_RETURN_V(outBuffer != nullptr, Status::ERROR_CREATE_BUFFER);
    outBuffer->ReadFromMessageParcel(reply);

    return Status::OK;
}

Status AVBufferQueueProducerProxyImpl::PushBuffer(const std::shared_ptr<AVBuffer>& inBuffer, bool available)
{
    FALSE_RETURN_V(inBuffer != nullptr, Status::ERROR_NULL_POINT_BUFFER);

    ABQ_IPC_DEFINE_VARIABLES;

    arguments.WriteUint64(inBuffer->GetUniqueId());
    arguments.WriteBool(available);

    ABQ_IPC_SEND_REQUEST(PRODUCER_PUSH_BUFFER);

    return Status::OK;
}

Status AVBufferQueueProducerProxyImpl::ReturnBuffer(const std::shared_ptr<AVBuffer>& inBuffer, bool available)
{
    FALSE_RETURN_V(inBuffer != nullptr, Status::ERROR_NULL_POINT_BUFFER);

    ABQ_IPC_DEFINE_VARIABLES;

    arguments.WriteUint64(inBuffer->GetUniqueId());
    arguments.WriteBool(available);

    ABQ_IPC_SEND_REQUEST(PRODUCER_RETURN_BUFFER);

    return Status::OK;
}

Status AVBufferQueueProducerProxyImpl::AttachBuffer(std::shared_ptr<AVBuffer>& inBuffer, bool isFilled)
{
    FALSE_RETURN_V(inBuffer != nullptr, Status::ERROR_NULL_POINT_BUFFER);

    ABQ_IPC_DEFINE_VARIABLES;

    inBuffer->WriteToMessageParcel(arguments);
    arguments.WriteBool(isFilled);

    ABQ_IPC_SEND_REQUEST(PRODUCER_ATTACH_BUFFER);

    return Status::OK;
}

Status AVBufferQueueProducerProxyImpl::DetachBuffer(const std::shared_ptr<AVBuffer>& outBuffer)
{
    FALSE_RETURN_V(outBuffer != nullptr, Status::ERROR_NULL_POINT_BUFFER);

    ABQ_IPC_DEFINE_VARIABLES;

    arguments.WriteUint64(outBuffer->GetUniqueId());

    ABQ_IPC_SEND_REQUEST(PRODUCER_DETACH_BUFFER);

    return Status::OK;
}

Status AVBufferQueueProducerProxyImpl::SetBufferFilledListener(sptr<IBrokerListener>& listener)
{
    ABQ_IPC_DEFINE_VARIABLES;

    arguments.WriteRemoteObject(listener->AsObject());

    ABQ_IPC_SEND_REQUEST(PRODUCER_SET_FILLED_LISTENER);

    return Status::OK;
}

Status AVBufferQueueProducerProxyImpl::RemoveBufferFilledListener(sptr<IBrokerListener>& listener)
{
    ABQ_IPC_DEFINE_VARIABLES;
 
    arguments.WriteRemoteObject(listener->AsObject());
 
    ABQ_IPC_SEND_REQUEST(PRODUCER_REMOVE_FILLED_LISTENER);
 
    return Status::OK;
}

Status AVBufferQueueProducerProxyImpl::SetBufferAvailableListener(sptr<IProducerListener>& listener)
{
    ABQ_IPC_DEFINE_VARIABLES;

    arguments.WriteRemoteObject(listener->AsObject());

    ABQ_IPC_SEND_REQUEST(PRODUCER_SET_AVAILABLE_LISTENER);

    return Status::OK;
}

Status AVBufferQueueProducerProxyImpl::Clear()
{
    return Status::OK;
}

Status AVBufferQueueProducerProxyImpl::ClearBufferIf(std::function<bool(const std::shared_ptr<AVBuffer> &)> pred)
{
    return Status::OK;
}
} // namespace Media
} // namespace OHOS