import {
  InvalidAccessError,
  InvalidStateError,
  NotSupportedError,
} from '../errors';
import { IIIRFilterNode } from '../jsi-interfaces';
import AudioNode from './AudioNode';
import { IIRFilterOptions } from '../types';
import type BaseAudioContext from './BaseAudioContext';

export default class IIRFilterNode extends AudioNode {
  constructor(context: BaseAudioContext, options: IIRFilterOptions) {
    IIRFilterNode.validateIIRFilterOptions(options);
    const iirFilterNode = context.context.createIIRFilter(options);
    super(context, iirFilterNode);
  }

  public getFrequencyResponse(
    frequencyArray: Float32Array,
    magResponseOutput: Float32Array,
    phaseResponseOutput: Float32Array
  ) {
    if (
      frequencyArray.length !== magResponseOutput.length ||
      frequencyArray.length !== phaseResponseOutput.length
    ) {
      throw new InvalidAccessError(
        `The lengths of the arrays are not the same frequencyArray: ${frequencyArray.length}, magResponseOutput: ${magResponseOutput.length}, phaseResponseOutput: ${phaseResponseOutput.length}`
      );
    }
    (this.node as IIIRFilterNode).getFrequencyResponse(
      frequencyArray,
      magResponseOutput,
      phaseResponseOutput
    );
  }

  private static validateIIRFilterOptions(options: IIRFilterOptions) {
    const { feedforward, feedback } = options;

    if (feedforward.length === 0 || feedforward.length > 20) {
      throw new NotSupportedError(
        `The length of feedforward must be between 1 and 20, but got ${feedforward.length}`
      );
    }

    if (feedforward.every((value) => value === 0)) {
      throw new InvalidStateError(
        `At least one value in feedforward must be non-zero`
      );
    }

    if (feedback.length === 0 || feedback.length > 20) {
      throw new NotSupportedError(
        `The length of feedback must be between 1 and 20, but got ${feedback.length}`
      );
    }

    if (feedback[0] === 0) {
      throw new InvalidStateError(
        `The first value of feedback must be non-zero`
      );
    }
  }
}
