// Canvas display — draws each decoded VideoFrame into a 2D canvas, then
// closes the frame. The canvas auto-resizes to the host's coded width/height
// on the first frame and on any resolution change (multi-monitor switch).

export class CanvasView {
  private canvas: HTMLCanvasElement;
  private ctx: CanvasRenderingContext2D;
  private width = 0;
  private height = 0;

  // FPS counter (rolling 1-second window).
  private frameTimes: number[] = [];

  constructor(parent: HTMLElement) {
    this.canvas = document.createElement("canvas");
    this.canvas.className = "rd-canvas";
    parent.appendChild(this.canvas);
    const ctx = this.canvas.getContext("2d", { alpha: false });
    if (!ctx) throw new Error("canvas: 2d context not available");
    this.ctx = ctx;
  }

  /** Draw a decoded frame, then close it. Must be called from the
   *  VideoDecoder.output callback. */
  draw(frame: VideoFrame): void {
    try {
      if (frame.codedWidth !== this.width || frame.codedHeight !== this.height) {
        this.width = frame.codedWidth;
        this.height = frame.codedHeight;
        this.canvas.width = this.width;
        this.canvas.height = this.height;
      }
      this.ctx.drawImage(frame, 0, 0);
      this.tickFps();
    } catch (e) {
      console.error("[rustdesk-web] canvas draw failed:", e);
    } finally {
      frame.close();
    }
  }

  private tickFps(): void {
    const now = performance.now();
    this.frameTimes.push(now);
    while (this.frameTimes.length > 0 && now - this.frameTimes[0]! > 1000) {
      this.frameTimes.shift();
    }
  }

  /** Current frames-per-second over the last second. */
  fps(): number {
    return this.frameTimes.length;
  }

  /** Coded dimensions of the most recent frame. Used by input mappers to
   *  translate browser pixel coords → peer screen coords. */
  size(): { width: number; height: number } {
    return { width: this.width, height: this.height };
  }

  /** Bounding rect of the canvas in browser viewport pixels. */
  rect(): DOMRect {
    return this.canvas.getBoundingClientRect();
  }

  /** Underlying canvas — used by input modules to attach event listeners. */
  el(): HTMLCanvasElement {
    return this.canvas;
  }
}
