import { StandardLibrary as StandardLibrary } from '../../sandbox/initStandardLibrary';
import CommandProject from '../../sandbox/CommandProject';
import { CommandTrack } from '../../types';

interface SettingDefinition<T> {
  name: string;
  default: T;
}

type NumberSettingDefinition = SettingDefinition<number> & {
  min: number;
  max: number;
  exponential?: boolean;
}

type BooleanSettingDefinition = SettingDefinition<boolean> & {
  trueLabel: string;
  falseLabel: string;
}

type OptionSettingDefinition<T> = SettingDefinition<T> & {
  options: {[key: string]: T} | T[]
}

type WavtoolValue = {
  sampleRate: number;
  sin: (x: number) => number;
  saw: (x: number) => number;
  square: (x: number) => 1 | -1;
  makeAudioBuffer: ({ length, numberOfChannels }: { length: number, numberOfChannels: number}) => AudioBuffer,
  numberSetting: (settingDefinition?: Partial<NumberSettingDefinition>) => number;
  frequencySetting: (settingDefinition?: Partial<NumberSettingDefinition>) => number;
  booleanSetting: (settingDefinition?: Partial<BooleanSettingDefinition>) => boolean;
  optionSetting: <T>(settingDefinition?: Partial<OptionSettingDefinition<T>>) => T;
}

type CommandTrack = {
  title: string;
  height: number;
  selected: boolean;
  audioBuffer: AudioBuffer;
};

type MapSamplesFunction = (sample: number, index: number, selectedSamples: Float32Array) => number;
type MapBuffersFunction = (audioBuffer: AudioBuffer, selectionStart: number, selectionEnd: number) => AudioBuffer;
type MapChannelsFunction = (track: Float32Array, selectionStart: number, selectionEnd: number) => Float32Array;
type MapFrequencySpaceFunction = (frequencyMagnitudeBins: Float32Array, sampleIndex?: number, channelIndex?: number) => Float32Array;

type ComplexPolarArray = {
  magnitudes: Float32Array;
  phases: Float32Array;
}

type MapFourierFunction = (block: ComplexPolarArray, sampleIndex?: number, channelIndex?: number) => ComplexPolarArray;

type CommandProject = {
  sampleRate: number;
  tracks: CommandTrack[];
  selectionStart: number;
  selectionEnd: number;

  getSelectionLength: () => number;
  isSelected: (samplePosition: number) => boolean;

  mapSelectedSamples: (fn: MapSamplesFunction) => void;
  mapSelectedAudioBuffers: (fn: MapBuffersFunction) => void;
  mapSelectedChannels: (fn: MapChannelsFunction) => void;

  mapSelectedSamplesFrequencySpace: (fn: MapFrequencySpaceFunction, crossfadeSamples = 0) => void;
  mapSelectedSamplesFourier: (fn: MapFourierFunction, crossfadeSamples = 0, fourierSamples = 2048, fourierShift = 256) => void;

  generateTrack: (
    generator: (index: number) => (number[] | number),
    lengthInSamples: number = this.sampleRate,
    numberOfChannels: number = 1,
    title?: string,
    index?: number
  ) => CommandTrack;

  addTrack: (audioBuffer: AudioBuffer, title: string = `Track ${this.tracks.length + 1}`, index: number = this.tracks.length) => CommandTrack
}

declare global {
  var wavtool: WavtoolValue;
  var project: CommandProject;
}
