export class VideoSource {
  private stream: MediaStream | null = null
  private video: HTMLVideoElement
  private mode: 'webcam' | 'file'

  private constructor(video: HTMLVideoElement, mode: 'webcam' | 'file') {
    this.video = video
    this.mode = mode
  }

  /**
   * Create a video source and start playback.
   * Handles the full lifecycle: attach source -> wait for loadeddata -> play.
   */
  static async create(
    video: HTMLVideoElement,
    mode: 'webcam' | 'file',
    fileUrl?: string,
  ): Promise<VideoSource> {
    const source = new VideoSource(video, mode)

    // Attach listener BEFORE changing source to avoid race condition
    const loadPromise = new Promise<void>((resolve, reject) => {
      video.addEventListener('loadeddata', () => resolve(), { once: true })
      video.addEventListener('error', () => reject(new Error('Failed to load video')), { once: true })
    })

    if (mode === 'file' && fileUrl) {
      video.srcObject = null
      video.src = fileUrl
      video.loop = true
    } else {
      const stream = await navigator.mediaDevices.getUserMedia({
        video: { width: 1280, height: 720, facingMode: 'user' },
      })
      source.stream = stream
      video.removeAttribute('src')
      video.srcObject = stream
    }

    await loadPromise
    await video.play()

    return source
  }

  /** Check if a debug video exists at /debug.webm. */
  static async probeDebugVideo(): Promise<string | null> {
    try {
      const res = await fetch('/debug.webm', { method: 'HEAD' })
      const type = res.headers.get('content-type') || ''
      if (res.ok && type.startsWith('video/')) return '/debug.webm'
    } catch { /* ignore */ }
    return null
  }

  getStream(): MediaStream | null {
    return this.stream
  }

  getMode(): 'webcam' | 'file' {
    return this.mode
  }

  dispose(): void {
    if (this.stream) {
      this.stream.getTracks().forEach((t) => t.stop())
      // Only clear video element if it's still using our stream
      if (this.video.srcObject === this.stream) {
        this.video.srcObject = null
      }
      this.stream = null
    }
    // Only clear src if we set it (file mode)
    if (this.mode === 'file' && this.video.src) {
      this.video.removeAttribute('src')
    }
  }
}
