import { StudioContextType } from '../StudioContext';
import createTrack from '../createTrack';
import {
  getDerivedTiming,
  getReducedStudioClipsByTrackId,
  getSelectionEndBeats,
  getSelectionStartBeats,
} from '../selectors';
import { InfillPayload } from '../types';
import prepareInfillRequest from './prepareInfillRequest';
import resolveStyles from './resolveStyles';

const getCommonInfillPayloadProps = (
  studioContext: StudioContextType
): Pick<
  InfillPayload,
  | 'timing'
  | 'modelTier'
  | 'modelOverride'
  | 'styles'
  | 'excludeStyles'
  | 'lyrics'
  | 'lyricsUpdated'
  | 'studioProjectId'
  | 'projectId'
  | 'tracks'
  | 'selection'
> => {
  const { stateRef } = studioContext;
  const state = stateRef.current;

  if (!studioContext.studioProjectId) {
    throw new Error('No studio project id');
  }

  if (!state.selection.focusedTrackId) {
    throw new Error('No focused track id');
  }

  const { styles, excludeStyles } = resolveStyles(studioContext);
  const lyrics = studioContext.lyricsEditController.getLyricsEditSpec();

  return {
    timing: getDerivedTiming(state),
    modelTier: studioContext.modelTier,
    modelOverride: studioContext.modelOverride,

    styles,
    excludeStyles,
    lyrics,
    lyricsUpdated:
      lyrics.originalPlaintextLyrics !== lyrics.editedPlaintextLyrics,
    studioProjectId: studioContext.studioProjectId,
    projectId: studioContext.projectId,
    tracks: [
      {
        ...createTrack(),
        clips:
          getReducedStudioClipsByTrackId(state)[state.selection.focusedTrackId],
      },
    ],

    selection: {
      type: 'exact-beat-range',
      startBeats: getSelectionStartBeats(state),
      endBeats: getSelectionEndBeats(state),
    },
  };
};

export const prepareFixedInfillSelectionRequest = async (
  studioContext: StudioContextType
) => {
  const { stateRef } = studioContext;
  const state = stateRef.current;

  const payload: InfillPayload = {
    ...getCommonInfillPayloadProps(studioContext),
    mode: 'fixed',
    contextWindow: {
      type: 'centered-seconds-window',
      centerBeats:
        getSelectionStartBeats(state) +
        (getSelectionEndBeats(state) - getSelectionStartBeats(state)) / 2,
      durationSeconds: 30,
    },
  };

  return await prepareInfillRequest(studioContext.clipsStore, payload);
};

export const prepareInfillSelectionRequest = async (
  studioContext: StudioContextType
) => {
  const { stateRef } = studioContext;
  const state = stateRef.current;

  const payload: InfillPayload = {
    ...getCommonInfillPayloadProps(studioContext),
    mode: 'classic',
    timing: getDerivedTiming(state),
    contextWindow: {
      type: 'exact-beat-range',
      startBeats:
        getSelectionStartBeats(state) - studioContext.contextBeforeBeats,
      endBeats: getSelectionEndBeats(state) + studioContext.contextAfterBeats,
    },
  };

  return await prepareInfillRequest(studioContext.clipsStore, payload);
};
