// Background-blur processor wrapper. LiveKit's `@livekit/track-processors`
// ships a MediaPipe-based selfie-segmentation pipeline that keeps the
// foreground sharp and blurs the background. The model (~1.5MB) downloads
// lazily on first activation, so users who never enable blur don't pay
// for it.
//
// attach/detach hide behind a guard so repeated toggles don't create a
// stack of processors — `setProcessor(null)` tears down the WebGL context
// and frees the GPU surface.

import type { LocalParticipant, LocalVideoTrack } from 'livekit-client';
import { Track } from 'livekit-client';

let cachedProcessor: unknown = null;

async function getProcessor(): Promise<unknown> {
  if (cachedProcessor) return cachedProcessor;
  const mod = (await import('@livekit/track-processors')) as {
    BackgroundBlur?: (radius?: number) => unknown;
  };
  if (!mod.BackgroundBlur) {
    throw new Error('BackgroundBlur not exported by @livekit/track-processors');
  }
  cachedProcessor = mod.BackgroundBlur(12);
  return cachedProcessor;
}

function getCameraTrack(lp: LocalParticipant): LocalVideoTrack | null {
  const pub = lp.getTrackPublication(Track.Source.Camera);
  const track = pub?.track;
  if (!track) return null;
  return track as LocalVideoTrack;
}

export async function applyBackgroundBlurToLocal(lp: LocalParticipant): Promise<void> {
  try {
    const track = getCameraTrack(lp);
    if (!track) return;
    const processor = await getProcessor();
    // `setProcessor` is declared on LocalVideoTrack; cast because the
    // processor type lives in a separate module we don't want to strongly
    // couple to here.
    await (track as unknown as {
      setProcessor: (p: unknown) => Promise<void>;
    }).setProcessor(processor);
  } catch (err: unknown) {
    console.warn('applyBackgroundBlur failed', err);
  }
}

export async function removeBackgroundBlurFromLocal(lp: LocalParticipant): Promise<void> {
  try {
    const track = getCameraTrack(lp);
    if (!track) return;
    const setter = (track as unknown as {
      setProcessor?: (p: unknown) => Promise<void>;
      stopProcessor?: () => Promise<void>;
    });
    if (setter.stopProcessor) {
      await setter.stopProcessor();
    } else if (setter.setProcessor) {
      await setter.setProcessor(null);
    }
  } catch (err: unknown) {
    console.warn('removeBackgroundBlur failed', err);
  }
}
