<script lang="ts">
  import { downloads } from "$lib/stores/downloads";
  import { auth } from "$lib/stores/auth";
  import { commands } from "$lib/api/bindings";
  import { QUALITY_PRESETS, type QualityPreset } from "$lib/api/quality-presets";
  import { createLogger } from "$lib/utils/logger";

  const log = createLogger("VideoDownloadButton");

  interface Props {
    itemId: string;
    itemName?: string;
    // For movies
    isMovie?: boolean;
    // For episodes
    seriesName?: string;
    seasonName?: string;
    episodeNumber?: number;
    seasonNumber?: number;
    size?: "sm" | "md" | "lg";
    className?: string;
  }

  let {
    itemId,
    itemName = "",
    isMovie = false,
    seriesName,
    seasonName,
    episodeNumber,
    seasonNumber,
    size = "md",
    className = ""
  }: Props = $props();

  const sizeClasses = {
    sm: "w-4 h-4",
    md: "w-5 h-5",
    lg: "w-6 h-6",
  };

  let isProcessing = $state(false);
  let showQualityPicker = $state(false);
  let buttonEl: HTMLButtonElement;
  let dropdownPos = $state({ top: 0, left: 0 });

  // Find download for this item
  const downloadInfo = $derived(
    Object.values($downloads.downloads).find((d) => d.itemId === itemId)
  );

  const status = $derived(downloadInfo?.status || "not_downloaded");
  const progress = $derived(downloadInfo?.progress || 0);

  async function startDownload(quality: QualityPreset) {
    showQualityPicker = false;
    if (isProcessing) return;

    isProcessing = true;
    try {
      const userId = $auth.user?.id;
      if (!userId) {
        log.error("No user ID found");
        return;
      }

      const repo = auth.getRepository();

      log.debug("🎬 Starting video download for item:", itemId, "quality:", quality);

      // Get stream URL based on quality
      const streamUrl = await repo.getVideoDownloadUrl(itemId, quality);
      log.debug("   Stream URL obtained");

      // Get target directory
      const targetDir = await commands.storageGetPath();

      // Create file path
      const safeName = (itemName || itemId).replace(/[/\\:*?"<>|]/g, "_");
      let filePath: string;

      if (isMovie) {
        filePath = `videos/movies/${safeName}.mp4`;
      } else if (seriesName && seasonNumber !== undefined && episodeNumber !== undefined) {
        const safeSeriesName = seriesName.replace(/[/\\:*?"<>|]/g, "_");
        filePath = `videos/${safeSeriesName}/S${String(seasonNumber).padStart(2, '0')}E${String(episodeNumber).padStart(2, '0')}_${safeName}.mp4`;
      } else {
        filePath = `videos/${safeName}.mp4`;
      }

      log.debug("   File path:", filePath);

      // Queue download with video metadata
      const downloadId = await downloads.downloadVideo(
        itemId,
        userId,
        filePath,
        "video/mp4",
        isMovie ? 500 : (1000 - (episodeNumber || 0)), // Movies have medium priority, episodes ordered by number
        itemName || undefined,
        quality,
        seriesName,
        seasonName,
        episodeNumber,
        seasonNumber
      );
      log.debug("   Download queued with ID:", downloadId);

      // Pin the item metadata
      await downloads.pinItem(itemId);

      // Actually start the download
      await commands.startDownload(downloadId, streamUrl, targetDir);
      log.debug("   Download started");
    } catch (error) {
      log.error("Failed to start video download:", error);
    } finally {
      isProcessing = false;
    }
  }

  async function handleClick() {
    if (isProcessing) return;

    if (status === "completed") {
      // Delete download
      if (downloadInfo?.id) {
        await downloads.delete(downloadInfo.id);
        // Unpin when deleted
        await downloads.unpinItem(itemId);
      }
    } else if (status === "downloading" || status === "pending") {
      // Cancel download
      if (downloadInfo?.id) {
        await downloads.cancel(downloadInfo.id);
      }
    } else if (status === "failed") {
      // Show quality picker to retry
      openQualityPicker();
    } else {
      // Show quality picker
      openQualityPicker();
    }
  }

  function openQualityPicker() {
    if (buttonEl) {
      const rect = buttonEl.getBoundingClientRect();
      const dropdownWidth = 160; // w-40
      const padding = 8;
      let left = rect.right - dropdownWidth;
      // Clamp to viewport bounds
      left = Math.max(padding, Math.min(left, window.innerWidth - dropdownWidth - padding));
      dropdownPos = { top: rect.bottom + 4, left };
    }
    showQualityPicker = true;
  }

  function getTitle(): string {
    switch (status) {
      case "completed":
        return "Downloaded - Click to remove";
      case "downloading":
        return `Downloading... ${Math.round(progress * 100)}%`;
      case "pending":
        return "Queued for download";
      case "paused":
        return "Download paused";
      case "failed":
        return "Download failed - Click to retry";
      default:
        return "Download for offline playback";
    }
  }

  function getColor(): string {
    switch (status) {
      case "completed":
        return "text-green-500 hover:text-green-400";
      case "downloading":
      case "pending":
        return "text-blue-500 hover:text-blue-400";
      case "failed":
        return "text-red-500 hover:text-red-400";
      default:
        return "text-gray-400 hover:text-white";
    }
  }
</script>

<div class="relative">
  <button
    bind:this={buttonEl}
    onclick={handleClick}
    disabled={isProcessing}
    class="p-2 rounded-full transition-all {getColor()} {isProcessing
      ? 'opacity-50 cursor-wait'
      : ''} {className}"
    title={getTitle()}
    aria-label={getTitle()}
  >
    <div class="relative {sizeClasses[size]}">
      {#if status === "downloading"}
        <!-- Progress ring -->
        <svg class="absolute inset-0 -rotate-90" viewBox="0 0 24 24">
          <circle
            cx="12"
            cy="12"
            r="10"
            fill="none"
            stroke="currentColor"
            stroke-width="2"
            opacity="0.2"
          />
          <circle
            cx="12"
            cy="12"
            r="10"
            fill="none"
            stroke="currentColor"
            stroke-width="2"
            stroke-dasharray={2 * Math.PI * 10}
            stroke-dashoffset={2 * Math.PI * 10 * (1 - progress)}
            stroke-linecap="round"
            class="transition-all duration-300"
          />
        </svg>
        <svg
          class="absolute inset-0 m-auto w-3 h-3"
          fill="none"
          stroke="currentColor"
          viewBox="0 0 24 24"
          stroke-width="2.5"
        >
          <path
            stroke-linecap="round"
            stroke-linejoin="round"
            d="M12 4v12m0 0l-4-4m4 4l4-4"
          />
        </svg>
      {:else if status === "completed"}
        <svg class={sizeClasses[size]} fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2.5">
          <path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
        </svg>
      {:else if status === "pending"}
        <svg class={sizeClasses[size]} fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2">
          <path stroke-linecap="round" stroke-linejoin="round" d="M12 6v6l4 2m6-2a10 10 0 11-20 0 10 10 0 0120 0z" />
        </svg>
      {:else if status === "failed"}
        <svg class={sizeClasses[size]} fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2">
          <path stroke-linecap="round" stroke-linejoin="round" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
        </svg>
      {:else}
        <svg class={sizeClasses[size]} fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2">
          <path stroke-linecap="round" stroke-linejoin="round" d="M12 4v12m0 0l-4-4m4 4l4-4m-9 7h10" />
        </svg>
      {/if}
    </div>
  </button>
</div>

<!-- Quality picker dropdown (fixed position, viewport-clamped) -->
{#if showQualityPicker}
  <button
    class="fixed inset-0 z-40"
    onclick={() => showQualityPicker = false}
    aria-label="Close quality picker"
  ></button>
  <div
    class="fixed z-50 w-40 bg-[var(--color-surface)] rounded-lg shadow-xl border border-gray-700 overflow-hidden"
    style="top: {dropdownPos.top}px; left: {dropdownPos.left}px;"
  >
    <div class="p-2 text-xs text-gray-400 border-b border-gray-700">
      Select Quality
    </div>
    {#each Object.entries(QUALITY_PRESETS) as [key, preset]}
      <button
        onclick={() => startDownload(key as QualityPreset)}
        class="w-full px-3 py-2 text-left text-sm hover:bg-gray-700 transition-colors flex justify-between items-center"
      >
        <span>{preset.label}</span>
        {#if preset.videoBitrate}
          <span class="text-xs text-gray-500">{Math.round(preset.videoBitrate / 1_000_000)}Mbps</span>
        {:else}
          <span class="text-xs text-gray-500">Direct</span>
        {/if}
      </button>
    {/each}
    <button
      onclick={() => showQualityPicker = false}
      class="w-full px-3 py-2 text-left text-sm text-gray-400 hover:bg-gray-700 border-t border-gray-700"
    >
      Cancel
    </button>
  </div>
{/if}
