#ifndef CROSSDESK_GUI_PLATFORM_METAL_VIDEO_RENDERER_H_
#define CROSSDESK_GUI_PLATFORM_METAL_VIDEO_RENDERER_H_

#include <cstddef>
#include <cstdint>
#include <memory>
#include <string>
#include <string_view>
#include <vector>

#include "platform/video_renderer.h"

namespace crossdesk {

// macOS video compositor used by CrossDesk only. MiniRTC continues to expose
// tightly packed CPU NV12 frames; this renderer performs the single required
// copy into shared Metal buffers and converts NV12 to RGB in the fragment
// shader. AppKit attachment and rendering are main-thread operations, while
// SubmitNv12() is safe to call from MiniRTC's decode callback thread.
class MacMetalVideoRenderer final : public VideoRenderer {
 public:
  MacMetalVideoRenderer();
  ~MacMetalVideoRenderer() override;

  MacMetalVideoRenderer(const MacMetalVideoRenderer&) = delete;
  MacMetalVideoRenderer& operator=(const MacMetalVideoRenderer&) = delete;

  bool IsReady() const override;
  bool IsActive() const override;

  // The selected stream is the only stream uploaded. Frames for background
  // tabs are intentionally dropped to avoid wasting memory bandwidth.
  bool SetSelectedStream(std::string remote_id) override;
  void DiscardStream(std::string_view remote_id) override;

  // Copies one tightly packed NV12 frame into a free shared Metal slot.
  SubmitResult SubmitNv12(std::string_view remote_id, const uint8_t* data,
                          size_t size, int width, int height) override;

  // Seeds a newly selected stream from its retained CPU snapshot without
  // replacing a newer decoded frame that is already queued or rendering.
  SubmitResult SubmitCachedNv12(std::string_view remote_id,
                                const uint8_t* data, size_t size, int width,
                                int height) override;

  // Attaches a native CAMetalLayer-backed sibling below Slint's NSView and
  // restores the containing AppKit window's ordinary opaque titlebar.
  // |slint_view| is an NSView* kept opaque so this header remains valid C++.
  bool Attach(void* slint_view);
  void Detach();
  bool IsAttached() const;

  // Cheap main-thread geometry check used by the UI frame timer. New decoded
  // frames are tracked by GuiRuntime's dirty flag; this covers native resize,
  // scale, stream selection, and retry work without a full session sync.
  bool NeedsSurfaceRedraw() const;

  // Draws the newest queued frame for |remote_id|. top_inset_points reserves
  // Slint's tab strip above the native video surface. A rendered outcome
  // carries metadata from the exact slot submitted to the command buffer.
  RenderOutcome RenderLatest(std::string_view remote_id,
                             double top_inset_points,
                             bool native_titlebar_visible);

  // Used only when a session closes, so thumbnail generation does not require
  // a second per-frame CPU copy during normal playback.
  bool CopyLatestNv12(std::string_view remote_id,
                      std::vector<unsigned char>* output, int* width,
                      int* height) const override;

 private:
  SubmitResult SubmitNv12Internal(std::string_view remote_id,
                                  const uint8_t* data, size_t size, int width,
                                  int height, bool replace_pending);

  struct Impl;
  std::unique_ptr<Impl> impl_;
};

}  // namespace crossdesk

#endif  // CROSSDESK_GUI_PLATFORM_METAL_VIDEO_RENDERER_H_
