// Core type definitions for the CapCut-style web editor.

export type MediaKind = 'video' | 'audio' | 'image';

/** Per-clip color grading. All values are 0..1 (mapped to FFmpeg eq ranges).
 *  - brightness: -1..1   (eq: -1..1)
 *  - contrast: -1..1     (eq: 0..3, we map -1..1 → 0.5..1.5)
 *  - saturation: -1..1   (eq: 0..3, we map -1..1 → 0..2)
 *  - hue: -180..180      (eq hue degrees)
 *  - sepia: 0..1         (mix via colorchannelmixer)
 */
export interface ColorGrading {
  brightness: number;
  contrast: number;
  saturation: number;
  hue: number;
  sepia: number;
  preset?: ColorPreset;
}

export type ColorPreset =
  | 'original'
  | 'warm'
  | 'cool'
  | 'bw'
  | 'vintage'
  | 'vivid'
  | 'cinematic'
  | 'noir';

export const DEFAULT_COLOR: ColorGrading = {
  brightness: 0,
  contrast: 0,
  saturation: 0,
  hue: 0,
  sepia: 0,
  preset: 'original',
};

/** Common color filter presets (FFmpeg eq values, raw). */
export const COLOR_PRESETS: Record<ColorPreset, ColorGrading> = {
  original: { brightness: 0, contrast: 0, saturation: 0, hue: 0, sepia: 0, preset: 'original' },
  warm:     { brightness: 0.05, contrast: 0.05, saturation: 0.15, hue: 15, sepia: 0, preset: 'warm' },
  cool:     { brightness: -0.05, contrast: 0, saturation: 0.1, hue: -20, sepia: 0, preset: 'cool' },
  bw:       { brightness: 0, contrast: 0.15, saturation: -1, hue: 0, sepia: 0, preset: 'bw' },
  vintage:  { brightness: 0.05, contrast: -0.05, saturation: -0.3, hue: 5, sepia: 0.5, preset: 'vintage' },
  vivid:    { brightness: 0, contrast: 0.15, saturation: 0.5, hue: 0, sepia: 0, preset: 'vivid' },
  cinematic:{ brightness: -0.05, contrast: 0.1, saturation: -0.2, hue: -10, sepia: 0, preset: 'cinematic' },
  noir:     { brightness: -0.1, contrast: 0.4, saturation: -1, hue: 0, sepia: 0, preset: 'noir' },
};

export interface MediaAsset {
  id: string;
  name: string;
  kind: MediaKind;
  /** Object URL pointing to the original file (browser-only) */
  url: string;
  /** File size in bytes */
  size: number;
  /** Native duration in seconds (decoded at upload) */
  duration: number;
  /** Native width / height for video */
  width?: number;
  height?: number;
  /** Cached audio buffer for waveform + dead-air detection */
  audioBuffer?: AudioBuffer;
}

/** A text overlay clipped on a `text` track — no file needed. */
export interface TextOverlay {
  id: string;
  trackId: string;
  start: number;
  duration: number;
  text: string;
  fontFamily: string;
  fontSize: number;
  bold: boolean;
  italic: boolean;
  color: string;
  backgroundColor: string;
  /** 0..1 alpha (1 = opaque) */
  opacity: number;
  /** Position on canvas (relative to width/height). */
  xRatio: number;
  yRatio: number;
  /** Animation in/out */
  animation: 'none' | 'fade' | 'pop';
}

export type TrackKind = 'video' | 'audio' | 'text';

/** Where a non-base video track sits on the canvas. `full` covers the
 *  underlying video; `*-pip-*` keeps the underlying video visible. */
export type VideoPosition =
  | 'full'
  | 'pip-tl' // top-left
  | 'pip-tr' // top-right
  | 'pip-bl' // bottom-left
  | 'pip-br' // bottom-right
  | 'pip-c'; // center

export interface Track {
  id: string;
  kind: TrackKind;
  name: string;
  /** Volume 0..1 — applies to all audio passing through this track */
  volume: number;
  muted: boolean;
  /** Background / letterbox settings (video only) */
  background?: {
    color: string;
    blur: boolean;
  };
  /** Layout on the canvas (video only). Defaults to `full` for the
   *  bottom-most video track, `pip-br` for the rest. */
  videoPosition?: VideoPosition;
  /** Scale of the overlay (0..1). Only used when videoPosition is a PIP. */
  videoScale?: number;
  /** Opacity 0..1 of the overlay. Only used when videoPosition is a PIP. */
  videoOpacity?: number;
  /** Noise reduction settings (audio only) — uses FFmpeg's `afftdn` filter */
  noiseReduction?: {
    /** Toggle the denoise filter on this track */
    enabled: boolean;
    /** Strength 0..1 — mapped to `afftdn`'s noise floor in dB (-80..-20) */
    amount: number;
  };
}

export type TransitionType = 'cut' | 'crossfade' | 'fadeIn' | 'fadeOut' | 'dipToBlack';

export interface Clip {
  id: string;
  assetId: string;
  trackId: string;
  /** Timeline position (seconds) — start on the timeline */
  start: number;
  /** Duration in the timeline (may be shorter than asset if trimmed) */
  duration: number;
  /** Trim offset into the source asset (seconds) */
  sourceIn: number;
  /** Playback speed 0.25..4.0. Default 1. */
  speed?: number;
  /** Color grading for this clip (video only). */
  colorGrading?: ColorGrading;
  /** Transition into this clip from the previous one on the same track */
  transitionIn?: {
    type: TransitionType;
    durationMs: number;
  };
  /**
   * Per-clip volume keyframes (timeline-relative seconds → volume 0..1).
   * If absent, the track's volume is applied uniformly. Keyframes are
   * interpolated linearly between adjacent points.
   */
  volumeKeyframes?: VolumeKeyframe[];
}

export interface VolumeKeyframe {
  /** Time in seconds relative to the clip's start on the timeline. */
  time: number;
  /** Volume at this point (0..2; 1 = 100%, 2 = +6dB boost). */
  value: number;
}

export interface SilenceSegment {
  id: string;
  /** Track id this silence is on */
  trackId: string;
  start: number;
  end: number;
}

export interface SubtitleCue {
  id: number;
  start: number;
  end: number;
  text: string;
  /** Optional style override. If absent, SubtitleStyle.default applies. */
  style?: Partial<SubtitleStyle>;
}

export type SubtitlePosition = 'top' | 'middle' | 'bottom';

export interface SubtitleStyle {
  /** Font family (CSS font stack). */
  fontFamily: string;
  /** Font size in pixels (rendered + burned-in). */
  fontSize: number;
  /** Text color — hex (#RRGGBB) or rgba. */
  color: string;
  /** Outline color for legibility. */
  outlineColor: string;
  /** Outline width in px. */
  outlineWidth: number;
  /** Background color behind each character ('none' = transparent). */
  background: string;
  /** Position on screen. */
  position: SubtitlePosition;
  /** Bold weight. */
  bold: boolean;
}

export const DEFAULT_SUBTITLE_STYLE: SubtitleStyle = {
  fontFamily: 'Sarabun, Inter, sans-serif',
  fontSize: 32,
  color: '#ffffff',
  outlineColor: '#000000',
  outlineWidth: 2,
  background: '#00000066',
  position: 'bottom',
  bold: true,
};

export interface ExportSettings {
  /** Remove silence segments before exporting */
  removeSilence: boolean;
  silenceThresholdDb: number;
  silenceMinDurationMs: number;
  /** Output resolution */
  width: number;
  height: number;
  fps: number;
  /** Bitrates */
  videoBitrate: string;
  audioBitrate: string;
}

export interface HistoryState {
  /** Serialised timeline snapshot */
  snapshot: TimelineSnapshot;
  label: string;
}

export interface TimelineSnapshot {
  tracks: Track[];
  clips: Clip[];
  assets: MediaAsset[];
  silenceSegments: SilenceSegment[];
  subtitles: SubtitleCue[];
  selection: { clipId?: string; trackId?: string };
}