// Single clip block on the timeline — drag to move, drag edges to trim,
// click to select. Renders an embedded Waveform for audio clips.

'use client';

import { useEffect, useRef, useState } from 'react';
import { useEditor } from '@/store/editor';
import type { Clip, MediaAsset, Track } from '@/types';
import { Waveform } from '@/components/Waveform';
import { TRACK_HEIGHT } from './constants';

interface Props {
  clip: Clip;
  track: Track;
  zoom: number;
  selected: boolean;
  assets: MediaAsset[];
  onSelect: () => void;
  onChange: (patch: Partial<Clip>) => void;
  onCommit: () => void;
}

type DragMode = 'move' | 'left' | 'right';

interface DragRef {
  startX: number;
  startStart: number;
  startDur: number;
  startSourceIn: number;
}

export function ClipBlock({ clip, track, zoom, selected, assets, onSelect, onChange, onCommit }: Props) {
  const asset = assets.find((a) => a.id === clip.assetId);
  const [dragging, setDragging] = useState<DragMode | null>(null);
  const dragRef = useRef<DragRef | null>(null);

  const left = clip.start * zoom;
  const width = Math.max(8, clip.duration * zoom);

  function onMouseDown(e: React.MouseEvent, mode: DragMode) {
    e.stopPropagation();
    e.preventDefault();
    onSelect();
    dragRef.current = {
      startX: e.clientX,
      startStart: clip.start,
      startDur: clip.duration,
      startSourceIn: clip.sourceIn,
    };
    setDragging(mode);
  }

  useEffect(() => {
    if (!dragging) return;
    const onMove = (e: MouseEvent) => {
      const dx = e.clientX - (dragRef.current?.startX ?? e.clientX);
      const dt = dx / zoom;
      const ref = dragRef.current!;
      if (dragging === 'move') {
        const newStart = Math.max(0, Math.round((ref.startStart + dt) * 100) / 100);
        onChange({ start: newStart });
      } else if (dragging === 'right') {
        const newDur = Math.max(0.1, ref.startDur + dt);
        const maxDur = (asset?.duration ?? newDur) - ref.startSourceIn;
        const clamped = Math.min(newDur, maxDur);
        onChange({ duration: Math.round(clamped * 100) / 100 });
      } else if (dragging === 'left') {
        const maxDelta = ref.startDur - 0.1;
        const delta = Math.min(maxDelta, Math.max(-ref.startSourceIn, dt));
        const newSourceIn = ref.startSourceIn + delta;
        const newStart = ref.startStart + delta;
        const newDur = ref.startDur - delta;
        if (newDur < 0.1) return;
        onChange({
          sourceIn: Math.max(0, newSourceIn),
          start: Math.max(0, newStart),
          duration: newDur,
        });
      }
    };
    const onUp = () => {
      setDragging(null);
      dragRef.current = null;
      onCommit();
    };
    window.addEventListener('mousemove', onMove);
    window.addEventListener('mouseup', onUp);
    return () => {
      window.removeEventListener('mousemove', onMove);
      window.removeEventListener('mouseup', onUp);
    };
  }, [dragging, zoom, asset, onChange, onCommit]);

  const colorClass =
    track.kind === 'video'
      ? 'bg-capcut-blue/30 border-capcut-blue'
      : 'bg-capcut-orange/30 border-capcut-orange';

  return (
    <div
      className={`absolute top-1 bottom-1 rounded border ${colorClass} ${
        selected ? 'ring-2 ring-capcut-blue' : ''
      } overflow-hidden select-none`}
      style={{ left, width }}
      onMouseDown={(e) => onMouseDown(e, 'move')}
      onClick={(e) => {
        e.stopPropagation();
        onSelect();
      }}
    >
      <div
        className="absolute left-0 top-0 bottom-0 w-2 cursor-col-resize hover:bg-white/20"
        onMouseDown={(e) => onMouseDown(e, 'left')}
      />
      <div
        className="absolute right-0 top-0 bottom-0 w-2 cursor-col-resize hover:bg-white/20"
        onMouseDown={(e) => onMouseDown(e, 'right')}
      />

      <div
        className={`absolute top-0 left-2 right-2 text-[10px] truncate font-medium pointer-events-none ${
          track.kind === 'video' ? 'text-white' : 'text-capcut-text'
        }`}
      >
        {asset?.name ?? 'สื่อที่หายไป'}
      </div>

      {track.kind === 'audio' && asset?.audioBuffer ? (
        <div className="absolute top-3 left-0 right-0 bottom-0 pointer-events-none">
          <Waveform
            buffer={asset.audioBuffer}
            sourceIn={clip.sourceIn}
            duration={clip.duration}
            height={TRACK_HEIGHT - 16}
            color="#ff8a3d"
          />
        </div>
      ) : null}

      {/* Volume keyframes curve overlay (Phase B) */}
      {clip.volumeKeyframes && clip.volumeKeyframes.length >= 2 && (
        <svg
          className="absolute top-3 left-0 right-0 bottom-0 pointer-events-none"
          viewBox={`0 0 100 ${TRACK_HEIGHT - 16}`}
          preserveAspectRatio="none"
          style={{ width: '100%', height: TRACK_HEIGHT - 16 }}
        >
          {/* Background guide line at volume=1 */}
          <line x1={0} y1={(TRACK_HEIGHT - 16) / 2} x2={100} y2={(TRACK_HEIGHT - 16) / 2} stroke="rgba(255,255,255,0.1)" strokeWidth="0.5" vectorEffect="non-scaling-stroke" />
          {/* Keyframe curve */}
          <polyline
            fill="none"
            stroke="#fff"
            strokeWidth="1.5"
            vectorEffect="non-scaling-stroke"
            points={clip.volumeKeyframes
              .map((kf) => {
                const xPct = (kf.time / clip.duration) * 100;
                // y: 0 = top of waveform area, 100 = bottom. Volume 0..2 mapped to y 0..100 inverted.
                const yPct = 50 - (kf.value / 2) * 50;
                return `${xPct.toFixed(2)},${yPct.toFixed(2)}`;
              })
              .join(' ')}
          />
          {/* Keyframe dots */}
          {clip.volumeKeyframes.map((kf, i) => {
            const xPct = (kf.time / clip.duration) * 100;
            const yPct = 50 - (kf.value / 2) * 50;
            return (
              <circle
                key={i}
                cx={xPct}
                cy={yPct}
                r="1.5"
                fill="#fff"
                stroke="#3aa6ff"
                strokeWidth="0.5"
                vectorEffect="non-scaling-stroke"
              />
            );
          })}
        </svg>
      )}
    </div>
  );
}

// Re-export for useEditor.getState typing in callers
export type { Clip, MediaAsset, Track };