import type { SynthEngine, PitchLock } from './base/SynthEngine';

interface SampleParams {
  loaded: boolean;
}

export class Sample implements SynthEngine<SampleParams> {
  private leftChannel: Float32Array | null = null;
  private rightChannel: Float32Array | null = null;
  private sampleRate: number = 44100;

  getName(): string {
    return 'Sample';
  }

  getDescription(): string {
    return 'Load audio files from disk and process them';
  }

  getType() {
    return 'sample' as const;
  }

  getCategory() {
    return 'Utility' as const;
  }

  async loadFile(file: File): Promise<void> {
    const arrayBuffer = await file.arrayBuffer();
    const audioContext = new AudioContext();
    const audioBuffer = await audioContext.decodeAudioData(arrayBuffer);

    this.sampleRate = audioBuffer.sampleRate;

    if (audioBuffer.numberOfChannels === 1) {
      this.leftChannel = audioBuffer.getChannelData(0);
      this.rightChannel = audioBuffer.getChannelData(0);
    } else {
      this.leftChannel = audioBuffer.getChannelData(0);
      this.rightChannel = audioBuffer.getChannelData(1);
    }

    await audioContext.close();
  }

  generate(_params: SampleParams, sampleRate: number, _duration: number): [Float32Array, Float32Array] {
    if (!this.leftChannel || !this.rightChannel) {
      throw new Error('No audio file loaded. Please load a file first.');
    }

    if (this.sampleRate === sampleRate) {
      return [this.leftChannel.slice(), this.rightChannel.slice()];
    }

    const resampleRatio = sampleRate / this.sampleRate;
    const newLength = Math.floor(this.leftChannel.length * resampleRatio);
    const leftResampled = new Float32Array(newLength);
    const rightResampled = new Float32Array(newLength);

    for (let i = 0; i < newLength; i++) {
      const sourceIndex = i / resampleRatio;
      const index0 = Math.floor(sourceIndex);
      const index1 = Math.min(index0 + 1, this.leftChannel.length - 1);
      const fraction = sourceIndex - index0;

      leftResampled[i] = this.leftChannel[index0] * (1 - fraction) + this.leftChannel[index1] * fraction;
      rightResampled[i] = this.rightChannel[index0] * (1 - fraction) + this.rightChannel[index1] * fraction;
    }

    return [leftResampled, rightResampled];
  }

  randomParams(_pitchLock?: PitchLock): SampleParams {
    return { loaded: this.leftChannel !== null && this.rightChannel !== null };
  }

  mutateParams(params: SampleParams, _mutationAmount?: number, _pitchLock?: PitchLock): SampleParams {
    return params;
  }
}
