import type { Plugin } from "@/plugins/core/types";
import { componentSetting, defineSettings, numberSetting, booleanSetting } from "@/plugins/core/settingsHelpers";
import styles from "./styles.css?inline";
import BackgroundMusicSetting from "./BackgroundMusicSetting.svelte";
import localforage from "localforage";

const settings = defineSettings({
  uploader: componentSetting({
    title: "Background Music",
    description: "Upload a .wav or .mp3 audio file to play in the background.",
    component: BackgroundMusicSetting,
  }),
  volume: numberSetting({
    title: "Volume",
    description: "Set background music volume",
    default: 0.5,
    min: 0,
    max: 1,
    step: 0.05,
  }),
  pauseOnHidden: booleanSetting({
    title: "Pause when tab hidden",
    description: "Pause music when switching to another tab or minimizing the browser",
    default: true,
  }),
});

const store = localforage.createInstance({
  name: "background-music-store",
  storeName: "music",
});

let currentAudio: HTMLAudioElement | null = null;
let currentObjectUrl: string | null = null;
let cleanupRegistered = false;
let pendingGestureCancel: (() => void) | null = null;
let visibilityResumeTimeout: number | null = null;

async function loadAudioBlob(): Promise<Blob | null> {
  const blob = await store.getItem<Blob>("audio-blob");
  return blob && blob instanceof Blob ? blob : null;
}

function stopAndCleanupAudio(): void {
  if (currentAudio) {
    currentAudio.pause();
    currentAudio.src = "";
    currentAudio.remove();
    currentAudio = null;
  }
  if (currentObjectUrl) {
    URL.revokeObjectURL(currentObjectUrl);
    currentObjectUrl = null;
  }
}

function ensureGestureStart(handler: () => void): () => void {
  const eventTypes = ["pointerdown", "keydown", "touchstart"]; // broad user gesture coverage
  const listener = () => {
    handler();
    for (const type of eventTypes) {
      window.removeEventListener(type, listener);
    }
  };
  for (const type of eventTypes) {
    window.addEventListener(type, listener, { once: true, passive: true });
  }
  return () => {
    for (const type of eventTypes) {
      window.removeEventListener(type, listener);
    }
  };
}

async function startPlayback(volume: number): Promise<void> {
  const blob = await loadAudioBlob();
  if (!blob) return;

  stopAndCleanupAudio();

  currentObjectUrl = URL.createObjectURL(blob);
  const audio = new Audio(currentObjectUrl);
  audio.loop = true;
  audio.volume = Math.max(0, Math.min(1, volume));
  audio.preload = "auto";
  audio.crossOrigin = "anonymous";
  audio.style.display = "none";
  document.body.appendChild(audio);
  currentAudio = audio;

  try {
    // Attempt immediate play; may be blocked until gesture
    await audio.play();
  } catch {
    // Ignore; will be started after gesture if enabled
  }
}

const backgroundMusicPlugin: Plugin<typeof settings> = {
  id: "background-music",
  name: "Background Music",
  description: "Play your own music in the background while SEQTA is open.",
  version: "1.0.0",
  settings,
  styles,
  disableToggle: true,
  defaultEnabled: false,

  run: async (api) => {
    await api.storage.loaded;

    // react to specific setting changes
    api.settings.onChange("volume" as any, (value: any) => {
      const vol = (typeof value === "number" ? value : 0.5) as number;
      if (currentAudio) currentAudio.volume = Math.max(0, Math.min(1, vol));
    });

    api.settings.onChange("pauseOnHidden" as any, (value: any) => {
      const pauseOnHidden = (typeof value === "boolean" ? value : true) as boolean;
      // If the setting is disabled and audio is currently paused due to tab being hidden, resume it
      if (!pauseOnHidden && currentAudio && currentAudio.paused && document.visibilityState === "hidden") {
        currentAudio.play().catch(() => {});
      }
    });

    // Note: Stop button/event removed by user; no stop handling needed

    // Start if we have audio and autoplay is enabled
    const tryStart = async () => {
      const vol = (api.settings as any).volume ?? 0.5;
      await startPlayback(vol);
    };

    // Always arm gesture start and attempt immediate start
    const cancel = ensureGestureStart(() => { tryStart(); });
    cleanupRegistered = true;
    (window as any).__betterseqta_bg_music_cancel__ = cancel;
    tryStart();

    // Pause on tab hide, resume on show with a small delay (if enabled)
    const visHandler = () => {
      if (!currentAudio) return;
      const pauseOnHidden = (api.settings as any).pauseOnHidden ?? true;
      if (!pauseOnHidden) return;
      
      if (document.visibilityState === "hidden") {
        if (visibilityResumeTimeout !== null) {
          clearTimeout(visibilityResumeTimeout);
          visibilityResumeTimeout = null;
        }
        currentAudio.pause();
      } else if (document.visibilityState === "visible") {
        if (visibilityResumeTimeout !== null) {
          clearTimeout(visibilityResumeTimeout);
        }
        visibilityResumeTimeout = window.setTimeout(() => {
          visibilityResumeTimeout = null;
          currentAudio?.play().catch(() => {});
        }, 200);
      }
    };
    document.addEventListener("visibilitychange", visHandler);

    // Allow uploads to trigger refresh
    const uploadedHandler = () => {
      const vol = (api.settings as any).volume ?? 0.5;
      startPlayback(vol);
    };
    window.addEventListener("betterseqta-background-music-updated", uploadedHandler);

    return () => {
      document.removeEventListener("visibilitychange", visHandler);
      window.removeEventListener("betterseqta-background-music-updated", uploadedHandler);
      if (cleanupRegistered && (window as any).__betterseqta_bg_music_cancel__) {
        (window as any).__betterseqta_bg_music_cancel__();
        (window as any).__betterseqta_bg_music_cancel__ = undefined;
      }
      if (pendingGestureCancel) { pendingGestureCancel(); pendingGestureCancel = null; }
      if (visibilityResumeTimeout !== null) { clearTimeout(visibilityResumeTimeout); visibilityResumeTimeout = null; }
      stopAndCleanupAudio();
    };
  },
};

export default backgroundMusicPlugin;


