import { ClipCreationIntent, StudioProjectState } from '../types';

/**
 * Creates a state updater function that updates all id'd clip creation intents within all tracks.
 * This is a common pattern used throughout the codebase to update clip creation intents' properties.
 *
 * @param clipCreationIntentIds The IDs of the clip creation intents to update
 * @param updateFn A function that receives a current clip creation intent and returns an updated clip creation intent
 * @returns A function that can be used with setState to update the specified clip creation intents
 */

export const isValidClipCreationIntent = (
  clipCreationIntent: ClipCreationIntent
) => {
  return (
    (clipCreationIntent.startBeats ?? -Infinity) <
    (clipCreationIntent.endBeats ?? Infinity)
  );
};

export default function updateClipCreationIntents(
  clipCreationIntentIds: string[],
  updateFn: (
    clipCreationIntent: ClipCreationIntent
  ) => ClipCreationIntent | null
) {
  return (state: StudioProjectState) => ({
    ...state,
    tracks: state.tracks.map((t) => {
      const hasMatchingIntent =
        t.clipCreationIntents.some((c) =>
          clipCreationIntentIds.includes(c.id)
        ) ||
        t.takeLanes.some((tl) =>
          tl.clipCreationIntents.some((c) =>
            clipCreationIntentIds.includes(c.id)
          )
        );
      if (!hasMatchingIntent) {
        return t;
      }
      return {
        ...t,
        takeLanes: t.takeLanes.map((tl) => ({
          ...tl,
          clipCreationIntents: tl.clipCreationIntents
            .map((c) => {
              const result = clipCreationIntentIds.includes(c.id)
                ? updateFn(c)
                : c;
              if (
                !result ||
                (result.possibleClipIds.length === 0 &&
                  result.queuedGenerationIds.length === 0)
              ) {
                return null;
              }
              return result;
            })
            .filter(Boolean) as ClipCreationIntent[],
        })),
        clipCreationIntents: (
          t.clipCreationIntents
            .map((c) => {
              const result = clipCreationIntentIds.includes(c.id)
                ? updateFn(c)
                : c;
              if (
                !result ||
                (result.possibleClipIds.length === 0 &&
                  result.queuedGenerationIds.length === 0)
              ) {
                return null;
              }
              return result;
            })
            .filter(Boolean) as ClipCreationIntent[]
        ).filter(isValidClipCreationIntent),
      };
    }),
  });
}
