/**
 * NativePlayerAdapter — the Android/ExoPlayer PlayerAdapter implementation.
 *
 * ExoPlayer is driven entirely by the Rust backend (JNI), which already emits
 * PlayerStatusEvents and handles seek/audio-track internally. So this adapter is
 * a thin delegate to backend commands; there is no DOM element to touch and no
 * hls.js. State reporting is unnecessary here because the native backend emits
 * events directly — the adapter's job is only to forward control intents.
 *
 * NOTE: On current Tauri, native Android video rendering is blocked upstream
 * (transparent webview / SurfaceView compositing — tauri#10152), so video on
 * Android currently runs through the HTML5 adapter via the interim override in
 * the factory. This adapter exists for the audio/native path and for when that
 * upstream limitation is resolved.
 *
 * TRACES: UR-003, UR-005 | DR-004, DR-028
 */

import { commands } from "$lib/api/bindings";
import type { AdapterHost, PlayerAdapter, PlayerLoadOptions } from "./types";

export class NativePlayerAdapter implements PlayerAdapter {
  readonly kind = "native" as const;

  // Kept for symmetry / future reporting needs; the native backend emits events.
  private host: AdapterHost;
  private position = 0;

  constructor(host: AdapterHost) {
    this.host = host;
  }

  // The native surface is owned by the backend; nothing to attach in the DOM.
  attach(_element: HTMLVideoElement | null): void {}

  async load(_streamUrl: string, options: PlayerLoadOptions): Promise<void> {
    // player_play_item already initiated native playback before this adapter is
    // created; nothing further to do. Seed a resume position if requested (the
    // native backend performs the actual seek internally).
    if (options.initialPosition > 0) {
      this.position = options.initialPosition;
    }
  }

  async play(): Promise<void> {
    await commands.playerPlay();
  }

  async pause(): Promise<void> {
    await commands.playerPause();
  }

  async toggle(): Promise<boolean> {
    const response = (await commands.playerToggle()) as any;
    return response?.state === "playing";
  }

  /**
   * PRIMITIVE: in-place seek. For the native backend, the backend drives
   * ExoPlayer's seek internally, so this simply records the target position.
   * (The decision to seek-in-place vs reload was already made by the backend.)
   */
  async seekElement(positionSeconds: number, _offset: number): Promise<void> {
    this.position = positionSeconds;
  }

  /**
   * PRIMITIVE: reload source. For the native backend the backend already
   * performed the reload+seek internally as part of the seek decision; nothing
   * to do on the frontend beyond recording position.
   */
  async reloadSource(_url: string, offset: number): Promise<void> {
    this.position = offset;
  }

  setVolume(volume: number): void {
    void commands.playerSetVolume(Math.max(0, Math.min(1, volume)));
  }

  setMuted(_muted: boolean): void {
    void commands.playerToggleMute();
  }

  async selectSubtitle(streamIndex: number | null, arrayIndex?: number): Promise<void> {
    const indexToUse = streamIndex === null ? null : arrayIndex ?? streamIndex;
    await commands.playerSetSubtitleTrack(indexToUse);
  }

  getPosition(): number {
    return this.position;
  }

  async dispose(): Promise<void> {
    // The backend is stopped via player_stop by the owning view; nothing to free.
  }
}
