type EncodeWavOptions = {
  numChannels?: number;
  sampleRate?: number;
  byteRate?: number;
};

/**
 * 编码pcm文件为wav文件
 * @param rawPCM
 * @param options
 * @returns
 */
export function encodeWav(rawPCM: Buffer | string, options?: EncodeWavOptions) {
  if (typeof rawPCM === 'string') {
    rawPCM = Buffer.from(rawPCM, 'binary');
  }

  if (!Buffer.isBuffer(rawPCM)) {
    throw new TypeError('pcm data must be Buffer or string');
  }
  const opt = options || {};
  const sampleRate = opt.sampleRate || 16000;
  const numChannels = opt.numChannels || 1;
  const byteRate = opt.byteRate || 16;

  const buf = rawPCM;
  const header = Buffer.alloc(44);

  header.write('RIFF', 0);
  header.writeUInt32LE(buf.length, 4);
  header.write('WAVE', 8);
  header.write('fmt ', 12);
  header.writeUInt8(16, 16);
  header.writeUInt8(1, 20);
  header.writeUInt8(numChannels, 22);
  header.writeUInt32LE(sampleRate, 24);
  header.writeUInt32LE(byteRate, 28);
  header.writeUInt8(4, 32);
  header.writeUInt8(16, 34);
  header.write('data', 36);
  header.writeUInt32LE(buf.length + 44 - 8, 40);

  return Buffer.concat([header, buf]);
}

/**
 * 解码wav文件
 * @param rawWav
 * @returns
 */
export function decodeWav(rawWav: Buffer | string) {
  if (typeof rawWav === 'string') {
    rawWav = Buffer.from(rawWav, 'binary');
  }

  if (!Buffer.isBuffer(rawWav)) {
    throw new TypeError('pcm data must be Buffer or string');
  }

  // remove the header of pcm format
  rawWav = rawWav.subarray(44);

  return rawWav;
}

export const converter = {
  encodeWav,
  decodeWav,
};

/**
 * 生成无声音频
 * @param duration 音频时长（秒）
 * @param sampleRate 采样率
 * @param channels 声道数
 * @returns 无声音频
 */
export const generateSilent = (duration: number = 2, sampleRate: number = 16000, channels: number = 1) => {
  const bufferSize = Math.floor(duration * sampleRate * channels * 2); // 2 bytes per sample
  const silent = Buffer.alloc(bufferSize);
  return silent;
};
