using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using IFSEngine.Model;
namespace IFSRenderer.AvaloniaShell.Rendering;
/// <summary>
/// The renderer as the windows see it: a plugin catalogue, the open fractal, a work queue
/// onto the render thread, and the counters the status bar reports.
/// </summary>
/// <remarks>
/// <para>
/// <see cref="RenderService"/> is the real implementation, and owns an OpenGL context pinned
/// to its own thread. Depending on this interface instead lets the UI be constructed and
/// driven with no GPU, no window and no GL — which is what makes the windows testable.
/// </para>
/// <para>
/// <b>Ordering is the load-bearing part of this contract.</b> <see cref="Post"/> only QUEUES:
/// it returns before the engine has run the action, so anything that must observe the result
/// belongs INSIDE the action, not on the line after it. Getting that wrong is what made
/// node-graph and post-effect edits appear one action late.
/// </para>
/// </remarks>
public interface IRenderQueue : IDisposable
{
/// <summary>Loads the plugin library, then starts the render thread.</summary>
Task StartAsync(string libraryDir, string transformsDir);
/// <summary>Re-reads the plugin files from disk and recompiles the kernel.</summary>
Task ReloadPluginsAsync(string libraryDir, string transformsDir);
IReadOnlyList<TransformPlugin> Transforms { get; }
IReadOnlyList<EffectPlugin> Effects { get; }
/// <summary>The open fractal, or null before one has been loaded.</summary>
IFS Current { get; }
/// <summary>Makes a fractal current and sizes the preview to the viewport.</summary>
void LoadFractal(IFS fractal, int viewportWidth, int viewportHeight);
/// <summary>Queues an action to run on the render thread. Returns immediately.</summary>
void Post(Action<IRenderer> action);
/// <summary>Queues an action and completes once it has run.</summary>
Task PostAsync(Action<IRenderer> action);
void SetViewport(int width, int height, bool fillViewport = true);
/// <summary>Guards <see cref="FrameBuffer"/> against the UI reading a torn frame.</summary>
object FrameLock { get; }
/// <summary>Bottom-up BGRA8 pixels, <see cref="FrameWidth"/> x <see cref="FrameHeight"/>.</summary>
byte[] FrameBuffer { get; }
int FrameWidth { get; }
int FrameHeight { get; }
event Action FrameReady;
event Action<Exception> Failed;
string GpuName { get; }
/// <summary>The exception that stopped the render loop, or null while it is healthy.</summary>
Exception LastError { get; }
ulong TotalIterations { get; }
int IterationLevel { get; }
double Fps { get; }
double IterationSpeed { get; }
int InvocationIters { get; }
int WorkgroupCount { get; }
bool Paused { get; set; }
Task SetWorkgroupCountAsync(int count);
Task ExportAsync(string path, int width, int height, int targetLevel,
Action<int> onLevel = null, ExportMetadata metadata = null);
Task ExportFramesAsync(string directory, int width, int height, int targetLevel,
Action<int, int> onProgress, Func<bool> isCancelled, bool rawExr = false,
Action<byte[], int, int> frameSink = null);
Task<byte[]> RenderThumbnailAsync(IFS candidate, int width, int height, int level);
}