using System.Runtime.InteropServices;
using OpenTK.Graphics.OpenGL;
using Serilog;
using Serilog.Events;
using Evergine.Bindings.RenderDoc;

namespace Engine.Graphics;

internal static class Debug
{
  private static RenderDoc _renderDocApi;

  public static void Setup()
  {
    GL.Enable(EnableCap.DebugOutput);
    GL.DebugMessageCallback(DebugCallback, IntPtr.Zero);
  }

  public static void InitializeRenderDoc()
  {
    RenderDoc.Load(out _renderDocApi);
  }

  public static void RenderDocStartFrame()
  {
    // _renderDocApi.API.StartFrameCapture(IntPtr.Zero, IntPtr.Zero);
  }

  public static void RenderDocEndFrame()
  {
    // _renderDocApi.API.EndFrameCapture(IntPtr.Zero, IntPtr.Zero);
  }

  private static void DebugCallback(DebugSource parSource, DebugType parType, int parId, DebugSeverity parSeverity,
    int parLength,
    IntPtr parMessage, IntPtr parUserParam)
  {
    var logger = Log.ForContext<Engine>();

    var messageText = Marshal.PtrToStringAnsi(parMessage, parLength) ?? "Unknown OpenGL Error";

    var typePrefix = parType switch
    {
      DebugType.DebugTypeError => "Error",
      DebugType.DebugTypeDeprecatedBehavior => "Deprecated",
      DebugType.DebugTypeUndefinedBehavior => "Undefined",
      DebugType.DebugTypePortability => "Portability",
      DebugType.DebugTypePerformance => "Performance",
      DebugType.DebugTypeMarker => "Marker",
      DebugType.DebugTypePushGroup => "PushGroup",
      DebugType.DebugTypePopGroup => "PopGroup",
      DebugType.DebugTypeOther => "Info",
      _ => "Unknown"
    };

    var sourcePrefix = parSource switch
    {
      DebugSource.DebugSourceApi => "API",
      DebugSource.DebugSourceWindowSystem => "Window",
      DebugSource.DebugSourceShaderCompiler => "Shader",
      DebugSource.DebugSourceThirdParty => "ThirdParty",
      DebugSource.DebugSourceApplication => "Application",
      DebugSource.DebugSourceOther => "Other",
      _ => "Unknown"
    };

    logger.Write(GetLogLevel(parSeverity),
      "[OpenGL {TypePrefix}] [{Source}] {Message} (ID: 0x{Id:X8})",
      typePrefix,
      sourcePrefix,
      messageText,
      parId
    );
  }

  private static LogEventLevel GetLogLevel(DebugSeverity parSeverity)
  {
    return parSeverity switch
    {
      DebugSeverity.DebugSeverityNotification => LogEventLevel.Information,
      DebugSeverity.DebugSeverityHigh => LogEventLevel.Error,
      DebugSeverity.DebugSeverityMedium => LogEventLevel.Warning,
      DebugSeverity.DebugSeverityLow => LogEventLevel.Debug,
      _ => LogEventLevel.Debug
    };
  }
}