using System.Collections.Concurrent;
using OpenTK.Graphics.OpenGL;

namespace Dashboard.Drawing.OpenGL
{
    public class ContextCollector : IDisposable
    {
        private readonly ConcurrentQueue<GLObject> _disposedObjects = new ConcurrentQueue<GLObject>();

        public void Dispose()
        {
            while (_disposedObjects.TryDequeue(out GLObject obj))
            {
                obj.Dispose();
            }
        }

        void DeleteObject(ObjectIdentifier identifier, int handle) => _disposedObjects.Enqueue(new GLObject(identifier, handle));

        public void DeleteTexture(int texture) => DeleteObject(ObjectIdentifier.Texture, texture);
        public void DeleteBufffer(int buffer) => DeleteObject(ObjectIdentifier.Buffer, buffer);
        public void DeleteFramebuffer(int framebuffer) => DeleteObject(ObjectIdentifier.Framebuffer, framebuffer);
        public void DeleteRenderBuffer(int renderbuffer) => DeleteObject(ObjectIdentifier.Renderbuffer, renderbuffer);
        public void DeleteSampler(int sampler) => DeleteObject(ObjectIdentifier.Sampler, sampler);
        public void DeleteShader(int shader) => DeleteObject(ObjectIdentifier.Shader, shader);
        public void DeleteProgram(int program) => DeleteObject(ObjectIdentifier.Program, program);
        public void DeleteVertexArray(int vertexArray) => DeleteObject(ObjectIdentifier.VertexArray, vertexArray);
        public void DeleteQuery(int query) => DeleteObject(ObjectIdentifier.Query, query);
        public void DeleteProgramPipeline(int programPipeline) => DeleteObject(ObjectIdentifier.ProgramPipeline, programPipeline);
        public void DeleteTransformFeedback(int transformFeedback) => DeleteObject(ObjectIdentifier.TransformFeedback, transformFeedback);

        private readonly record struct GLObject(ObjectIdentifier Type, int Handle)
        {
            public void Dispose()
            {
                switch (Type)
                {
                    case ObjectIdentifier.Texture:
                        GL.DeleteTexture(Handle);
                        break;
                    case ObjectIdentifier.Buffer:
                        GL.DeleteBuffer(Handle);
                        break;
                    case ObjectIdentifier.Framebuffer:
                        GL.DeleteFramebuffer(Handle);
                        break;
                    case ObjectIdentifier.Renderbuffer:
                        GL.DeleteRenderbuffer(Handle);
                        break;
                    case ObjectIdentifier.Sampler:
                        GL.DeleteSampler(Handle);
                        break;
                    case ObjectIdentifier.Shader:
                        GL.DeleteShader(Handle);
                        break;
                    case ObjectIdentifier.VertexArray:
                        GL.DeleteVertexArray(Handle);
                        break;
                    case ObjectIdentifier.Program:
                        GL.DeleteProgram(Handle);
                        break;
                    case ObjectIdentifier.Query:
                        GL.DeleteQuery(Handle);
                        break;
                    case ObjectIdentifier.ProgramPipeline:
                        GL.DeleteProgramPipeline(Handle);
                        break;
                    case ObjectIdentifier.TransformFeedback:
                        GL.DeleteTransformFeedback(Handle);
                        break;
                }
            }
        }

        public static readonly ContextCollector Global = new ContextCollector();
    }
}