<script lang="ts">
  import { onMount } from 'svelte';
  import { streamUrl } from '$lib/utils/tauri';
  import { app } from '$lib/stores/app.svelte';
  import { formatTimecode, formatTimecodeShort } from '$lib/utils/format';
  // SegmentedControl replaced with custom toggle

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

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

  let trackRef: HTMLDivElement | undefined = $state();
  let innerRef: HTMLDivElement | undefined = $state();
  let dragging: 'in' | 'out' | 'scrub' | null = $state(null);
  let hoverX: number | null = $state(null);
  let hoverTime: number | null = $state(null);
  let zoomLevel = $state(1);
  let animating = $state(false); // true when trim handles should animate (button clicks, not drags)

  let inInput = $state('');
  let outInput = $state('');

  function parseTimecode(str: string): number {
    const m = str.trim().match(/^(\d{1,2}):(\d{2}):(\d{2})(?:\.(\d{1,3}))?$/);
    if (!m) return -1;
    const h = parseInt(m[1]);
    const min = parseInt(m[2]);
    const sec = parseInt(m[3]);
    const ms = m[4] ? parseInt(m[4].padEnd(3, '0')) : 0;
    return h * 3600 + min * 60 + sec + ms / 1000;
  }

  function commitIn() {
    const t = parseTimecode(inInput);
    if (t >= 0 && t < outTime) {
      app.setTrimRange(Math.max(0, t), outTime);
    }
    inInput = formatTimecode(inTime);
  }

  function commitOut() {
    const t = parseTimecode(outInput);
    if (t > inTime && t <= duration) {
      app.setTrimRange(inTime, t);
    }
    outInput = formatTimecode(outTime);
  }

  function handleInKey(e: KeyboardEvent) {
    if (e.key === 'Enter') (e.target as HTMLInputElement).blur();
  }

  function handleOutKey(e: KeyboardEvent) {
    if (e.key === 'Enter') (e.target as HTMLInputElement).blur();
  }

  // keep input values in sync when trim changes externally (drag etc)
  $effect(() => { inInput = formatTimecode(inTime); });
  $effect(() => { outInput = formatTimecode(outTime); });

  let duration = $derived(app.videoInfo?.duration ?? 0);
  let keyframes = $derived(app.videoInfo?.keyframe_times ?? []);

  let inTime = $derived(app.trimRange?.start ?? 0);
  let outTime = $derived(app.trimRange?.end ?? duration);
  let inPct = $derived(duration > 0 ? (inTime / duration) * 100 : 0);
  let outPct = $derived(duration > 0 ? (outTime / duration) * 100 : 100);
  let playheadPct = $derived(duration > 0 ? (currentTime / duration) * 100 : 0);
  let selectedDuration = $derived(outTime - inTime);

  let trimModeLabel = $derived(app.trimMode === 'keyframe' ? 'Keyframe snap' : 'Smart cut');
  let modeOptions = ['Keyframe snap', 'Smart cut'];

  function pctFromEvent(e: MouseEvent): number {
    if (!trackRef || !innerRef) return 0;
    const rect = trackRef.getBoundingClientRect();
    const scrollLeft = trackRef.scrollLeft;
    const innerWidth = innerRef.offsetWidth;
    const x = e.clientX - rect.left + scrollLeft;
    return Math.max(0, Math.min(100, (x / innerWidth) * 100));
  }

  function timeFromPct(pct: number): number {
    return (pct / 100) * duration;
  }

  function nearestKeyframe(time: number): number {
    if (keyframes.length === 0) return time;
    let best = keyframes[0];
    let dist = Math.abs(time - best);
    for (const kf of keyframes) {
      const d = Math.abs(time - kf);
      if (d < dist) { best = kf; dist = d; }
    }
    return best;
  }

  function snapTime(time: number): number {
    if (app.trimMode === 'keyframe') return nearestKeyframe(time);
    return time;
  }

  let scrubStartX = 0;
  let scrubStartTime = 0;

  function handlePointerDown(e: PointerEvent, mode: 'scrub' | 'in' | 'out') {
    if (dragging) return;
    dragging = mode;
    (e.currentTarget as HTMLElement).setPointerCapture(e.pointerId);

    if (mode === 'scrub') {
      const pct = pctFromEvent(e);
      const time = timeFromPct(pct);
      onSeek(time);
      scrubStartX = e.clientX;
      scrubStartTime = time;
    }
  }

  function handlePointerMove(e: PointerEvent) {
    if (!trackRef || !innerRef || !dragging) return;
    const rect = trackRef.getBoundingClientRect();
    const innerWidth = innerRef.offsetWidth;

    if (dragging === 'scrub') {
      const vertDist = Math.abs(e.clientY - (rect.top + rect.height / 2));
      const speed = vertDist < 30 ? 1 : vertDist < 80 ? 0.5 : vertDist < 150 ? 0.25 : 0.1;
      const dx = e.clientX - scrubStartX;
      const pxPerSecond = innerWidth / duration;
      const timeDelta = (dx * speed) / pxPerSecond;
      const newTime = Math.max(0, Math.min(duration, scrubStartTime + timeDelta));
      scrubStartX = e.clientX;
      scrubStartTime = newTime;
      onSeek(newTime);
      return;
    }

    const scrollLeft = trackRef.scrollLeft;
    const x = e.clientX - rect.left + scrollLeft;
    const pct = Math.max(0, Math.min(100, (x / innerWidth) * 100));
    const time = timeFromPct(pct);

    if (dragging === 'in') {
      const snapped = snapTime(Math.min(time, outTime - 0.1));
      app.setTrimRange(Math.max(0, snapped), outTime);
      onSeek(Math.max(0, snapped));
    } else if (dragging === 'out') {
      const snapped = snapTime(Math.max(time, inTime + 0.1));
      app.setTrimRange(inTime, Math.min(duration, snapped));
      onSeek(Math.min(duration, snapped));
    }
  }

  function handlePointerUp() {
    dragging = null;
  }

  function handleHoverMove(e: MouseEvent) {
    if (!trackRef || !innerRef || dragging) return;
    const rect = trackRef.getBoundingClientRect();
    const scrollLeft = trackRef.scrollLeft;
    const innerWidth = innerRef.offsetWidth;
    const x = e.clientX - rect.left + scrollLeft;
    hoverTime = timeFromPct(Math.max(0, Math.min(100, (x / innerWidth) * 100)));
    // viewport-relative tooltip position
    hoverX = Math.max(62, Math.min(rect.width - 62, e.clientX - rect.left));
  }

  function handleMouseLeave() {
    hoverX = null;
    hoverTime = null;
  }

  function handleWheel(e: WheelEvent) {
    e.preventDefault();
    if (e.deltaY < 0) zoomLevel = Math.min(8, zoomLevel * 1.15);
    else zoomLevel = Math.max(1, zoomLevel / 1.15);
  }

  function handleModeChange(val: string) {
    app.trimMode = val === 'Keyframe snap' ? 'keyframe' : 'smart';
  }

  function handleTrackKeydown(e: KeyboardEvent) {
    if (e.key === 'ArrowLeft') {
      e.preventDefault();
      app.seek(app.currentTime - (e.shiftKey ? 5 : 1));
    } else if (e.key === 'ArrowRight') {
      e.preventDefault();
      app.seek(app.currentTime + (e.shiftKey ? 5 : 1));
    } else if (e.key === 'Home') {
      e.preventDefault();
      app.seek(0);
    } else if (e.key === 'End') {
      e.preventDefault();
      app.seek(duration);
    } else if (e.key === 'i' || e.key === 'I') {
      e.preventDefault();
      app.setTrimRange(currentTime, outTime);
      onSeek(currentTime);
    } else if (e.key === 'o' || e.key === 'O') {
      e.preventDefault();
      app.setTrimRange(inTime, currentTime);
      onSeek(currentTime);
    }
  }

</script>

<div class="flex flex-col gap-2 w-full">
  <!-- main filmstrip area -->
  <div class="tl-track-outer">
  <div
    bind:this={trackRef}
    class="relative w-full cursor-crosshair select-none"
    class:tl-animating={animating}
    style="height: 72px; border-radius: var(--radius-md); overflow-x: auto; overflow-y: visible; background: var(--color-bg-elevated); border: 1px solid var(--color-border); scrollbar-width: none;"
    role="slider"
    aria-valuemin={0}
    aria-valuemax={duration}
    aria-valuenow={currentTime}
    tabindex="0"
    onpointerdown={(e) => handlePointerDown(e, 'scrub')}
    onpointermove={handlePointerMove}
    onpointerup={handlePointerUp}
    onmousemove={handleHoverMove}
    onmouseleave={handleMouseLeave}
    onwheel={handleWheel}
    onkeydown={handleTrackKeydown}
  >
    <div bind:this={innerRef} class="tl-inner" style="width: calc(100% * {zoomLevel}); position: relative; height: 100%;">
    <!-- thumbnail strip -->
    {#if app.thumbnails.length > 0}
      <div
        class="absolute inset-0 flex"
        style="opacity: 0.8"
      >
        {#each app.thumbnails as thumb, i}
          <div
            class="h-full flex-1"
            style="background: url('{streamUrl(thumb)}') center/cover no-repeat"
          ></div>
        {/each}
      </div>
    {/if}

    <!-- keyframe color segments -->
    {#each keyframes as kf, i}
      {#if i > 0}
        {@const prevPct = (keyframes[i - 1] / duration) * 100}
        {@const kfPct = (kf / duration) * 100}
        <div
          class="absolute top-0 h-full"
          style="
            left: {prevPct}%;
            width: {kfPct - prevPct}%;
            background: {i % 2 === 0 ? 'rgba(5,150,105,0.05)' : 'rgba(37,99,235,0.05)'};
          "
        ></div>
      {/if}
    {/each}

    <!-- dark overlay for unselected regions -->
    {#if app.trimRange}
      <div
        class="absolute top-0 h-full"
        style="left: 0; width: {inPct}%; background: rgba(0,0,0,0.35)"
      ></div>
      <div
        class="absolute top-0 h-full"
        style="left: {outPct}%; right: 0; background: rgba(0,0,0,0.35)"
      ></div>
    {/if}

    <!-- selected region top/bottom border -->
    {#if app.trimRange}
      <div
        class="absolute z-10 pointer-events-none"
        style="
          left: calc({inPct}%);
          width: calc({outPct - inPct}%);
          top: 0;
          height: 100%;
          border-top: 2px solid var(--color-accent-trim);
          border-bottom: 2px solid var(--color-accent-trim);
        "
      ></div>
    {/if}

    <!-- IN handle -->
    {#if app.trimRange}
    <div
      class="trim-handle trim-handle--in"
      style="left: calc({inPct}% - {inPct > 0 ? 12 : 0}px);"
      onpointerdown={(e) => handlePointerDown(e, 'in')}
      onpointermove={handlePointerMove}
      onpointerup={handlePointerUp}
      role="slider"
      aria-label="Trim in point"
      aria-valuenow={inTime}
      tabindex="0"
    >
      <div class="trim-handle-inner">
        <svg width="6" height="20" viewBox="0 0 6 20" fill="none">
          <line x1="1" y1="3" x2="1" y2="17" stroke="rgba(255,255,255,0.7)" stroke-width="1.5" stroke-linecap="round"/>
          <line x1="4.5" y1="3" x2="4.5" y2="17" stroke="rgba(255,255,255,0.7)" stroke-width="1.5" stroke-linecap="round"/>
        </svg>
      </div>
    </div>

    <!-- OUT handle -->
    <div
      class="trim-handle trim-handle--out"
      style="left: calc({outPct}% - {outPct >= 100 ? 12 : 0}px);"
      onpointerdown={(e) => handlePointerDown(e, 'out')}
      onpointermove={handlePointerMove}
      onpointerup={handlePointerUp}
      role="slider"
      aria-label="Trim out point"
      aria-valuenow={outTime}
      tabindex="0"
    >
      <div class="trim-handle-inner">
        <svg width="6" height="20" viewBox="0 0 6 20" fill="none">
          <line x1="1" y1="3" x2="1" y2="17" stroke="rgba(255,255,255,0.7)" stroke-width="1.5" stroke-linecap="round"/>
          <line x1="4.5" y1="3" x2="4.5" y2="17" stroke="rgba(255,255,255,0.7)" stroke-width="1.5" stroke-linecap="round"/>
        </svg>
      </div>
    </div>
    {/if}

    <!-- playhead -->
    <div
      class="playhead-wrapper"
      style="--ph-pct: {playheadPct}"
    >
      <div class="playhead-line"></div>
    </div>
    </div>
  </div>

  <!-- hover tooltip -->
  {#if hoverX !== null && hoverTime !== null && !dragging}
    <div
      class="absolute z-40 pointer-events-none"
      style="
        bottom: calc(100% + 8px);
        left: {hoverX}px;
        transform: translateX(-50%);
      "
    >
      <div
        class="flex flex-col items-center gap-1"
        style="
          background: var(--color-bg-elevated);
          border: 1px solid var(--color-border);
          border-radius: var(--radius-sm);
          padding: 4px 6px;
          box-shadow: 0 2px 8px rgba(0,0,0,0.2);
        "
      >
        <!-- mini thumb -->
        {#if duration > 0 && app.thumbnails.length > 0}
          {@const thumbIdx = Math.min(Math.floor((hoverTime / duration) * app.thumbnails.length), app.thumbnails.length - 1)}
          <div
            class="rounded"
            style="width: 120px; height: 68px; background: url('{streamUrl(app.thumbnails[thumbIdx])}') center/cover no-repeat"
          ></div>
        {:else}
          <div
            class="rounded"
            style="width: 120px; height: 68px; background: var(--color-bg-surface)"
          ></div>
        {/if}
        <span class="font-mono text-xs" style="color: var(--color-text-secondary)">
          {formatTimecode(hoverTime)}
        </span>
      </div>
    </div>
  {/if}
  </div>

  <!-- below timeline: controls row -->
  <div class="tl-controls">
    <!-- left: cut mode toggle -->
    <div class="tl-mode">
      <button
        type="button"
        class="tl-mode-btn"
        class:tl-mode-btn--active={app.trimMode === 'keyframe'}
        onclick={() => handleModeChange('Keyframe snap')}
      >
        <i class="ti ti-scissors" style="font-size: 13px"></i>
        Keyframe
      </button>
      <button
        type="button"
        class="tl-mode-btn"
        class:tl-mode-btn--active={app.trimMode === 'smart'}
        onclick={() => handleModeChange('Smart cut')}
      >
        <i class="ti ti-cut" style="font-size: 13px"></i>
        Smart
      </button>
    </div>

    <!-- right: timecodes -->
    <div class="tl-times">
      <div class="tl-time-field">
        <button
          type="button"
          class="tl-time-label tl-time-label--btn"
          title="Set in point to current position"
          onclick={() => { animating = true; app.setTrimRange(currentTime, outTime); onSeek(currentTime); setTimeout(() => { animating = false; }, 500); }}
        >IN</button>
        <input
          type="text"
          class="tl-time-input"
          bind:value={inInput}
          onblur={commitIn}
          onkeydown={handleInKey}
          onfocus={(e) => (e.target as HTMLInputElement).select()}
        />
        <span class="tl-kbd-hint"><kbd>I</kbd></span>
      </div>
      <div class="tl-time-field">
        <button
          type="button"
          class="tl-time-label tl-time-label--btn"
          title="Set out point to current position"
          onclick={() => { animating = true; app.setTrimRange(inTime, currentTime); onSeek(currentTime); setTimeout(() => { animating = false; }, 500); }}
        >OUT</button>
        <input
          type="text"
          class="tl-time-input"
          bind:value={outInput}
          onblur={commitOut}
          onkeydown={handleOutKey}
          onfocus={(e) => (e.target as HTMLInputElement).select()}
        />
        <span class="tl-kbd-hint"><kbd>O</kbd></span>
      </div>
      <button
        type="button"
        class="tl-duration"
        title="Reset trim to full video"
        onclick={() => { animating = true; app.clearTrimRange(); setTimeout(() => { animating = false; }, 500); }}
      >
        <i class="ti ti-clock" style="font-size: 12px"></i>
        {formatTimecodeShort(selectedDuration)}
      </button>
    </div>
  </div>
</div>

<style>
  .tl-controls {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
  }

  .tl-mode {
    display: flex;
    gap: 2px;
    background: var(--color-bg-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    padding: 2px;
  }
  .tl-mode-btn {
    display: flex;
    align-items: center;
    gap: 5px;
    padding: 5px 10px;
    border: none;
    border-radius: 5px;
    background: none;
    color: var(--color-text-disabled);
    font-family: var(--font-body);
    font-size: 11px;
    font-weight: 600;
    cursor: pointer;
    transition: color var(--transition-fast), background var(--transition-fast);
    white-space: nowrap;
  }
  .tl-mode-btn:hover {
    color: var(--color-text-secondary);
  }
  .tl-mode-btn--active {
    background: var(--color-accent-trim);
    color: white;
  }
  .tl-mode-btn--active:hover {
    color: white;
  }

  .tl-times {
    display: flex;
    align-items: center;
    gap: 8px;
  }

  .tl-time-field {
    display: flex;
    align-items: stretch;
    background: var(--color-bg-surface);
    border: 1px solid var(--color-border);
    border-radius: 5px;
    overflow: hidden;
  }
  .tl-time-field:focus-within {
    border-color: var(--color-accent-trim);
  }

  .tl-time-label {
    display: flex;
    align-items: center;
    padding: 0 8px;
    font-family: var(--font-body);
    font-size: 9px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--color-text-disabled);
    background: var(--color-bg-elevated);
    border: none;
    border-right: 1px solid var(--color-border);
    user-select: none;
  }
  .tl-time-label--btn {
    cursor: pointer;
    transition: color var(--transition-fast), background var(--transition-fast);
  }
  .tl-time-label--btn:hover {
    color: var(--color-accent-trim);
    background: var(--color-bg-surface);
  }

  .tl-time-input {
    width: 90px;
    padding: 5px 8px;
    font-family: var(--font-mono);
    font-size: 11px;
    color: var(--color-text-secondary);
    background: none;
    border: none;
    outline: none;
  }
  .tl-time-input:focus {
    color: var(--color-text-primary);
  }

  .tl-duration {
    display: flex;
    align-items: center;
    gap: 4px;
    padding: 5px 10px;
    font-family: var(--font-mono);
    font-size: 11px;
    font-weight: 600;
    color: var(--color-text-primary);
    background: var(--color-bg-surface);
    border: 1px solid var(--color-border);
    border-radius: 5px;
    cursor: pointer;
    transition: border-color var(--transition-fast), color var(--transition-fast);
  }
  .tl-duration:hover {
    border-color: var(--color-text-secondary);
    color: var(--color-accent-compress);
  }

  /* when animating is active (button clicks), transition all positioned elements */
  .tl-animating .trim-handle,
  .tl-animating .trim-handle ~ div,
  :global(.tl-animating) :is([style*="left:"], [style*="width:"]) {
    transition: left 500ms ease-in-out, width 500ms ease-in-out, right 500ms ease-in-out;
  }

  .tl-track-outer {
    position: relative;
    height: 72px;
  }

  .tl-inner {
    min-width: 100%;
  }

  .playhead-wrapper {
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    pointer-events: none;
    z-index: 30;
    will-change: transform;
    transform: translateX(calc(var(--ph-pct) * 1% - 1px));
  }
  .playhead-line {
    width: 2px;
    height: 100%;
    background: var(--color-accent-compress);
    box-shadow: 0 0 6px rgba(5,150,105,0.7), 0 0 12px rgba(5,150,105,0.4);
  }

  .tl-kbd-hint {
    display: flex;
    align-items: center;
    padding: 0 6px;
    font-family: var(--font-mono);
    font-size: 9px;
    font-weight: 600;
    color: var(--color-text-disabled);
    user-select: none;
  }
  .tl-kbd-hint kbd {
    background: var(--color-bg-elevated);
    border: 1px solid var(--color-border);
    border-radius: 3px;
    padding: 1px 4px;
    font-size: 9px;
  }

  .trim-handle {
    position: absolute;
    top: 0;
    height: 100%;
    width: 14px;
    z-index: 20;
    cursor: ew-resize;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--color-accent-trim);
  }
  .trim-handle--in {
    border-radius: 4px 0 0 4px;
  }
  .trim-handle--out {
    border-radius: 0 4px 4px 0;
  }
  .trim-handle-inner {
    display: flex;
    align-items: center;
    justify-content: center;
    transition: transform var(--transition-fast), opacity var(--transition-fast);
    opacity: 0.7;
  }
  .trim-handle:hover .trim-handle-inner {
    opacity: 1;
    transform: scaleX(1.4);
  }
</style>
