/** 频率自相关算法
 * 参考: https://github.com/cwilso/PitchDetect
 * @param {Float32Array} buf - 音频数据
 * @param {number} sampleRate - 采样率
 * @returns {number} 频率
 */
function autoCorrelate(buf: Float32Array, sampleRate: number) {
	// Implements the ACF2+ algorithm
	var SIZE = buf.length;
	var rms = 0;

	for (var i = 0; i < SIZE; i++) {
		var val = buf[i];
		rms += val * val;
	}
	rms = Math.sqrt(rms / SIZE);
	if (rms < 0.01)
		// not enough signal
		return -1;

	var r1 = 0,
		r2 = SIZE - 1,
		thres = 0.2;
	for (var i = 0; i < SIZE / 2; i++)
		if (Math.abs(buf[i]) < thres) {
			r1 = i;
			break;
		}
	for (var i = 1; i < SIZE / 2; i++)
		if (Math.abs(buf[SIZE - i]) < thres) {
			r2 = SIZE - i;
			break;
		}

	buf = buf.slice(r1, r2);
	SIZE = buf.length;

	var c = new Array(SIZE).fill(0);
	for (var i = 0; i < SIZE; i++) for (var j = 0; j < SIZE - i; j++) c[i] = c[i] + buf[j] * buf[j + i];

	var d = 0;
	while (c[d] > c[d + 1]) d++;
	var maxval = -1,
		maxpos = -1;
	for (var i = d; i < SIZE; i++) {
		if (c[i] > maxval) {
			maxval = c[i];
			maxpos = i;
		}
	}
	var T0 = maxpos;

	var x1 = c[T0 - 1],
		x2 = c[T0],
		x3 = c[T0 + 1];
	let a = (x1 + x3 - 2 * x2) / 2;
	let b = (x3 - x1) / 2;
	if (a) T0 = T0 - b / (2 * a);

	return sampleRate / T0;
}
export const audioRecorder = {
	/** 录音实例 */
	audioContext: null as unknown as AudioContext,
	mediaRecorder: null as any,
	recordeState: false,
	progress: (frequency: number) => {},
	init() {
		// 创建音频上下文
		this.audioContext = new (window.AudioContext || (window as any).webkitAudioContext)();
	},
	/** 切换录音状态 */
	toggleRecord(open: boolean) {
		return new Promise((resolve, reject) => {
			if (open) {
				// 通过用户媒体设备获取音频流
				navigator.mediaDevices
					.getUserMedia({ audio: true })
					.then((stream) => {
						audioRecorder.mediaRecorder = stream.getAudioTracks()[0];
						audioRecorder.recordeState = true;
						// 创建音频源节点
						const source = this.audioContext.createMediaStreamSource(stream);

						// 创建分析器节点
						const analyser = this.audioContext.createAnalyser();
						analyser.fftSize = 2048; // 设置FFT大小，可以根据需要进行调整

						// 连接源节点和分析器节点
						source.connect(analyser);

						var buf = new Float32Array(analyser.fftSize);
						const sampleRate = this.audioContext.sampleRate;

						function getData() {
							if (!audioRecorder.recordeState) return;
							analyser.getFloatTimeDomainData(buf);
							const ac = autoCorrelate(buf, sampleRate);
							audioRecorder.progress(ac);
							setTimeout(() => {
								getData();
							}, 10);
						}
						getData();
						resolve(true);
					})
					.catch((error) => {
						resolve(false);
						console.error("Error accessing media devices:", error);
					});
			} else {
				audioRecorder.mediaRecorder.stop();
			}
		});
	},

	/** 检测是否支持录音 */
	checkSupport(): Promise<boolean> {
		return new Promise((resolve, reject) => {
			if (navigator.mediaDevices.getUserMedia) {
				const constraints = { audio: true };
				navigator.mediaDevices.getUserMedia(constraints).then(
					(stream) => {
						resolve(true);
						console.log("授权成功！");
					},
					() => {
						resolve(false);
						console.error("授权失败！");
					}
				);
			} else {
				resolve(false);
				console.error("浏览器不支持 getUserMedia");
			}
		});
	},
};
