/*
 * Copyright (C) 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.
 */

#ifndef VIDEO_DECODER_H
#define VIDEO_DECODER_H

#include <atomic>
#include <map>
#include <shared_mutex>
#include <fstream>
#include <vector>
#include "block_queue.h"
#include "codecbase.h"
#include "render_surface.h"

namespace OHOS {
namespace MediaAVCodec {
namespace Codec {

typedef signed char INT8;
typedef signed int INT32;
typedef unsigned char UINT8;
typedef unsigned int UINT32;
typedef unsigned long long UINT64;
using AVBuffer = Media::AVBuffer;
using AVAllocator = Media::AVAllocator;
using AVAllocatorFactory = Media::AVAllocatorFactory;
using MemoryFlag = Media::MemoryFlag;
using FormatDataType = Media::FormatDataType;

class VideoDecoder : public RenderSurface, public CodecBase {
public:
    explicit VideoDecoder(const std::string &name);
    ~VideoDecoder() = default;

    int32_t Init(Media::Meta &callerInfo) override;
    int32_t Start() override;
    int32_t Stop() override;
    int32_t Flush() override;
    int32_t Reset() override;
    int32_t Release() override;
    int32_t SetParameter(const Format &format) override;
    int32_t GetOutputFormat(Format &format) override;
    int32_t QueueInputBuffer(uint32_t index) override;
    int32_t ReleaseOutputBuffer(uint32_t index) override;
    int32_t SetCallback(const std::shared_ptr<MediaCodecCallback> &callback) override;
    int32_t NotifyMemoryRecycle() override;
    int32_t NotifyMemoryWriteBack() override;
    int32_t Configure(const Format &format) override;

    virtual void ConfigurelWidthAndHeight(const Format &format, const std::string_view &formatKey, bool isWidth) = 0;
    void ConfigureDefaultVal(const Format &format, const std::string_view &formatKey, int32_t minVal = 0,
        int32_t maxVal = INT_MAX);
    virtual void ConfigureHdrMetadata(const Format &format);
    int32_t SetOutputSurface(sptr<Surface> surface) override;
    int32_t RenderOutputBuffer(uint32_t index) override;
    int32_t CheckFormatChange(uint32_t index, int width, int height, int bitDepth);

    virtual int32_t CreateDecoder() = 0;
    virtual void DeleteDecoder() = 0;
    bool IsValid() const { return isValid_; }
    void ReleaseResource();
    void FramePostProcess(const std::shared_ptr<CodecBuffer> &frameBuffer, uint32_t index, int32_t status);
    int32_t FillFrameBuffer(const std::shared_ptr<CodecBuffer> &frameBuffer);
    void ResetData();
    int32_t UpdateOutputBuffer(uint32_t index);
    int32_t UpdateSurfaceMemory(uint32_t index);
    int32_t GetSurfaceBufferStride(const std::shared_ptr<CodecBuffer> &frameBuffer);
    virtual void FlushAllFrames() {};
    virtual void FillHdrInfo(sptr<SurfaceBuffer> surfaceBuffer) {};
    
#ifdef BUILD_ENG_VERSION
    void OpenDumpFile();
    void DumpOutputBuffer(int32_t bitDepth = BITS_PER_PIXEL_COMPONENT_8);
    void DumpConvertOut(struct SurfaceInfo &surfaceInfo);
#endif

    static std::mutex decoderCountMutex_;
    static std::vector<uint32_t> freeIDSet_;
    uint32_t decInstanceID_ = 0;
    static std::vector<uint32_t> decInstanceIDSet_;
    void* handle_ = nullptr;
    std::string codecName_;
    bool isValid_ = true;
    std::shared_ptr<MediaCodecCallback> callback_;
    bool isOutBufSetted_ = false;
    std::mutex decRunMutex_;
    std::mutex convertDataMutex_;
    std::string decName_;
    CallerInfo decInfo_;
    std::shared_ptr<TaskThread> sendTask_ = nullptr;
    std::shared_ptr<AVFrame> cachedFrame_ = nullptr;
    std::atomic<bool> isSendEos_ = false;
    std::shared_ptr<BlockQueue<uint32_t>> inputAvailQue_;
    std::shared_ptr<Scale> scale_ = nullptr;
#ifdef BUILD_ENG_VERSION
    std::shared_ptr<std::ofstream> dumpInFile_ = nullptr;
    std::shared_ptr<std::ofstream> dumpOutFile_ = nullptr;
    std::shared_ptr<std::ofstream> dumpConvertFile_ = nullptr;
#endif

protected:
    virtual void ConfigureOutPutOrder(bool isDisplay) {};
    virtual void ConfigureHdrColorSpaceIno(const Format &format) {};
    virtual void ConfigureHdrStaticMetadata(const Format &format) {};
    void CallCallBack(AVCodecErrorType errType, AVCodecServiceErrCode serEcode) override;
    int32_t inputBufferSize_ = 0;
    std::atomic<bool> isValidHdrSttMd_ = false;

private:
    virtual int32_t Initialize() = 0;
    bool IsActive() const;
    virtual void CalculateBufferSize();
    virtual int32_t GetDecoderWidthStride(void) { return width_; }
    int32_t AllocateBuffers();
    void InitBuffers();
    void ResetBuffers();
    void ReleaseBuffers();
    void StopThread();
    virtual void SendFrame() = 0;
    int32_t AllocateInputBuffer(int32_t bufferCnt, int32_t inBufferSize);
    int32_t AllocateOutputBuffer(int32_t bufferCnt);
    int32_t AllocateOutputBuffersFromSurface(int32_t bufferCnt);
    void SetSurfaceParameter();
    int32_t Detach(sptr<SurfaceBuffer> surfaceBuffer);
    virtual int32_t DecodeFrameOnce() = 0;
    virtual void InitParams() = 0;
    void SetCallerToBuffer(sptr<SurfaceBuffer> surfaceBuffer);
    void SetBufferCropMetadata(sptr<SurfaceBuffer> surfaceBuffer);
    void GetSurfaceCfgFromFmt(const Format &format);
    void ConfigureFormatHdr(const Format &format);

    int32_t inputBufferCnt_ = 0;
    uint8_t *scaleData_[AV_NUM_DATA_POINTERS] = {nullptr};
    int32_t scaleLineSize_[AV_NUM_DATA_POINTERS] = {0};
    bool isConverted_ = false;
    sptr<Surface> surface_ = nullptr;
    std::mutex renderBufferMapMutex_;
    std::atomic<bool> isBufferAllocated_ = false;
};

} // namespace Codec
} // namespace MediaAVCodec
} // namespace OHOS
#endif // VIDEO_DECODER_H