// Clip + track + asset action creators — the "media library + timeline" domain.

import type { Clip, TextOverlay, Track } from '@/types';
import type { EditorActions, Getter, Setter } from './types';
import { uid } from './types';

export function createMediaActions(
  set: Setter,
  get: Getter,
): Pick<
  EditorActions,
  | 'addAsset'
  | 'removeAsset'
  | 'addTrack'
  | 'removeTrack'
  | 'updateTrack'
  | 'addClip'
  | 'updateClip'
  | 'removeClip'
  | 'removeClips'
  | 'duplicateClips'
  | 'setClipIds'
  | 'toggleClipSelection'
  | 'splitClipAtCurrent'
  | 'addTextOverlay'
  | 'updateTextOverlay'
  | 'removeTextOverlay'
> {
  return {
    addAsset: (asset) => {
      // No history push — assets are file-backed, undoable independently.
      set((s) => ({ assets: [...s.assets, asset] }));
    },

    removeAsset: (id) => {
      set((s) => ({
        assets: s.assets.filter((a) => a.id !== id),
        clips: s.clips.filter((c) => c.assetId !== id),
      }));
    },

    addTrack: (kind) => {
      get().pushHistory('เพิ่มแทร็ก');
      set((s) => {
        const idx = s.tracks.filter((t) => t.kind === kind).length + 1;
        const namePrefix = kind === 'video' ? 'วิดีโอ' : 'เสียง';
        // Cycle PIP positions so the 2nd/3rd/4th video track don't all stack.
        const videoTracks = s.tracks.filter((t) => t.kind === 'video');
        const pipCycle: ('pip-br' | 'pip-tl' | 'pip-tr' | 'pip-bl' | 'pip-c')[] = [
          'pip-br',
          'pip-tl',
          'pip-tr',
          'pip-bl',
          'pip-c',
        ];
        const isFirstVideo = kind === 'video' && videoTracks.length === 0;
        const track: Track = {
          id: uid(),
          kind,
          name: `${namePrefix} ${idx}`,
          volume: 1,
          muted: false,
          background: kind === 'video' ? { color: '#000000', blur: false } : undefined,
          noiseReduction: kind === 'audio' ? { enabled: false, amount: 0.5 } : undefined,
          videoPosition: kind === 'video'
            ? (isFirstVideo ? 'full' : pipCycle[(videoTracks.length - 1) % pipCycle.length])
            : undefined,
          videoScale: kind === 'video' ? (isFirstVideo ? 1 : 0.3) : undefined,
          videoOpacity: kind === 'video' ? 1 : undefined,
        };
        return { tracks: [...s.tracks, track] };
      });
    },

    removeTrack: (id) => {
      get().pushHistory('ลบแทร็ก');
      set((s) => ({
        tracks: s.tracks.filter((t) => t.id !== id),
        clips: s.clips.filter((c) => c.trackId !== id),
        silenceSegments: s.silenceSegments.filter((seg) => seg.trackId !== id),
      }));
    },

    updateTrack: (id, patch) => {
      set((s) => ({
        tracks: s.tracks.map((t) => (t.id === id ? { ...t, ...patch } : t)),
      }));
    },

    addClip: (clip) => {
      const id = uid();
      get().pushHistory('เพิ่มคลิป');
      set((s) => ({ clips: [...s.clips, { ...clip, id }] }));
      return id;
    },

    updateClip: (id, patch) => {
      set((s) => ({
        clips: s.clips.map((c) => (c.id === id ? { ...c, ...patch } : c)),
      }));
    },

    addTextOverlay: (overlay: Omit<TextOverlay, 'id'>) => {
      const id = uid();
      get().pushHistory('เพิ่มข้อความลอย');
      set((s) => ({ textOverlays: [...s.textOverlays, { ...overlay, id }] }));
      return id;
    },

    updateTextOverlay: (id, patch) => {
      set((s) => ({
        textOverlays: s.textOverlays.map((t) => (t.id === id ? { ...t, ...patch } : t)),
      }));
    },

    removeTextOverlay: (id) => {
      get().pushHistory('ลบข้อความลอย');
      set((s) => ({ textOverlays: s.textOverlays.filter((t) => t.id !== id) }));
    },

    removeClip: (id) => {
      get().pushHistory('ลบคลิป');
      set((s) => ({
        clips: s.clips.filter((c) => c.id !== id),
        selection: s.selection.clipId === id ? {} : s.selection,
      }));
    },

    /** V23 — Multi-select bulk delete */
    removeClips: (ids) => {
      if (!ids || ids.length === 0) return;
      get().pushHistory(`ลบ ${ids.length} คลิป`);
      const idSet = new Set(ids);
      set((s) => ({
        clips: s.clips.filter((c) => !idSet.has(c.id)),
        selection: {
          ...s.selection,
          clipIds: (s.selection.clipIds ?? []).filter((id) => !idSet.has(id)),
          clipId: s.selection.clipId && idSet.has(s.selection.clipId) ? undefined : s.selection.clipId,
        },
      }));
    },

    /** V23 — Multi-select duplicate (Cmd+D) */
    duplicateClips: (ids) => {
      if (!ids || ids.length === 0) return;
      get().pushHistory(`คัดลอก ${ids.length} คลิป`);
      const idSet = new Set(ids);
      const sources = get().clips.filter((c) => idSet.has(c.id));
      // Offset by 1s so duplicates don't overlap originals.
      const newClips = sources.map((c) => ({
        ...c,
        id: `${c.id}-dup-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 5)}`,
        start: c.start + Math.max(0.5, c.duration * 0.1),
      }));
      set((s) => ({
        clips: [...s.clips, ...newClips],
        selection: {
          ...s.selection,
          clipIds: newClips.map((c) => c.id),
        },
      }));
      get().setToast({
        message: `คัดลอก ${newClips.length} คลิป`,
        level: 'success',
      });
    },

    /** V23 — Set multi-selection (replaces `clipIds` array) */
    setClipIds: (ids) => {
      set((s) => ({
        selection: { ...s.selection, clipIds: ids, clipId: ids[ids.length - 1] },
      }));
    },

    /** V23 — Toggle a clip in/out of multi-selection */
    toggleClipSelection: (id, additive) => {
      set((s) => {
        const current = new Set(s.selection.clipIds ?? (s.selection.clipId ? [s.selection.clipId] : []));
        if (additive) {
          if (current.has(id)) current.delete(id);
          else current.add(id);
        } else {
          current.clear();
          current.add(id);
        }
        const arr = Array.from(current);
        return {
          selection: { ...s.selection, clipIds: arr, clipId: arr[arr.length - 1] },
        };
      });
    },

    splitClipAtCurrent: () => {
      const t = get().currentTime;
      const clips = get().clips;
      const targets = clips.filter(
        (c) => t > c.start + 0.05 && t < c.start + c.duration - 0.05,
      );
      if (targets.length === 0) {
        get().setToast({
          message: 'เลื่อน playhead ไปอยู่ในคลิปก่อนแล้วลองอีกครั้ง',
          level: 'info',
        });
        return;
      }
      get().pushHistory('แยกคลิป');
      const next: Clip[] = [];
      for (const c of clips) {
        if (!targets.find((tg) => tg.id === c.id)) {
          next.push(c);
          continue;
        }
        const offset = t - c.start;
        next.push({ ...c, duration: offset });
        next.push({
          ...c,
          id: uid(),
          start: t,
          duration: c.duration - offset,
          sourceIn: c.sourceIn + offset,
        });
      }
      set({ clips: next });
    },
  };
}