import { useState, type DragEvent } from 'react';
import type {
  AvProjectV1,
  MediaAssetReference,
  TimelineClip,
} from '../project';
import type { WaveformPeakData } from '../waveform';
import { formatDuration } from '../app/application-state';
import { Icon } from './Icon';
import { WaveformEditor, type WaveformSelection } from './WaveformEditor';

export interface TimelineProps {
  project: AvProjectV1;
  selectedClipId?: string;
  onSelect: (clipId: string) => void;
  onMove: (clipId: string, index: number) => void;
  onUpdate: (clipId: string, changes: Partial<TimelineClip>) => void;
  onRemove: (clipId: string) => void;
  waveformPeaks?: WaveformPeakData;
  currentTimeSeconds?: number;
  splitMarkers?: readonly number[];
  onSelectionChange?: (selection: WaveformSelection) => void;
  onSeek?: (timeSeconds: number) => void;
  waveformDisabled?: boolean;
}

export function Timeline({
  project,
  selectedClipId,
  onSelect,
  onMove,
  onUpdate,
  onRemove,
  waveformPeaks,
  currentTimeSeconds,
  splitMarkers = [],
  onSelectionChange,
  onSeek,
  waveformDisabled = false,
}: TimelineProps) {
  const [draggedId, setDraggedId] = useState<string>();
  const assetMap = new Map(project.assets.map((asset) => [asset.id, asset]));
  const selectedClip = project.timeline.find(
    (clip) => clip.id === selectedClipId
  );

  const dropAt = (event: DragEvent, index: number) => {
    event.preventDefault();
    if (draggedId) onMove(draggedId, index);
    setDraggedId(undefined);
  };

  return (
    <section className="timeline-panel" aria-labelledby="timeline-title">
      <header>
        <div>
          <p className="eyebrow">Sequential, non-destructive</p>
          <h2 id="timeline-title">Timeline</h2>
        </div>
        <span>
          {project.timeline.length} clip
          {project.timeline.length === 1 ? '' : 's'}
        </span>
      </header>
      {project.timeline.length === 0 ? (
        <div className="timeline-empty">
          Imported sources with a known duration are added here.
        </div>
      ) : (
        <div className="timeline-track">
          {project.timeline.map((clip, index) => (
            <TimelineClipCard
              key={clip.id}
              clip={clip}
              asset={assetMap.get(clip.assetId)}
              selected={clip.id === selectedClipId}
              first={index === 0}
              last={index === project.timeline.length - 1}
              onSelect={() => onSelect(clip.id)}
              onDragStart={() => setDraggedId(clip.id)}
              onDragEnd={() => setDraggedId(undefined)}
              onDragOver={(event) => event.preventDefault()}
              onDrop={(event) => dropAt(event, index)}
              onMove={(offset) => onMove(clip.id, index + offset)}
              onUpdate={(changes) => onUpdate(clip.id, changes)}
              onRemove={() => onRemove(clip.id)}
            />
          ))}
        </div>
      )}
      {waveformPeaks && selectedClip ? (
        <div className="timeline-waveform subpanel">
          <WaveformEditor
            peaks={waveformPeaks}
            inSeconds={selectedClip.sourceInSeconds}
            outSeconds={selectedClip.sourceOutSeconds}
            markers={splitMarkers}
            currentTimeSeconds={currentTimeSeconds}
            onSeek={onSeek}
            disabled={waveformDisabled}
            ariaLabel={`Waveform editor for ${
              assetMap.get(selectedClip.assetId)?.originalName ??
              'selected clip'
            }`}
            onChange={(selection) => {
              onUpdate(selectedClip.id, {
                sourceInSeconds: selection.inSeconds,
                sourceOutSeconds: selection.outSeconds,
              });
              onSelectionChange?.(selection);
            }}
          />
        </div>
      ) : null}
    </section>
  );
}

interface TimelineClipCardProps {
  clip: TimelineClip;
  asset?: MediaAssetReference;
  selected: boolean;
  first: boolean;
  last: boolean;
  onSelect: () => void;
  onDragStart: () => void;
  onDragEnd: () => void;
  onDragOver: (event: DragEvent) => void;
  onDrop: (event: DragEvent) => void;
  onMove: (offset: number) => void;
  onUpdate: (changes: Partial<TimelineClip>) => void;
  onRemove: () => void;
}

function TimelineClipCard({
  clip,
  asset,
  selected,
  first,
  last,
  onSelect,
  onDragStart,
  onDragEnd,
  onDragOver,
  onDrop,
  onMove,
  onUpdate,
  onRemove,
}: TimelineClipCardProps) {
  const sourceDurationSeconds = asset?.probe?.durationSeconds;
  const canResetTrim =
    sourceDurationSeconds !== undefined &&
    Number.isFinite(sourceDurationSeconds) &&
    sourceDurationSeconds >= 0.001;
  const trimIsFullSource =
    canResetTrim &&
    clip.sourceInSeconds === 0 &&
    clip.sourceOutSeconds === sourceDurationSeconds;

  return (
    <article
      className={`timeline-clip${selected ? ' is-selected' : ''}`}
      draggable
      onDragStart={onDragStart}
      onDragEnd={onDragEnd}
      onDragOver={onDragOver}
      onDrop={onDrop}
    >
      <button className="timeline-clip__main" type="button" onClick={onSelect}>
        <span className="timeline-clip__thumb">
          <Icon name="video" />
        </span>
        <span>
          <strong>{asset?.originalName ?? 'Missing source'}</strong>
          <small>
            {formatDuration(clip.sourceOutSeconds - clip.sourceInSeconds)}
          </small>
        </span>
      </button>
      {selected ? (
        <div className="timeline-clip__controls">
          <label>
            In
            <input
              type="number"
              min="0"
              step="0.01"
              value={clip.sourceInSeconds}
              onChange={(event) =>
                onUpdate({
                  sourceInSeconds: Math.max(
                    0,
                    Number(event.currentTarget.value)
                  ),
                })
              }
            />
          </label>
          <label>
            Out
            <input
              type="number"
              min={clip.sourceInSeconds + 0.001}
              step="0.01"
              value={clip.sourceOutSeconds}
              onChange={(event) =>
                onUpdate({
                  sourceOutSeconds: Number(event.currentTarget.value),
                })
              }
            />
          </label>
          <div className="timeline-clip__actions">
            <button
              className="timeline-clip__reset"
              type="button"
              disabled={!canResetTrim || trimIsFullSource}
              aria-label="Reset trim to full source"
              onClick={() => {
                if (!canResetTrim) return;
                onUpdate({
                  sourceInSeconds: 0,
                  sourceOutSeconds: sourceDurationSeconds,
                });
              }}
            >
              Reset trim
            </button>
            <button
              type="button"
              disabled={first}
              aria-label="Move clip earlier"
              onClick={() => onMove(-1)}
            >
              ←
            </button>
            <button
              type="button"
              disabled={last}
              aria-label="Move clip later"
              onClick={() => onMove(1)}
            >
              →
            </button>
            <button type="button" aria-label="Remove clip" onClick={onRemove}>
              <Icon name="trash" />
            </button>
          </div>
        </div>
      ) : null}
    </article>
  );
}
