import type { AudioProcessor, ProcessorCategory } from './AudioProcessor';

export class PanShuffler implements AudioProcessor {
  getName(): string {
    return 'Pan Shuffler';
  }

  getDescription(): string {
    return 'Smoothly pans segments across the stereo field';
  }

  getCategory(): ProcessorCategory {
    return 'Space';
  }

  process(
    leftChannel: Float32Array,
    rightChannel: Float32Array
  ): [Float32Array, Float32Array] {
    const length = leftChannel.length;
    const numSegments = Math.floor(Math.random() * 8) + 4;
    const segmentSize = Math.floor(length / numSegments);
    const transitionLength = Math.min(4410, Math.floor(segmentSize / 4));

    const outputLeft = new Float32Array(length);
    const outputRight = new Float32Array(length);

    // Generate random pan positions from -1 (left) to 1 (right)
    const panPositions: number[] = [];
    for (let i = 0; i < numSegments; i++) {
      panPositions.push(Math.random() * 2 - 1);
    }

    let writePos = 0;
    for (let i = 0; i < numSegments; i++) {
      const start = i * segmentSize;
      const end = i === numSegments - 1 ? length : (i + 1) * segmentSize;
      const segLen = end - start;

      const currentPan = panPositions[i];
      const nextPan = i < numSegments - 1 ? panPositions[i + 1] : currentPan;

      for (let j = 0; j < segLen && writePos < length; j++, writePos++) {
        let pan = currentPan;

        // Smooth transition to next segment's pan position
        if (i < numSegments - 1 && j >= segLen - transitionLength) {
          const transitionPos = (j - (segLen - transitionLength)) / transitionLength;
          const smoothTransition = 0.5 * (1.0 - Math.cos(Math.PI * transitionPos));
          pan = currentPan + (nextPan - currentPan) * smoothTransition;
        }

        // Constant-power panning
        const panAngle = (pan + 1) * 0.25 * Math.PI;
        const leftGain = Math.cos(panAngle);
        const rightGain = Math.sin(panAngle);

        // Mix both channels and apply panning
        const mono = (leftChannel[start + j] + rightChannel[start + j]) * 0.5;

        outputLeft[writePos] = mono * leftGain;
        outputRight[writePos] = mono * rightGain;
      }
    }

    return [outputLeft, outputRight];
  }
}
