import { useRef, useCallback, useState, useEffect } from 'react';
import { useCutsceneStore, useSelectedCutscene } from '../../store/cutsceneStore';
import { useShallow } from 'zustand/react/shallow';
import styles from './Timeline.module.css';

const LABEL_WIDTH = 140;
const ROW_HEIGHT = 32;
const SUBTITLE_ROW_HEIGHT = 14;
const MIN_ZOOM = 20;   // px per second
const MAX_ZOOM = 400;

const LAYER_COLORS = ['#4a7fc1', '#c17a4a', '#4ac17a', '#c14a7a', '#7a4ac1', '#c1b44a', '#4ac1c1'];

function layerColor(i: number) { return LAYER_COLORS[i % LAYER_COLORS.length]; }

function basename(path: string) {
  return path.split('/').pop() ?? path;
}

export default function Timeline() {
  const cutscene = useSelectedCutscene();
  const { selectedLayerIndex, currentTimeMs, playState } = useCutsceneStore(useShallow(s => ({
    selectedLayerIndex: s.selectedLayerIndex,
    currentTimeMs: s.currentTimeMs,
    playState: s.playState,
  })));
  const { selectLayer, addLayer, removeLayer, moveLayerUp, moveLayerDown, updateLayer, setCurrentTime, setPlayState } = useCutsceneStore(useShallow(s => ({
    selectLayer: s.selectLayer,
    addLayer: s.addLayer,
    removeLayer: s.removeLayer,
    moveLayerUp: s.moveLayerUp,
    moveLayerDown: s.moveLayerDown,
    updateLayer: s.updateLayer,
    setCurrentTime: s.setCurrentTime,
    setPlayState: s.setPlayState,
  })));

  const [pxPerSec, setPxPerSec] = useState(60);
  const scrollRef = useRef<HTMLDivElement>(null);
  const isDraggingPlayhead = useRef(false);
  const dragState = useRef<{
    type: 'move' | 'left' | 'right';
    layerIndex: number;
    startX: number;
    startMs: number;
    endMs: number;
    durationMs: number;
  } | null>(null);

  const msToX = useCallback((ms: number) => (ms / 1000) * pxPerSec, [pxPerSec]);
  const xToMs = useCallback((x: number) => Math.max(0, Math.round((x / pxPerSec) * 1000)), [pxPerSec]);

  const totalMs = cutscene
    ? Math.max(
        cutscene.durationMs,
        cutscene.imageSegments.reduce((m, s) => Math.max(m, s.endMs), 0),
        10000,
      ) + 2000
    : 12000;

  const rulerWidth = Math.ceil(msToX(totalMs));

  // Ruler ticks
  const tickStepMs = pxPerSec >= 100 ? 500 : pxPerSec >= 50 ? 1000 : 2000;
  const labelStepMs = pxPerSec >= 100 ? 1000 : pxPerSec >= 50 ? 2000 : 4000;
  const ticks: number[] = [];
  for (let ms = 0; ms <= totalMs; ms += tickStepMs) ticks.push(ms);

  // Scroll wheel zoom
  useEffect(() => {
    const el = scrollRef.current;
    if (!el) return;
    function onWheel(e: WheelEvent) {
      if (!e.ctrlKey && !e.metaKey) return;
      e.preventDefault();
      setPxPerSec(prev => Math.min(MAX_ZOOM, Math.max(MIN_ZOOM, prev * (e.deltaY < 0 ? 1.15 : 0.87))));
    }
    el.addEventListener('wheel', onWheel, { passive: false });
    return () => el.removeEventListener('wheel', onWheel);
  }, []);

  // Auto-scroll playhead into view while playing
  useEffect(() => {
    if (playState !== 'playing') return;
    const el = scrollRef.current;
    if (!el) return;
    const x = msToX(currentTimeMs) + LABEL_WIDTH;
    const { scrollLeft, clientWidth } = el;
    if (x > scrollLeft + clientWidth - 40) {
      el.scrollLeft = x - clientWidth + 80;
    }
  }, [currentTimeMs, playState, msToX]);

  // ── Playhead drag ──────────────────────────────────────────────────────────
  function onRulerMouseDown(e: React.MouseEvent) {
    if (e.button !== 0) return;
    isDraggingPlayhead.current = true;
    const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();
    const x = e.clientX - rect.left - LABEL_WIDTH + (scrollRef.current?.scrollLeft ?? 0);
    setCurrentTime(xToMs(x));
    if (playState === 'playing') setPlayState('paused');

    function onMove(ev: MouseEvent) {
      const x2 = ev.clientX - rect.left - LABEL_WIDTH + (scrollRef.current?.scrollLeft ?? 0);
      setCurrentTime(xToMs(x2));
    }
    function onUp() {
      isDraggingPlayhead.current = false;
      window.removeEventListener('mousemove', onMove);
      window.removeEventListener('mouseup', onUp);
    }
    window.addEventListener('mousemove', onMove);
    window.addEventListener('mouseup', onUp);
  }

  // ── Segment bar drag ───────────────────────────────────────────────────────
  function onBarMouseDown(e: React.MouseEvent, layerIndex: number, type: 'move' | 'left' | 'right') {
    e.preventDefault();
    e.stopPropagation();
    selectLayer(layerIndex);
    const seg = cutscene!.imageSegments[layerIndex];
    dragState.current = {
      type,
      layerIndex,
      startX: e.clientX,
      startMs: seg.startMs,
      endMs: seg.endMs,
      durationMs: seg.endMs - seg.startMs,
    };

    function onMove(ev: MouseEvent) {
      if (!dragState.current) return;
      const dx = ev.clientX - dragState.current.startX;
      const dMs = Math.round((dx / pxPerSec) * 1000);
      const { type, layerIndex: li, startMs, endMs, durationMs } = dragState.current;

      if (type === 'move') {
        const newStart = Math.max(0, startMs + dMs);
        updateLayer(li, { startMs: newStart, endMs: newStart + durationMs });
      } else if (type === 'left') {
        const newStart = Math.max(0, Math.min(endMs - 100, startMs + dMs));
        updateLayer(li, { startMs: newStart });
      } else {
        const newEnd = Math.max(startMs + 100, endMs + dMs);
        updateLayer(li, { endMs: newEnd });
      }
    }
    function onUp() {
      dragState.current = null;
      window.removeEventListener('mousemove', onMove);
      window.removeEventListener('mouseup', onUp);
    }
    window.addEventListener('mousemove', onMove);
    window.addEventListener('mouseup', onUp);
  }

  const playheadX = msToX(currentTimeMs) + LABEL_WIDTH;

  // Subtitle timing for display
  let subtitleBlocks: { x: number; w: number; text: string }[] = [];
  if (cutscene) {
    let elapsed = 0;
    for (const line of cutscene.lines) {
      const dur = line.durationMs > 0
        ? line.durationMs
        : Math.max(1500, Math.round((line.text.length / 17) * 1000));
      subtitleBlocks.push({ x: msToX(elapsed), w: msToX(dur), text: line.text || '…' });
      elapsed += dur;
    }
  }

  const layerCount = cutscene?.imageSegments.length ?? 0;
  const totalHeight = layerCount * ROW_HEIGHT + SUBTITLE_ROW_HEIGHT + 20;

  return (
    <div className={styles.container}>
      {/* Toolbar */}
      <div className={styles.toolbar}>
        <button className={styles.tbBtn} onClick={addLayer} disabled={!cutscene} title="Add layer">+ Layer</button>
        {selectedLayerIndex !== null && cutscene && (
          <>
            <button className={styles.tbBtn} onClick={() => moveLayerUp(selectedLayerIndex!)} disabled={selectedLayerIndex! <= 0} title="Move up">↑</button>
            <button className={styles.tbBtn} onClick={() => moveLayerDown(selectedLayerIndex!)} disabled={selectedLayerIndex! >= layerCount - 1} title="Move down">↓</button>
            <button className={styles.tbBtn} onClick={() => removeLayer(selectedLayerIndex!)} title="Remove layer" style={{ color: '#e06c6c' }}>✕ Layer</button>
          </>
        )}
        <div className={styles.spacer} />
        <span className={styles.zoomLabel}>Zoom:</span>
        <button className={styles.tbBtn} onClick={() => setPxPerSec(p => Math.max(MIN_ZOOM, p * 0.75))}>−</button>
        <button className={styles.tbBtn} onClick={() => setPxPerSec(p => Math.min(MAX_ZOOM, p * 1.33))}>+</button>
        <button className={styles.tbBtn} onClick={() => setPxPerSec(60)}>Reset</button>
      </div>

      {/* Scrollable area */}
      <div className={styles.scroll} ref={scrollRef}>
        {/* Ruler */}
        <div
          className={styles.ruler}
          style={{ width: LABEL_WIDTH + rulerWidth }}
          onMouseDown={onRulerMouseDown}
        >
          <div style={{ width: LABEL_WIDTH, flexShrink: 0 }} />
          <div style={{ position: 'relative', flex: 1 }}>
            {ticks.map(ms => (
              <div
                key={ms}
                className={styles.tick}
                style={{ left: msToX(ms) }}
              >
                {ms % labelStepMs === 0 && (
                  <span className={styles.tickLabel}>{ms / 1000}s</span>
                )}
              </div>
            ))}
          </div>
        </div>

        {/* Layers + playhead overlay */}
        <div
          className={styles.layersArea}
          style={{ width: LABEL_WIDTH + rulerWidth, minHeight: totalHeight }}
        >
          {/* Playhead */}
          <div className={styles.playhead} style={{ left: playheadX }} />

          {/* Grid lines */}
          {ticks.filter(ms => ms % labelStepMs === 0).map(ms => (
            <div key={ms} className={styles.gridLine} style={{ left: LABEL_WIDTH + msToX(ms) }} />
          ))}

          {/* Layer rows */}
          {cutscene?.imageSegments.map((seg, i) => {
            const isSelected = selectedLayerIndex === i;
            const color = layerColor(i);
            const barX = LABEL_WIDTH + msToX(seg.startMs);
            const barW = Math.max(4, msToX(seg.endMs) - msToX(seg.startMs));
            return (
              <div
                key={i}
                className={`${styles.row} ${isSelected ? styles.rowSelected : ''}`}
                style={{ top: i * ROW_HEIGHT }}
                onClick={() => selectLayer(i)}
              >
                {/* Label */}
                <div className={styles.rowLabel} style={{ borderLeft: `3px solid ${color}` }}>
                  <span className={styles.layerName}>{basename(seg.path) || `Layer ${i + 1}`}</span>
                </div>

                {/* Bar */}
                <div
                  className={styles.bar}
                  style={{ left: barX, width: barW, background: color + (isSelected ? 'cc' : '88') }}
                  onMouseDown={e => onBarMouseDown(e, i, 'move')}
                >
                  <div className={`${styles.handle} ${styles.handleLeft}`}
                    onMouseDown={e => onBarMouseDown(e, i, 'left')} />
                  <div className={`${styles.handle} ${styles.handleRight}`}
                    onMouseDown={e => onBarMouseDown(e, i, 'right')} />
                </div>
              </div>
            );
          })}

          {/* Subtitle blocks row */}
          {cutscene && (
            <div
              className={styles.subtitleRow}
              style={{ top: layerCount * ROW_HEIGHT }}
            >
              <div className={styles.subtitleLabel}>Subtitles</div>
              {subtitleBlocks.map((b, i) => (
                <div
                  key={i}
                  className={styles.subtitleBlock}
                  style={{ left: LABEL_WIDTH + b.x, width: Math.max(2, b.w) }}
                  title={b.text}
                />
              ))}
            </div>
          )}
        </div>
      </div>
    </div>
  );
}
