import React, { useCallback, useMemo, useState } from 'react';

import { StudioTiming, StudioTrack } from '@/components/studio/types';
import { createContext } from '@/hooks/useContextSelector';

export type DraggedObjectType = 'clip' | 'multi-clip' | 'studio-timeline';

export type DraggedObjectPayload<T extends DraggedObjectType> = T extends 'clip'
  ? {
      clipId: string;
    }
  : T extends 'multi-clip'
    ? {
        clipIds: string[];
      }
    : T extends 'studio-timeline'
      ? {
          startBeats: number;
          endBeats: number;
          tracks: StudioTrack[];
          timing: StudioTiming;
        }
      : never;

export type DraggedObject<T extends DraggedObjectType> = {
  type: T;
  payload: DraggedObjectPayload<T>;
  onDrop?: () => void;
};

export type DraggedStudioTimeline = DraggedObject<'studio-timeline'>;
export type DraggedClip = DraggedObject<'clip'>;
export type DraggedMultiClip = DraggedObject<'multi-clip'>;
export type AnyDraggedObject = DraggedObject<DraggedObjectType>;

const useDragAndDrop = () => {
  const [draggedObject, setDraggedObject] = useState<AnyDraggedObject | null>(
    null
  );

  const onDrop = useCallback(() => {
    draggedObject?.onDrop?.();
    setDraggedObject(null);
  }, [draggedObject]);

  const onDragStart = useCallback((draggedObject: AnyDraggedObject) => {
    setDraggedObject(draggedObject);
  }, []);

  const onDragEnd = useCallback(() => {
    setDraggedObject(null);
  }, []);

  return useMemo(
    () => ({
      draggedObject,
      onDrop,
      onDragStart,
      onDragEnd,
    }),
    [draggedObject, onDrop, onDragStart, onDragEnd]
  );
};

const DragAndDropContext = createContext<ReturnType<typeof useDragAndDrop>>({
  draggedObject: null,
  onDrop: () => {},
  onDragStart: () => {},
  onDragEnd: () => {},
});

export default DragAndDropContext;

export const DragAndDropProvider = ({
  children,
}: {
  children: React.ReactNode;
}) => {
  const value = useDragAndDrop();

  return (
    <DragAndDropContext.Provider value={value}>
      {children}
    </DragAndDropContext.Provider>
  );
};
