import * as THREE from "three";

interface ViewerRenderSurfaceOptions {
  container: HTMLElement;
  renderer: THREE.WebGLRenderer;
  onFrame: () => void;
  onResize: (width: number, height: number) => void;
}

export class ViewerRenderSurface {
  private readonly container: HTMLElement;
  readonly renderer: THREE.WebGLRenderer;
  private readonly onFrame: () => void;
  private readonly onResizeCallback: (width: number, height: number) => void;
  private readonly resizeListener = () => this.resize();
  private readonly resizeObserver?: ResizeObserver;

  constructor(options: ViewerRenderSurfaceOptions) {
    this.container = options.container;
    this.renderer = options.renderer;
    this.onFrame = options.onFrame;
    this.onResizeCallback = options.onResize;
    this.renderer.domElement.style.width = "100%";
    this.renderer.domElement.style.height = "100%";
    this.renderer.domElement.style.display = "block";
    this.container.append(this.renderer.domElement);
    window.addEventListener("resize", this.resizeListener);
    if (typeof ResizeObserver !== "undefined") {
      this.resizeObserver = new ResizeObserver(() => this.resize());
      this.resizeObserver.observe(this.container);
    }
    this.resize();
  }

  get domElement() {
    return this.renderer.domElement;
  }

  start() {
    this.renderer.setAnimationLoop(this.onFrame);
  }

  stop() {
    this.renderer.setAnimationLoop(null);
  }

  resize() {
    const width = this.container.clientWidth || window.innerWidth;
    const height = this.container.clientHeight || window.innerHeight;
    this.renderer.setSize(width, height, false);
    this.onResizeCallback(width, height);
  }

  dispose() {
    this.stop();
    window.removeEventListener("resize", this.resizeListener);
    this.resizeObserver?.disconnect();
    this.renderer.dispose();
    this.renderer.domElement.remove();
  }
}
