/* Timeline — draggable, trimmable clips with thumbnail strips and snap-to-neighbor */
const { useRef, useEffect: useEff, useState: useS } = React;

const PX_PER_SEC = 72; // base pixel scale

function Timeline({
  clips,
  media,
  totalDuration,
  playheadTime,
  selectedIds,
  activeSelectedId,
  isPlaying,
  textOverlays,
  showThumbs,
  clipGap,
  showGrid,
  onSelect,
  onScrub,
  onDropMedia,
  onMoveClip,
  onTrimClip,
  onDeleteClip,
}) {
  const viewportRef = useRef(null);
  const [dragState, setDragState] = useS(null);
  const [trackDrag, setTrackDrag] = useS(false);

  const trackDuration = Math.max(totalDuration, 12);
  const trackWidth = trackDuration * PX_PER_SEC;

  // Scrubbing
  const handleScrubDown = (e) => {
    if (e.target.closest(".clip")) return;
    onSelect({ mode: "clear" });
    const rect = viewportRef.current.getBoundingClientRect();
    const x = e.clientX - rect.left + viewportRef.current.scrollLeft;
    onScrub(Math.max(0, x / PX_PER_SEC));

    const move = (ev) => {
      const nx = ev.clientX - rect.left + viewportRef.current.scrollLeft;
      onScrub(Math.max(0, nx / PX_PER_SEC));
    };
    const up = () => {
      window.removeEventListener("mousemove", move);
      window.removeEventListener("mouseup", up);
    };
    window.addEventListener("mousemove", move);
    window.addEventListener("mouseup", up);
  };

  // Clip drag (move/trim)
  const beginClipDrag = (e, clip, mode) => {
    e.stopPropagation();
    e.preventDefault();
    const selectMode = mode === "move"
      ? (e.shiftKey ? "range" : (e.metaKey || e.ctrlKey ? "toggle" : "plain"))
      : "plain";
    onSelect({ id: clip.id, mode: selectMode });
    if (mode === "move" && selectMode !== "plain") {
      return;
    }
    const startX = e.clientX;
    setDragState({ clipId: clip.id, mode, startX, initStart: clip.start, initDur: clip.duration });

    const move = (ev) => {
      const dx = ev.clientX - startX;
      const dt = dx / PX_PER_SEC;
      if (mode === "move") {
        onMoveClip(clip.id, Math.max(0, clip.start + dt));
      } else if (mode === "trim-r") {
        onTrimClip(clip.id, clip.duration + dt, "right");
      } else if (mode === "trim-l") {
        onTrimClip(clip.id, dt, "left");
      }
    };
    const up = () => {
      window.removeEventListener("mousemove", move);
      window.removeEventListener("mouseup", up);
      setDragState(null);
    };
    window.addEventListener("mousemove", move);
    window.addEventListener("mouseup", up);
  };

  // Media drop
  const onDragOver = (e) => { e.preventDefault(); setTrackDrag(true); };
  const onDragLeave = () => setTrackDrag(false);
  const onDrop = (e, trackIdx) => {
    e.preventDefault();
    setTrackDrag(false);
    const mediaId = e.dataTransfer.getData("text/media-id");
    if (!mediaId) return;
    const rect = viewportRef.current.getBoundingClientRect();
    const x = e.clientX - rect.left + viewportRef.current.scrollLeft;
    const t = Math.max(0, x / PX_PER_SEC);
    onDropMedia(mediaId, trackIdx, t);
  };

  // Auto-scroll playhead
  useEff(() => {
    if (!viewportRef.current || !isPlaying) return;
    const px = playheadTime * PX_PER_SEC;
    const vp = viewportRef.current;
    if (px > vp.scrollLeft + vp.clientWidth - 80) vp.scrollLeft = px - vp.clientWidth + 120;
    if (px < vp.scrollLeft) vp.scrollLeft = px;
  }, [playheadTime, isPlaying]);

  const ruler = buildRuler(trackDuration);

  return (
    <div className="timeline">
      <div className="tl-meta">
        <div className="time">
          <span className="cur">{formatTC(playheadTime)}</span>
          <span>/</span>
          <span className="total">{formatTC(totalDuration)}</span>
        </div>
        <div className="fps">
          <span>zoom · 100%</span>
          <span>snap · on</span>
          <span>magnet · on</span>
        </div>
      </div>

      <div className="tl-body">
        <div className="tl-track-labels" style={{gridTemplateRows:"26px 96px 44px 36px"}}>
          <div className="tl-track-label" style={{height:26, borderBottom:"1px solid var(--line-1)"}}></div>
          <div className="tl-track-label v" style={{height:96}}>
            <span className="dot"/>V1
          </div>
          <div className="tl-track-label a" style={{height:44}}>
            <span className="dot"/>A1
          </div>
          <div className="tl-track-label t" style={{height:36}}>
            <span className="dot"/>T1
          </div>
        </div>

        <div className="tl-viewport" ref={viewportRef} onMouseDown={handleScrubDown}>
          <div style={{width: trackWidth, position: "relative"}}>
            <div className="tl-ruler">
              {ruler.map((r, i) => (
                <React.Fragment key={i}>
                  <div className={"ruler-tick " + (r.minor ? "minor" : "")} style={{left: r.x}} />
                  {!r.minor && <div className="ruler-label" style={{left: r.x}}>{r.label}</div>}
                </React.Fragment>
              ))}
            </div>

            <div className="tl-tracks">
              <Track
                kind="v"
                height={96}
                clips={clips.filter((c) => c.track === 0)}
                media={media}
                selectedIds={selectedIds}
                activeSelectedId={activeSelectedId}
                showThumbs={showThumbs}
                showGrid={showGrid}
                onBeginDrag={beginClipDrag}
                onSelect={onSelect}
                onDragOver={onDragOver}
                onDragLeave={onDragLeave}
                onDrop={(e) => onDrop(e, 0)}
                trackDrag={trackDrag}
              />
              <Track
                kind="a"
                height={44}
                clips={clips.filter((c) => c.track === 1)}
                media={media}
                selectedIds={selectedIds}
                activeSelectedId={activeSelectedId}
                showThumbs={showThumbs}
                showGrid={showGrid}
                onBeginDrag={beginClipDrag}
                onSelect={onSelect}
                onDragOver={onDragOver}
                onDragLeave={onDragLeave}
                onDrop={(e) => onDrop(e, 1)}
                trackDrag={trackDrag}
              />
              <TextOverlayTrack
                overlays={textOverlays}
                height={36}
                showGrid={showGrid}
              />
            </div>

            <div className="playhead" style={{left: playheadTime * PX_PER_SEC}}>
              <div className="playhead-head"/>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

function TextOverlayTrack({ overlays, height, showGrid }) {
  const safeOverlays = Array.isArray(overlays) ? overlays : [];
  return (
    <div className="tl-track t" style={{height}}>
      {showGrid && <div className="tl-grid" style={{backgroundSize: `${PX_PER_SEC}px 100%`}}/>}
      {safeOverlays.map((cue) => {
        const left = cue.start * PX_PER_SEC;
        const width = Math.max(14, (cue.end - cue.start) * PX_PER_SEC);
        const label = cue.text.replace(/\n/g, " / ");
        return (
          <div
            key={cue.id}
            className="text-layer-clip"
            style={{left, width}}
            title={`${formatTC(cue.start)} - ${formatTC(cue.end)}\n${cue.text}`}
          >
            <span className="text-layer-tag">TXT</span>
            <span className="text-layer-name">{label}</span>
          </div>
        );
      })}
    </div>
  );
}

function Track({
  kind,
  height,
  clips,
  media,
  selectedIds,
  activeSelectedId,
  showThumbs,
  showGrid,
  onBeginDrag,
  onSelect,
  onDragOver,
  onDragLeave,
  onDrop,
  trackDrag,
}) {
  const selectedSet = new Set(selectedIds || []);
  return (
    <div
      className={"tl-track " + kind + (trackDrag ? " dragover" : "")}
      style={{height}}
      onDragOver={onDragOver}
      onDragLeave={onDragLeave}
      onDrop={onDrop}
    >
      {showGrid && <div className="tl-grid" style={{backgroundSize: `${PX_PER_SEC}px 100%`}}/>}
      {clips.length === 0 && kind === "v" && (
        <div className="empty-hint">Drop clips here</div>
      )}
      {clips.map((c) => (
        <Clip
          key={c.id}
          clip={c}
          media={media.find((m) => m.id === c.mediaId)}
          selected={selectedSet.has(c.id)}
          active={c.id === activeSelectedId}
          showThumbs={showThumbs}
          onBeginDrag={onBeginDrag}
          onSelect={onSelect}
        />
      ))}
    </div>
  );
}

function Clip({ clip, media, selected, active, showThumbs, onBeginDrag, onSelect }) {
  const left = clip.start * PX_PER_SEC;
  const width = Math.max(28, clip.duration * PX_PER_SEC);
  const isAudio = clip.type === "audio";
  const aiFx = clip.effects.filter((e) => e.kind === "ai");

  const thumbCount = Math.max(1, Math.min(8, Math.floor(width / 54)));

  return (
    <div
      className={"clip " + (isAudio ? "audio" : clip.type) + (selected ? " selected" : "") + (active ? " active" : "")}
      style={{left, width}}
      onMouseDown={(e) => onBeginDrag(e, clip, "move")}
    >
      <div className="clip-header">
        {aiFx.length > 0 && <span className="ai-mark">AI</span>}
        <span style={{overflow:"hidden", textOverflow:"ellipsis"}}>{clip.name}</span>
      </div>
      <div className="clip-body">
        {isAudio ? (
          <div className="clip-audio-wave">
            {Array.from({length: Math.max(12, Math.floor(width/4))}).map((_, i) => {
              const h = 20 + Math.abs(Math.sin(i * 0.7 + clip.start)) * 60 + Math.abs(Math.sin(i * 0.21)) * 20;
              return <div key={i} className="bar" style={{height: `${Math.min(90, h)}%`}}/>;
            })}
          </div>
        ) : clip.type === "video" && media ? (
          <video className="clip-video-preview" src={media.url} muted playsInline preload="metadata" />
        ) : showThumbs && media ? (
          <div className="clip-thumb-strip">
            {Array.from({length: thumbCount}).map((_, i) => (
              <div key={i} className="clip-thumb-cell" style={{backgroundImage: `url("${media.url}")`}}/>
            ))}
          </div>
        ) : (
          <div style={{width:"100%", height:"100%", background: "linear-gradient(180deg, #1a4258, #0f2a3a)"}}/>
        )}
        <div className="clip-footer">
          <span>{clip.duration.toFixed(1)}s</span>
          {aiFx.length > 0 && <span style={{color:"var(--warm)"}}>✦ {aiFx[0].name}</span>}
        </div>
      </div>
      <div className="clip-handle l" onMouseDown={(e) => onBeginDrag(e, clip, "trim-l")}/>
      <div className="clip-handle r" onMouseDown={(e) => onBeginDrag(e, clip, "trim-r")}/>
    </div>
  );
}

function buildRuler(duration) {
  const marks = [];
  const majorEvery = duration > 30 ? 5 : duration > 15 ? 2 : 1;
  for (let i = 0; i <= duration; i += 1) {
    const isMajor = i % majorEvery === 0;
    marks.push({
      x: i * PX_PER_SEC,
      minor: !isMajor,
      label: isMajor ? `${Math.floor(i / 60).toString().padStart(2, "0")}:${(i % 60).toString().padStart(2, "0")}` : "",
    });
    // half-ticks
    if (i < duration) {
      marks.push({ x: (i + 0.5) * PX_PER_SEC, minor: true, label: "" });
    }
  }
  return marks;
}

window.Timeline = Timeline;
