// ------------------------------------------------
// Copyright Joe Marshall 2024- All Rights Reserved
// ------------------------------------------------
//
// An implementation of IMediaSamples for the new
// v2 video timing in Unreal media player.
//
// With new timing, whilst in theory IMediaSamples
// is a queue, in use  only the most recent sample
// is ever read.
//
// Given we know that, this class dumps any
// previous samples immediately, which allows
// the underlying hardware image to be released as
// soon as possible, which makes video decoding
// work more efficiently.
// ------------------------------------------------

#pragma once

#include "AndroidVulkanTextureSample.h"
#include "IMediaSamples.h"

#include "UnrealLogging.h"
// for v2 video timing, the sample queue just
// holds a single image
class FVideoMediaSampleHolder : public IMediaSamples
{

  public:
    void AddVideo(TSharedRef<AndroidVulkanTextureSample, ESPMode::ThreadSafe> &InSample)
    {
        if (VideoSample.IsValid())
        {
            // force sample texture clear because
            // we're not going to display it
            VideoSample->Clear();
            UE_LOGFMT(LogDirectVideo, VeryVerbose, "Clearing videoframe {0}",
                      VideoSample.GetSharedReferenceCount());
        }
        VideoSample = InSample;
        UE_LOGFMT(LogDirectVideo, VeryVerbose, "CSet video frame {0}", VideoSample.IsValid());
    }

    virtual bool FetchVideo(
        TRange<FTimespan> TimeRange,
        TSharedPtr<IMediaTextureSample, ESPMode::ThreadSafe> &OutSample) override
    {
        UE_LOGFMT(LogDirectVideo, VeryVerbose, "BFetch video frame {0}", VideoSample.IsValid());
        if (VideoSample.IsValid())
        {
            OutSample = VideoSample;
            VideoSample.Reset();
            return true;
        }
        return false; // override in child classes, if supported
    }
    virtual bool FetchVideo(
        TRange<FMediaTimeStamp> TimeRange,
        TSharedPtr<IMediaTextureSample, ESPMode::ThreadSafe> &OutSample) override
    {
        UE_LOGFMT(LogDirectVideo, VeryVerbose, "AFetch video frame {0}", VideoSample.IsValid());
        if (VideoSample.IsValid())
        {
            OutSample = VideoSample;
            VideoSample.Reset();
            return true;
        }
        return false; // override in child classes, if supported
    }

    virtual EFetchBestSampleResult FetchBestVideoSampleForTimeRange(
        const TRange<FMediaTimeStamp> &TimeRange,
        TSharedPtr<IMediaTextureSample, ESPMode::ThreadSafe> &OutSample, bool bReverse)

    {
        UE_LOGFMT(LogDirectVideo, VeryVerbose, "Best sample {0}", VideoSample.IsValid());
        if (VideoSample.IsValid())
        {
            OutSample = VideoSample;
            VideoSample.Reset();
            return EFetchBestSampleResult::Ok;
        }
        else
        {
            return EFetchBestSampleResult::NoSample;
        }
    }

    virtual void FlushSamples() override
    {
        UE_LOGFMT(LogDirectVideo, VeryVerbose, "Flush samples {0}", VideoSample.IsValid());
        // override in child classes, if supported
        VideoSample.Reset();
        FlushCount += 1;
    }

    virtual uint32 GetFlushCount()
    {
        return FlushCount;
    }

    virtual bool PeekVideoSampleTime(FMediaTimeStamp &TimeStamp) override
    {
        if (VideoSample.IsValid())
        {
            TimeStamp = VideoSample->GetTime();
            UE_LOGFMT(LogDirectVideo, VeryVerbose, "Peek timestamp {0}",
                      TimeStamp.Time.GetTotalSeconds());
            return true;
        }
        else
        {
            //            UE_LOGFMT(LogDirectVideo, VeryVerbose, "Peek timestamp returning zero");
            //            TimeStamp =
            //            FMediaTimeStamp(FTimespan(0LL),FMediaTimeStamp::MakeSequenceIndex(0, 0));
            //            return true;

            UE_LOGFMT(LogDirectVideo, VeryVerbose, "Peek timestamp returning false");
            return false;
        }
    }

    virtual int32 NumVideoSamples() const override
    {
        UE_LOGFMT(LogDirectVideo, VeryVerbose, "Query num samples {0}", VideoSample.IsValid());
        if (VideoSample.IsValid())
        {
            return 1;
        }
        else
        {
            return 0;
        }
    }

    bool DiscardVideoSamples(const TRange<FMediaTimeStamp> &TimeRange, bool bReverse) override
    {
        UE_LOGFMT(LogDirectVideo, VeryVerbose, "Discard video samples {0}", VideoSample.IsValid());
        return false;
    }

    virtual uint32 PurgeOutdatedVideoSamples(const FMediaTimeStamp &ReferenceTime, bool bReversed,
                                             FTimespan MaxAge) override

    {
        UE_LOGFMT(LogDirectVideo, VeryVerbose, "PurgeOutdatedVideoSamples {0} {1}",
                  VideoSample.IsValid(), ReferenceTime.Time.GetTicks() * 100);
        return 0;
    };

    TSharedPtr<AndroidVulkanTextureSample, ESPMode::ThreadSafe> VideoSample;

    uint32 FlushCount = 0;
};
