import type { VideoTexture } from "three";
import type { MediaAuthorizationDecision } from "./types.ts";

export interface MediaSurfaceBinding {
  /** All objects are caller-owned. This adapter never obtains or fetches them. */
  video: HTMLVideoElement;
  texture: VideoTexture;
  track?: MediaStreamTrack;
}

export interface MediaSurfaceLifecycle {
  bind(binding: MediaSurfaceBinding): void;
  apply(decision: MediaAuthorizationDecision): void;
  texture(): VideoTexture | null;
  optedIn(): boolean;
  dispose(): void;
}

/**
 * Gate an already-created video texture behind a server decision and explicit
 * viewer consent. `play`, `getUserMedia`, `fetch`, `track.stop`, and
 * `texture.dispose` are intentionally absent: acquisition and ownership remain
 * with the caller.
 */
export function createMediaSurfaceLifecycle(): MediaSurfaceLifecycle {
  let binding: MediaSurfaceBinding | null = null;
  let allowed = false;
  let consent = false;
  let disposed = false;

  function silence(video: HTMLVideoElement): void {
    video.autoplay = false;
    video.muted = true;
    video.pause();
  }

  return {
    bind(next) {
      if (disposed) throw new Error("media surface lifecycle is disposed");
      if (binding) silence(binding.video);
      binding = next;
      silence(next.video);
    },
    apply(decision) {
      if (disposed) return;
      allowed = decision.canView && decision.surface.source !== null;
      consent = decision.optedIn;
      if (!allowed && binding) silence(binding.video);
    },
    texture: () => (!disposed && allowed && consent ? binding?.texture ?? null : null),
    optedIn: () => consent,
    dispose() {
      if (disposed) return;
      disposed = true;
      if (binding) silence(binding.video);
      binding = null;
      allowed = false;
      consent = false;
    },
  };
}

