#pragma once

#include <cstdint>
#include <deque>
#include <functional>
#include <mutex>
#include <string>
#include <vector>

struct VideoSample {
    std::vector<uint8_t> data;
    int64_t timestampUs;
    bool isKeyframe;
};

struct AudioSample {
    std::vector<uint8_t> data;
    int64_t timestampUs;
};

struct GopBuffer {
    std::vector<VideoSample> samples;
    int64_t startTimeUs = 0;
};

class ClipRecorder {
public:
    using ClipReadyCallback = std::function<void(const std::string& path)>;

    ClipRecorder() = default;
    ~ClipRecorder() = default;

    void Configure(int width, int height,
                   uint32_t audioSampleRate, uint32_t audioChannels,
                   int audioBitrate);

    void SetVideoFormat(const uint8_t* codecConfig, uint32_t size);
    void SetAudioFormat(const uint8_t* codecConfig, uint32_t size);

    void Start();
    void Stop();

    void FeedVideoPacket(const uint8_t* data, uint32_t size,
                         int64_t timestampUs, bool isKeyframe);
    void FeedAudioPacket(const uint8_t* data, uint32_t size,
                         int64_t timestampUs);

    bool FlushClip(const std::string& outputDir);

    void SetClipReadyCallback(ClipReadyCallback cb);

private:
    void TrimBuffers();

    std::mutex mutex;
    bool active = false;

    int videoWidth = 0;
    int videoHeight = 0;
    uint32_t sampleRate = 48000;
    uint32_t audioChannels = 2;
    int audioBitrate = 128000;

    std::vector<uint8_t> videoCodecConfig;
    std::vector<uint8_t> audioCodecConfig;

    std::deque<GopBuffer> gopBuffer;
    GopBuffer currentGop;

    std::deque<AudioSample> audioBuffer;

    ClipReadyCallback clipReadyCallback;

    static constexpr int64_t MAX_BUFFER_DURATION_US = 12000000; // 12s
};
