import { ProjectState, Selection } from '../types';
import { useState, useCallback, useMemo } from 'react';
import makeAudioBuffer from '../audio/utils/makeAudioBuffer';
import { RECORDING_BUFFER_SIZE } from './useAudioRecorder';
import cloneBuffer from '../audio/audioFunctions/cloneBuffer';

export default (state: ProjectState, selection: Selection, alterProjectState: (state: ProjectState, selection: Selection) => void) => {
  const [recordingChannelIndex, setRecordingChannelIndex] = useState<number | null>(null);
  const [recordingOffset, setRecordingOffset] = useState<number>(0);
  const firstBufferLength = useMemo(() => Math.max(recordingOffset, RECORDING_BUFFER_SIZE), [recordingOffset]);

  const continueRecording = useCallback(
    (inputAudioBuffer: AudioBuffer, firstWrittenSample: number) => {
      if (recordingChannelIndex === null) {
        throw new Error('recordingChannelIndex was null.');
      } else {
        const lastAudioBuffers = state.tracks[recordingChannelIndex].audioBuffers;
        const nextAudioBuffers = [...lastAudioBuffers]
        if (recordingOffset + firstWrittenSample < firstBufferLength) {
          nextAudioBuffers[nextAudioBuffers.length - 1] = makeAudioBuffer({
            length: recordingOffset + inputAudioBuffer.length,
            numberOfChannels: inputAudioBuffer.numberOfChannels,
            sampleRate: state.sampleRate
          });
          for (let i = 0; i < inputAudioBuffer.numberOfChannels; i ++) {
            nextAudioBuffers[nextAudioBuffers.length - 1].copyToChannel(lastAudioBuffers[lastAudioBuffers.length - 1].getChannelData(i), i, 0);
            nextAudioBuffers[nextAudioBuffers.length - 1].copyToChannel(inputAudioBuffer.getChannelData(i), i, recordingOffset);
          }
        } else {
          nextAudioBuffers.push(cloneBuffer(inputAudioBuffer))
        }
        alterProjectState(
          {
            ...state,
            tracks: state.tracks.map((track, index) =>
              index === recordingChannelIndex
                ? (
                  {
                    ...track,
                    audioBuffers: nextAudioBuffers
                  }
                )
                : track
            )
          },
          selection
        );
      }
    },
    [state, selection, recordingChannelIndex, alterProjectState, recordingOffset, firstBufferLength]
  );

  const insertNewRecordingTrack = useCallback(
    (offset: number) => {
      setRecordingChannelIndex(state.tracks.length);
      setRecordingOffset(offset);
      return makeAudioBuffer({ length: Math.max(offset, RECORDING_BUFFER_SIZE), sampleRate: state.sampleRate, numberOfChannels: 1 });
    },
    [setRecordingChannelIndex, state]
  );

  return [insertNewRecordingTrack, continueRecording] as [typeof insertNewRecordingTrack, typeof continueRecording];
}
