<script>
  import { onMount, onDestroy } from "svelte";
  import AudioVisualizer from "./lib/AudioVisualizer.svelte";
  import Controls from "./lib/Controls.svelte";

  const STORAGE_KEY = "ncs-visualizer-settings";

  const defaults = {
    selectedPreset: "cyanPink",
    logoUrl: "",
    title: "Audio Visualizer",
    subtitle: "Now Playing",
    bgImage: "",
    bgColor: "#0a0a0a",
    customPrimary: "#00d4ff",
    customSecondary: "#ff006e",
    useCustomColors: false,
    sidebarOpen: true,
    vignette: true,
    audioSource: "mic",
    audioUrl: "",
    vizMode: "circular",
    barCount: 48,
    sensitivity: 1.0,
    smoothing: 0.82,
    bassEmphasis: 0.25,
    particlesEnabled: true,
    particleDensity: 1.0,
    shakeAmount: 1.0,
    zoomIntensity: 1.0,
    glowIntensity: 0.6,
    logoSpin: false,
    logoSpinSpeed: 5,
    autoSubtitle: false,
    titlePosition: "top",
  };

  function loadSettings() {
    try {
      const raw = localStorage.getItem(STORAGE_KEY);
      return raw ? { ...defaults, ...JSON.parse(raw) } : { ...defaults };
    } catch {
      return { ...defaults };
    }
  }

  const saved = loadSettings();

  let selectedPreset = saved.selectedPreset;
  let logoUrl = saved.logoUrl;
  let title = saved.title;
  let subtitle = saved.subtitle;
  let bgImage = saved.bgImage;
  let bgColor = saved.bgColor;
  let customPrimary = saved.customPrimary;
  let customSecondary = saved.customSecondary;
  let useCustomColors = saved.useCustomColors;
  let isListening = false;
  let sidebarOpen = saved.sidebarOpen;
  let vignette = saved.vignette;
  let audioSource = saved.audioSource;
  let audioUrl = saved.audioUrl;
  let vizMode = saved.vizMode;
  let barCount = saved.barCount;
  let sensitivity = saved.sensitivity;
  let smoothing = saved.smoothing;
  let bassEmphasis = saved.bassEmphasis;
  let particlesEnabled = saved.particlesEnabled;
  let particleDensity = saved.particleDensity;
  let shakeAmount = saved.shakeAmount;
  let zoomIntensity = saved.zoomIntensity;
  let glowIntensity = saved.glowIntensity;
  let logoSpin = saved.logoSpin;
  let logoSpinSpeed = saved.logoSpinSpeed;
  let autoSubtitle = saved.autoSubtitle;
  let titlePosition = saved.titlePosition;
  let capturedTrackLabel = "";
  let visualizerComponent;
  let toggleHidden = false;
  let hideTimer;

  function startHideTimer() {
    clearTimeout(hideTimer);
    if (!sidebarOpen) {
      hideTimer = setTimeout(() => {
        toggleHidden = true;
      }, 2000);
    }
  }

  function handleToggleClick() {
    sidebarOpen = !sidebarOpen;
    toggleHidden = false;
    clearTimeout(hideTimer);
    if (!sidebarOpen) startHideTimer();
  }

  $: if (!sidebarOpen) {
    startHideTimer();
  } else {
    toggleHidden = false;
    clearTimeout(hideTimer);
  }

  $: if (autoSubtitle && capturedTrackLabel) {
    subtitle = capturedTrackLabel;
  }

  $: {
    const settings = {
      selectedPreset,
      logoUrl,
      title,
      subtitle,
      bgImage,
      bgColor,
      customPrimary,
      customSecondary,
      useCustomColors,
      sidebarOpen,
      vignette,
      audioSource,
      audioUrl,
      vizMode,
      barCount,
      sensitivity,
      smoothing,
      bassEmphasis,
      particlesEnabled,
      particleDensity,
      shakeAmount,
      zoomIntensity,
      glowIntensity,
      logoSpin,
      logoSpinSpeed,
      autoSubtitle,
      titlePosition,
    };
    try {
      localStorage.setItem(STORAGE_KEY, JSON.stringify(settings));
    } catch {}
  }

  function toggleListening() {
    if (isListening) {
      visualizerComponent.stopListening();
    } else {
      visualizerComponent.startListening();
    }
  }

  function handleScreenshot() {
    const dataUrl = visualizerComponent.takeScreenshot();
    if (!dataUrl) return;
    const link = document.createElement("a");
    link.download = "visualizer-screenshot.png";
    link.href = dataUrl;
    link.click();
  }

  function handleFullscreen() {
    if (!document.fullscreenElement) {
      document.documentElement.requestFullscreen().catch(() => {});
    } else {
      document.exitFullscreen().catch(() => {});
    }
  }

  function handleReset() {
    selectedPreset = defaults.selectedPreset;
    logoUrl = defaults.logoUrl;
    title = defaults.title;
    subtitle = defaults.subtitle;
    bgImage = defaults.bgImage;
    bgColor = defaults.bgColor;
    customPrimary = defaults.customPrimary;
    customSecondary = defaults.customSecondary;
    useCustomColors = defaults.useCustomColors;
    vignette = defaults.vignette;
    audioSource = defaults.audioSource;
    audioUrl = defaults.audioUrl;
    vizMode = defaults.vizMode;
    barCount = defaults.barCount;
    sensitivity = defaults.sensitivity;
    smoothing = defaults.smoothing;
    bassEmphasis = defaults.bassEmphasis;
    particlesEnabled = defaults.particlesEnabled;
    particleDensity = defaults.particleDensity;
    shakeAmount = defaults.shakeAmount;
    zoomIntensity = defaults.zoomIntensity;
    glowIntensity = defaults.glowIntensity;
    logoSpin = defaults.logoSpin;
    logoSpinSpeed = defaults.logoSpinSpeed;
    autoSubtitle = defaults.autoSubtitle;
    titlePosition = defaults.titlePosition;
  }

  let fileCurrentTime = 0;
  let fileDuration = 0;
  let filePlaying = false;
  let fileName = "";

  function handleAudioFile(e) {
    const file = e.detail;
    if (file && visualizerComponent) {
      if (isListening) {
        visualizerComponent.stopListening();
      }
      audioSource = "file";
      visualizerComponent.setAudioFile(file);
    }
  }

  function handleFilePause() {
    if (visualizerComponent) visualizerComponent.pauseAudio();
  }

  function handleFileResume() {
    if (visualizerComponent) visualizerComponent.resumeAudio();
  }

  function handleFileSeek(e) {
    if (visualizerComponent) visualizerComponent.seekAudio(e.detail);
  }

  function handleKeydown(e) {
    // Ignore if user is typing in an input
    if (
      e.target.tagName === "INPUT" ||
      e.target.tagName === "TEXTAREA" ||
      e.target.isContentEditable
    )
      return;

    switch (e.code) {
      case "Space":
        e.preventDefault();
        toggleListening();
        break;
      case "KeyF":
        e.preventDefault();
        handleFullscreen();
        break;
      case "KeyH":
        e.preventDefault();
        handleToggleClick();
        break;
    }
  }

  onMount(() => {
    window.addEventListener("keydown", handleKeydown);
  });

  onDestroy(() => {
    window.removeEventListener("keydown", handleKeydown);
  });

  const colorPresets = {
    cyanPink: {
      name: "Cyan/Pink",
      primary: "#00d4ff",
      secondary: "#ff006e",
    },
    purpleOrange: {
      name: "Purple/Orange",
      primary: "#8b5cf6",
      secondary: "#f97316",
    },
    greenYellow: {
      name: "Green/Yellow",
      primary: "#22c55e",
      secondary: "#eab308",
    },
    pinkBlue: {
      name: "Pink/Blue",
      primary: "#ec4899",
      secondary: "#3b82f6",
    },
    redOrange: {
      name: "Red/Orange",
      primary: "#ef4444",
      secondary: "#f97316",
    },
    white: {
      name: "White",
      primary: "#ffffff",
      secondary: "#888888",
    },
  };

  $: currentColors = useCustomColors
    ? { primary: customPrimary, secondary: customSecondary }
    : colorPresets[selectedPreset];
</script>

<main style="--bg-color: {bgColor}">
  {#if bgImage}
    <div class="bg-image" style="background-image: url({bgImage})"></div>
  {/if}
  {#if vignette}
    <div class="vignette"></div>
  {/if}

  <div class="stage">
    <AudioVisualizer
      bind:this={visualizerComponent}
      colors={currentColors}
      {logoUrl}
      {audioSource}
      {vizMode}
      {barCount}
      {sensitivity}
      {smoothing}
      {bassEmphasis}
      {particlesEnabled}
      {particleDensity}
      {shakeAmount}
      {zoomIntensity}
      {glowIntensity}
      {logoSpin}
      {logoSpinSpeed}
      bind:capturedTrackLabel
      bind:isListening
      bind:fileCurrentTime
      bind:fileDuration
      bind:filePlaying
      bind:fileName
    />
  </div>

  <div class="titles title-{titlePosition}">
    <h1 style="color: {currentColors.primary}">{title}</h1>
    <h2 style="color: {currentColors.secondary}">{subtitle}</h2>
  </div>

  <!-- svelte-ignore a11y-no-static-element-interactions -->
  <div
    class="toggle-zone"
    class:hidden={toggleHidden}
    on:mouseenter={() => {
      toggleHidden = false;
    }}
  >
    <button
      class="sidebar-toggle"
      class:open={sidebarOpen}
      on:click={handleToggleClick}
    >
      <svg
        xmlns="http://www.w3.org/2000/svg"
        width="20"
        height="20"
        viewBox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        stroke-width="2"
      >
        {#if sidebarOpen}
          <path d="M15 18l-6-6 6-6" />
        {:else}
          <path d="M9 18l6-6-6-6" />
        {/if}
      </svg>
    </button>
  </div>

  <aside class="sidebar" class:open={sidebarOpen}>
    <Controls
      bind:selectedPreset
      bind:logoUrl
      bind:title
      bind:subtitle
      bind:bgImage
      bind:bgColor
      bind:vignette
      bind:audioSource
      bind:audioUrl
      bind:customPrimary
      bind:customSecondary
      bind:useCustomColors
      bind:vizMode
      bind:barCount
      bind:sensitivity
      bind:smoothing
      bind:bassEmphasis
      bind:particlesEnabled
      bind:particleDensity
      bind:shakeAmount
      bind:zoomIntensity
      bind:glowIntensity
      bind:logoSpin
      bind:logoSpinSpeed
      bind:autoSubtitle
      bind:titlePosition
      {isListening}
      {colorPresets}
      onToggle={toggleListening}
      on:screenshot={handleScreenshot}
      on:fullscreen={handleFullscreen}
      on:reset={handleReset}
      on:audiofile={handleAudioFile}
      on:filepause={handleFilePause}
      on:fileresume={handleFileResume}
      on:fileseek={handleFileSeek}
      {fileCurrentTime}
      {fileDuration}
      {filePlaying}
      {fileName}
    />
  </aside>
</main>

<style>
  main {
    position: relative;
    display: flex;
    width: 100vw;
    height: 100vh;
    overflow: hidden;
    background: var(--bg-color);
  }

  .bg-image {
    position: absolute;
    inset: 0;
    background-size: cover;
    background-position: center;
    z-index: 0;
  }

  .vignette {
    position: absolute;
    inset: 0;
    background: radial-gradient(
      ellipse at center,
      rgba(0, 0, 0, 0.5) 0%,
      rgba(0, 0, 0, 1) 100%
    );
    z-index: 0;
  }

  .stage {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 1;
  }

  .titles {
    position: absolute;
    z-index: 10;
    pointer-events: none;
    text-align: center;
    padding: 1.5rem 2.5rem;
    background: radial-gradient(
      ellipse at center,
      rgba(0, 0, 0, 0.7) 0%,
      rgba(0, 0, 0, 0.4) 50%,
      transparent 80%
    );
    text-shadow:
      0 2px 8px rgba(0, 0, 0, 1),
      0 0 30px rgba(0, 0, 0, 0.9);
  }

  .title-top {
    top: 0;
    left: 50%;
    transform: translateX(-50%);
  }

  .title-bottom {
    bottom: 0;
    left: 50%;
    transform: translateX(-50%);
  }

  .title-center {
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
  }

  .title-top-left {
    top: 0;
    left: 0;
    text-align: left;
  }

  .title-top-right {
    top: 0;
    right: 0;
    text-align: right;
  }

  .title-bottom-left {
    bottom: 0;
    left: 0;
    text-align: left;
  }

  .title-bottom-right {
    bottom: 0;
    right: 0;
    text-align: right;
  }

  .title-left {
    top: 50%;
    left: 0;
    transform: translateY(-50%);
    text-align: left;
  }

  .title-right {
    top: 50%;
    right: 0;
    transform: translateY(-50%);
    text-align: right;
  }

  h1 {
    font-size: clamp(1.4rem, 3.5vw, 3rem);
    font-weight: 300;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    margin: 0;
  }

  h2 {
    font-size: clamp(1rem, 2vw, 1.8rem);
    font-weight: 300;
    letter-spacing: 0.15em;
    margin: 0.3rem 0 0 0;
    opacity: 0.7;
  }

  .toggle-zone {
    position: fixed;
    top: 0;
    right: 0;
    width: 50px;
    height: 100vh;
    z-index: 30;
    opacity: 1;
    transition: opacity 0.5s ease;
  }

  .toggle-zone.hidden {
    opacity: 0;
  }

  .toggle-zone.hidden:hover {
    opacity: 1;
  }

  .sidebar-toggle {
    position: absolute;
    top: 50%;
    right: 0;
    transform: translateY(-50%);
    background: rgba(255, 255, 255, 0.08);
    border: 1px solid rgba(255, 255, 255, 0.15);
    border-right: none;
    border-radius: 8px 0 0 8px;
    color: #fff;
    padding: 0.75rem 0.4rem;
    cursor: pointer;
    transition: right 0.3s ease;
  }

  .sidebar-toggle.open {
    right: 320px;
  }

  .sidebar-toggle:hover {
    background: rgba(255, 255, 255, 0.15);
  }

  .sidebar {
    position: fixed;
    top: 0;
    right: -320px;
    width: 320px;
    height: 100vh;
    background: rgba(10, 10, 15, 0.92);
    backdrop-filter: blur(12px);
    border-left: 1px solid rgba(255, 255, 255, 0.1);
    z-index: 20;
    overflow-y: auto;
    transition: right 0.3s ease;
    padding: 1.5rem;
    box-sizing: border-box;
  }

  .sidebar.open {
    right: 0;
  }
</style>
