using Engine.Graphics.Shader;
using OpenTK.Mathematics;

namespace Engine.Graphics.Render.Mesh;

public class AnyMeshRenderer(Engine parEngine, int parMaxInstanceCount)
{
  private readonly Dictionary<Asset.Mesh.Mesh, MeshRenderer> _meshRenderers = new();
  private readonly HashSet<Asset.Mesh.Mesh> _frameMeshes = [];

  private readonly Program _program = parEngine.EngineResourceManager.Load<Program>("shader/mesh");

  public void Commit(Asset.Mesh.Mesh parMesh, Matrix4 parModelMatrix, Texture.Texture? parAlbedo = null)
  {
    if (_meshRenderers.TryGetValue(parMesh, out var meshRenderer))
    {
      meshRenderer.Commit(parModelMatrix, parAlbedo);
    }
    else
    {
      var newMeshRenderer = new MeshRenderer(parMesh, parMaxInstanceCount, _program);
      newMeshRenderer.Commit(parModelMatrix, parAlbedo);

      _meshRenderers.Add(parMesh, newMeshRenderer);
    }

    _frameMeshes.Add(parMesh);
  }

  public void Render(in Matrix4 parProjectionMatrix, in Matrix4 parViewMatrix)
  {
    foreach (var meshRenderer in _meshRenderers.Values)
    {
      meshRenderer.Render(parProjectionMatrix, parViewMatrix);
    }
  }

  public void Reset()
  {
    foreach (var meshRenderer in _meshRenderers.Values)
    {
      meshRenderer.Reset();
    }

    var meshes = _meshRenderers.Keys.ToList();
    foreach (var mesh in meshes)
    {
      if (!_frameMeshes.Contains(mesh))
        _meshRenderers.Remove(mesh);
    }

    _frameMeshes.Clear();
  }
}