import { ProjectState, Selection, Edit } from '../types';
import { useState, useCallback } from 'react';
import { getSelectedTracks, getSelectionStart } from '../audio/utils/selectionTools';
import insertAudio from '../audio/audioFunctions/insertAudio';
import selectAudio from '../audio/audioFunctions/selectAudio';
import makeAudioBuffer from '../audio/utils/makeAudioBuffer';
import concatBuffers from '../audio/audioFunctions/concatBuffers';
import { expandedTrackHeight } from '../styles/dimensions';

export default (state: ProjectState, selection: Selection) => {
  const [copiedContent, setCopiedContent] = useState<{[key: string]: AudioBuffer} | null>(null);
  const copy = useCallback(
    () => {
      const selectedContent: {[key: string]: AudioBuffer} = {};
      const selectedTracks = getSelectedTracks(selection);
      selectedTracks.forEach((index) => {
        const relativeIndex = index - Math.min(...selectedTracks);
        selectedContent[relativeIndex] = selectAudio(concatBuffers(state.tracks[index].audioBuffers), selection[0]);
      });
      setCopiedContent(selectedContent);
    },
    [state, setCopiedContent, selection]
  );

  const paste: Edit = useCallback(
    async () => {
      if (!copiedContent) {
        return null;
      }
      const selectedTracks = getSelectedTracks(selection);
      const newTracks = [...state.tracks];
      const newSelectedTracks: number[] = [];
      const selectionStart = getSelectionStart(selection);
      // This is a lil complex cuz it's handling cases like a selection on tracks 1,3,5 that is pasted onto the bottom track in the project.
      Object.keys(copiedContent).forEach((relativeIndex) => {
        const audioToInsert = copiedContent[relativeIndex];
        const absoluteIndex = Math.min(Math.min(...selectedTracks) + Number(relativeIndex), newTracks.length);
        if (!newTracks[absoluteIndex]) {
          newTracks[absoluteIndex] = {
            title: `Track ${absoluteIndex + 1}`,
            height: expandedTrackHeight,
            audioBuffers: [makeAudioBuffer({ length: selectionStart + audioToInsert.length, sampleRate: state.sampleRate, numberOfChannels: audioToInsert.numberOfChannels })]
          }
        }
        newTracks[absoluteIndex] = {
          ...newTracks[absoluteIndex],
          audioBuffers: [insertAudio(concatBuffers(newTracks[absoluteIndex].audioBuffers), audioToInsert, selectionStart)]
        };
        newSelectedTracks.push(absoluteIndex);
      });
      const newSelectionEnd = selectionStart + Math.max(...Object.values(copiedContent).map((audioBuffer) => audioBuffer.length));
      return [
        { ...state, tracks: newTracks },
        [[selectionStart, newSelectionEnd], newSelectedTracks],
      ];
    },
    [
      state,
      copiedContent,
      selection
    ]
  );

  return [copy, paste] as [typeof copy, typeof paste];
}
