/**
 * Webview audio controller — the frontend half of audio-only playback on
 * platforms with no native audio backend (currently Windows).
 *
 * The Rust `WebviewAudioBackend` emits a `webview_audio_load` event carrying the
 * stream URL whenever a track loads. This controller owns a single hidden
 * `<audio>` element, plays that URL through a {@link WebviewAudioAdapter}, and
 * registers the adapter with the player facade so backend `control_command`
 * events (play/pause/seek — routed by playerEvents.ts) reach the element. The
 * adapter reports state/position back through the standard `player_report_*`
 * round-trip, keeping the Rust controller the single source of truth.
 *
 * No-op on platforms with a native audio backend (Linux/Android): the backend
 * never emits `webview_audio_load` there, so even if initialized this listener
 * stays idle. We still gate initialization on platform to avoid mounting a stray
 * element.
 *
 * TRACES: UR-003, UR-005 | DR-004
 */

import { type UnlistenFn } from "@tauri-apps/api/event";
import { events } from "$lib/api/bindings";
import { playerController } from "$lib/player";
import { createRustReportHost } from "$lib/player/adapters/rustReportHost";
import { WebviewAudioAdapter } from "$lib/player/adapters/webviewAudioAdapter";
import { getPlaybackCapabilities } from "$lib/services/playbackCapabilities";

let unlisten: UnlistenFn | null = null;
let audioEl: HTMLAudioElement | null = null;
let adapter: WebviewAudioAdapter | null = null;

/**
 * Initialize the webview audio controller. Safe to call unconditionally from the
 * root layout; it self-gates on platform and is idempotent.
 */
export async function initWebviewAudio(): Promise<void> {
  if (unlisten) return;

  // Whether this platform needs the webview element is a backend fact, so Rust
  // answers it. This used to sniff `navigator.userAgent` for "android"/"linux"
  // — a duplicate of the Rust cfg gate that could drift out of step with the
  // backends it was trying to describe.
  const { usesWebviewAudio } = await getPlaybackCapabilities();
  if (!usesWebviewAudio) return;

  audioEl = document.createElement("audio");
  audioEl.hidden = true;
  audioEl.preload = "auto";
  // Kept in the DOM so the browser keeps decoding it when not focused.
  document.body.appendChild(audioEl);

  unlisten = await events.playerStatusEvent.listen((event) => {
    const p = event.payload;
    if (p.type !== "webview_audio_load") return;
    void handleLoad(p.url, p.media_id, p.position, p.autoplay);
  });
}

async function handleLoad(
  url: string,
  mediaId: string | null,
  position: number,
  autoplay: boolean
): Promise<void> {
  if (!audioEl) return;

  // Fresh host/adapter per load so reporting targets the current media id.
  const host = createRustReportHost(mediaId ?? "", {});
  adapter = new WebviewAudioAdapter(audioEl, host);
  playerController.setActiveAdapter(adapter);

  await adapter.load(url, {
    mediaId: mediaId ?? "",
    mediaSourceId: null,
    needsTranscoding: false,
    initialPosition: position,
    isLive: false,
    audioTrackIndex: null,
    knownDuration: 0,
    subtitleTracks: [],
  });

  if (!autoplay) {
    await adapter.pause();
  }
}

/** Tear down the controller (idempotent). */
export function cleanupWebviewAudio(): void {
  if (unlisten) {
    unlisten();
    unlisten = null;
  }
  if (adapter) {
    playerController.clearActiveAdapter(adapter);
    void adapter.dispose();
    adapter = null;
  }
  if (audioEl) {
    audioEl.remove();
    audioEl = null;
  }
}
