<script lang="ts">
  import { app } from '$lib/stores/app.svelte';
  import { config } from '$lib/stores/config.svelte';
  import { generatePreview, streamUrl } from '$lib/utils/tauri';

  interface Props {
    currentTime?: number;
    onTimeUpdate?: (time: number) => void;
    onSeek?: (time: number) => void;
  }

  let { currentTime = $bindable(0), onTimeUpdate, onSeek }: Props = $props();

  let videoEl: HTMLVideoElement | undefined = $state();
  let playing = $state(false);
  let volume = $state(config.current.preview_volume);
  let showControls = $state(false);
  let showVolume = $state(false);
  let errorMsg = $state('');
  let previewPath = $state('');
  let generating = $state(false);
  let videoReady = $state(false);

  // try the original file first, fall back to generated H.264 proxy
  let src = $derived(previewPath ? streamUrl(previewPath) : app.videoInfo?.path ? streamUrl(app.videoInfo.path) : '');

  let prevVideoPath = '';

  $effect(() => {
    const path = app.videoInfo?.path;
    if (!path || path === prevVideoPath) return;
    prevVideoPath = path;
    previewPath = '';
    errorMsg = '';
    generating = false;
    videoReady = false;
  });

  async function handleVideoError() {
    const path = app.videoInfo?.path;
    if (!path || generating || previewPath) {
      // already tried the proxy and it also failed
      errorMsg = "Can't preview this video. It will still compress and trim correctly.";
      return;
    }

    // original file can't play (probably unsupported codec) - generate H.264 proxy
    generating = true;
    errorMsg = '';
    try {
      const proxy = await generatePreview(path, app.videoInfo?.video_codec);
      previewPath = proxy;
      // src will update via $derived, video element will reload
    } catch {
      errorMsg = "Can't preview this video. It will still compress and trim correctly.";
    }
    generating = false;
  }

  export function seekTo(time: number) {
    if (videoEl) {
      videoEl.currentTime = time;
      currentTime = time;
    }
  }

  export function togglePlay() {
    if (!videoEl) return;
    if (videoEl.paused) {
      // if we're outside the trim region, jump to the in point first
      const inPt = app.trimRange?.start ?? 0;
      const outPt = app.trimRange?.end ?? (app.videoInfo?.duration ?? 0);
      if (videoEl.currentTime < inPt || videoEl.currentTime >= outPt) {
        videoEl.currentTime = inPt;
      }
      videoEl.play();
      playing = true;
    } else {
      videoEl.pause();
      playing = false;
    }
  }

  let lastReportedTime = 0;

  function handleTimeUpdate() {
    if (!videoEl) return;

    // loop within trim region - always check, don't throttle
    if (playing && app.trimRange) {
      if (videoEl.currentTime >= app.trimRange.end) {
        videoEl.currentTime = app.trimRange.start;
      }
    }

    // throttle reactive updates to ~10Hz to prevent DOM thrashing
    const now = performance.now();
    if (now - lastReportedTime < 100) return;
    lastReportedTime = now;

    currentTime = videoEl.currentTime;
    onTimeUpdate?.(videoEl.currentTime);
  }

  function handleEnded() {
    // if trim range is set, loop back to in point
    if (videoEl && app.trimRange) {
      videoEl.currentTime = app.trimRange.start;
      videoEl.play();
      return;
    }
    playing = false;
  }

  $effect(() => {
    if (videoEl) videoEl.volume = volume;
  });

  // persist volume to config
  $effect(() => {
    if (volume !== config.current.preview_volume) {
      config.update({ preview_volume: volume });
    }
  });

  // sync external seek
  $effect(() => {
    if (videoEl && Math.abs(videoEl.currentTime - currentTime) > 0.1) {
      videoEl.currentTime = currentTime;
    }
  });
</script>

<div
  class="relative flex items-center justify-center overflow-hidden cursor-pointer video-container"
  style="aspect-ratio: {app.videoInfo?.width ?? 16} / {app.videoInfo?.height ?? 9}"
  role="button"
  tabindex="0"
  onclick={togglePlay}
  onkeydown={(e) => { if (e.key === ' ' || e.key === 'Enter') { e.preventDefault(); togglePlay(); } }}
  onmouseenter={() => { showControls = true; }}
  onmouseleave={() => { showControls = false; showVolume = false; }}
>
  <!-- skeleton - visible until video is ready -->
  {#if !videoReady}
    <div class="video-skeleton">
      {#if generating}
        <span class="inline-block w-6 h-6 border-2 border-t-transparent rounded-full animate-spin" style="border-color: var(--color-accent-compress); border-top-color: transparent"></span>
        <span style="font-family: var(--font-body); font-size: var(--text-xs); color: var(--color-text-disabled)">Generating preview...</span>
      {:else}
        <i class="ti ti-movie" style="font-size: 48px; color: var(--color-text-disabled); opacity: 0.3"></i>
      {/if}
    </div>
  {/if}

  <!-- video element - hidden until loaded, then fades in -->
  {#if src && !generating}
    <video
      bind:this={videoEl}
      src={src}
      class="video-element"
      class:video-element--ready={videoReady}
      ontimeupdate={handleTimeUpdate}
      onended={handleEnded}
      onerror={handleVideoError}
      onloadeddata={() => { errorMsg = ''; videoReady = true; }}
      preload="metadata"
    >
      <track kind="captions" />
    </video>
    {#if errorMsg}
      <div class="absolute inset-0 flex flex-col items-center justify-center gap-2" style="background: var(--color-bg-elevated); border-radius: var(--radius-lg)">
        <i class="ti ti-alert-circle" style="font-size: 32px; color: var(--color-accent-warning)"></i>
        <span style="font-family: var(--font-body); font-size: var(--text-sm); color: var(--color-text-secondary); text-align: center; padding: 0 16px;">
          {errorMsg}
        </span>
      </div>
    {/if}
  {/if}

  <!-- play/pause overlay -->
  <div
    class="absolute inset-0 flex items-center justify-center"
    style="
      background: rgba(0,0,0,0.15);
      opacity: {showControls ? 1 : 0};
      transition: opacity var(--transition-fast);
      pointer-events: none;
    "
  >
    <div
      class="flex items-center justify-center rounded-full"
      style="width: 48px; height: 48px; background: rgba(0,0,0,0.5); backdrop-filter: blur(4px)"
    >
      <i
        class={playing ? 'ti ti-player-pause' : 'ti ti-player-play'}
        style="font-size: 22px; color: white; margin-left: {playing ? '0' : '2px'}"
      ></i>
    </div>
  </div>

  <!-- volume control -->
  <div
    class="absolute bottom-2 right-2 flex items-center gap-1"
    style="
      opacity: {showControls ? 1 : 0};
      transition: opacity var(--transition-fast);
      pointer-events: {showControls ? 'auto' : 'none'};
    "
    onclick={(e) => e.stopPropagation()}
    onkeydown={(e) => e.stopPropagation()}
    role="group"
  >
    {#if showVolume}
      <input
        type="range"
        min="0"
        max="1"
        step="0.05"
        bind:value={volume}
        class="volume-slider w-16"
        onclick={(e) => e.stopPropagation()}
      />
    {/if}
    <button
      type="button"
      class="flex items-center justify-center rounded cursor-pointer"
      style="width: 28px; height: 28px; background: rgba(0,0,0,0.5); border: none; color: white; backdrop-filter: blur(4px)"
      onclick={(e) => { e.stopPropagation(); showVolume = !showVolume; }}
    >
      <i class={volume === 0 ? 'ti ti-volume-off' : 'ti ti-volume'} style="font-size: 14px"></i>
    </button>
  </div>
</div>

<style>
  .video-container {
    width: 100%;
    border-radius: var(--radius-lg);
    overflow: hidden;
    background: var(--color-bg-elevated);
  }
  .video-skeleton {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    gap: 6px;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-lg);
  }
  .video-element {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: contain;
    border-radius: var(--radius-lg);
    opacity: 0;
    transition: opacity 500ms ease-in-out;
  }
  .video-element--ready {
    opacity: 1;
  }
  .volume-slider {
    -webkit-appearance: none;
    appearance: none;
    height: 4px;
    border-radius: 2px;
    background: var(--color-bg-elevated);
    outline: none;
  }
  .volume-slider::-webkit-slider-thumb {
    -webkit-appearance: none;
    width: 12px;
    height: 12px;
    border-radius: 50%;
    background: var(--color-accent-compress);
    cursor: pointer;
  }
</style>
