import { reactive, watch } from "vue";
import { tickUrl as tick, tockUrl as tock } from "/src/constant/audios";
import { browser } from "./utils";
import state from "../pages/detail/state";
type IOptions = {
	speed: number;
};
const ac = window.AudioContext || (window as any).webkitAudioContext || (window as any).mozAudioContext || (window as any).msAudioContext;
const browserInfo = browser();
let tipsTimer: any = null; // 光标提示定时器
export const metronomeData = reactive({
	disable: true,
	lineShow: false,
	isClick: false,
	metro: null as unknown as Metronome,
	metroList: [] as number[],
	activeList: [] as number[],
	metroMeasure: [] as any[],
	activeIndex: null as unknown as number,
	activeMetro: {} as any,
	cursorMode: 1 as number, // 光标模式：1:音符指针；2:节拍指针；3:关闭指针
	cursorTips: '' as string, // 光标模式提示文字
});

watch(
	() => metronomeData.cursorMode,
	() => {
		const img: HTMLElement = document.querySelector("#cursorImg-0")!;
		if (img) {
			switch (metronomeData.cursorMode) {
				case 1:
					img.classList.remove("lineHide");
                    img.style.opacity = 'inherit'
					metronomeData.cursorTips = '您已切换到指针跟随音符播放';
                    img.style.opacity = 'inherit'
					break;
				case 2:
					img.classList.add("lineHide");
                    img.style.opacity = 'inherit'
					metronomeData.cursorTips = '您已切换到指针跟随节拍播放';
                    console.log('光标',img)
					break;
				case 3:
                    img.style.opacity = '0'
					metronomeData.cursorTips = '您已关闭指针显示';
					console.log('隐藏光标')
					break;
				default:
					break;
			}
			hideCursorTip()
		}
	}
);
class Metronome {
	ctx = new ac();
	playType = "tick";
	source = null as any; // 创建音频源头
	source1 = null as any;
	source2 = null as any;

	constructor(option?: IOptions) {}
	init(times: any[]) {
		this.calculation(times);
		metronomeData.activeList = [];
		return new Promise(async (resolve) => {
			if (this.source1 && this.source2) return resolve(true);
			this.source1 = await this.loadAudio1();
			this.source2 = await this.loadAudio2();
			resolve(true);
		});
	}

	// 播放
	sound = (currentTime: number) => {
		// console.log("🚀 ~ currentTime", currentTime)
		// currentTime = setCurrentTime(currentTime);
		let index = -1;
		let activeMetro = -1;
		for (let i = 0; i < metronomeData.metroList.length; i++) {
			const item = metronomeData.metroList[i];

			if (currentTime >= item) {
				// console.log(currentTime , item)
				index = i;
				activeMetro = item;
			} else {
				break;
			}
		}
		if (index > -1 && metronomeData.activeIndex !== index) {
			metronomeData.activeIndex = index;
			// console.log("播放", metronomeData.activeIndex);
			metronomeData.activeMetro = this.getStep(activeMetro);
			// console.log("🚀 ~ 节拍metronomeData.activeMetro",metronomeData.activeMetro.measureNumberIndex, metronomeData.activeMetro.index, metronomeData.activeMetro)
			this.playAudio();
			metronomeData.isClick = false;
			return;
		}
		metronomeData.isClick = false;
	};
	// 播放
	playAudio = () => {
		this.source = this.ctx.createBufferSource();
		this.source.buffer = metronomeData.activeMetro?.index === 0 ? this.source1 : this.source2;
		const gainNode = this.ctx.createGain();
		gainNode.gain.value = metronomeData.disable ? 0 : 0.4;
		this.source.connect(gainNode);
		gainNode.connect(this.ctx.destination);
		this.source.start(0); //立即播放
	};

	// 切换
	selectPlay() {}

	loadAudio1 = async () => {
		const audioUrl = tick; // "/tick.wav";
		const res = await fetch(audioUrl);
		const arrayBuffer = await res.arrayBuffer(); // byte array字节数组
		// console.log("🚀 ~ arrayBuffer", arrayBuffer)
		const audioBuffer = await this.ctx.decodeAudioData(arrayBuffer, function (decodeData) {
			return decodeData;
		});
		return audioBuffer;
	};
	loadAudio2 = async () => {
		const audioUrl = tock; //"/tock.wav";
		const res = await fetch(audioUrl);
		const arrayBuffer = await res.arrayBuffer(); // byte array字节数组
		const audioBuffer = await this.ctx.decodeAudioData(arrayBuffer, function (decodeData) {
			return decodeData;
		});
		return audioBuffer;
	};
	getStep(time: number) {
		for (let i = 0; i < metronomeData.metroMeasure.length; i++) {
			const list = metronomeData.metroMeasure[i];
			const item = list.find((n: any) => n.time === time);
			if (item) {
				// console.log('index',item)
				return item;
			}
		}
		return {};
	}

	// 计算 所有的拍子的时间
	calculation(times: any[]) {
		console.log("🚀 ~ times", times);
		// 1.统计有多少小节
		const measures: any[] = [];
		let xmlNumber = -1;
		for (let i = 0; i < times.length; i++) {
			const note = times[i];
			const measureNumberXML = note?.noteElement?.sourceMeasure?.measureNumber + 1 || -1;
			// console.log("🚀 ~ note?.noteElement?.sourceMeasure", note?.noteElement?.sourceMeasure)
			// console.log("🚀 ~ measureNumberXML", measureNumberXML, note)
			// console.log("🚀 ~ measureNumberXML", note)
			const measureListIndex = note?.noteElement?.sourceMeasure?.measureListIndex;
			if (measureNumberXML > -1) {
				if (measureNumberXML != xmlNumber) {
					const m = {
						measureNumberXML: measureNumberXML,
						measureNumberIndex: measureListIndex,
						numerator: note?.noteElement?.sourceMeasure?.ActiveTimeSignature?.numerator || 0,
						start: note.measures[0].time,
						end: note.measures[note.measures.length - 1].endtime,
						time: note.measures[note.measures.length - 1].endtime - note.measures[0].time,
						stave_x: note?.noteElement?.sourceMeasure?.verticalMeasureList?.[0]?.stave?.x || 0,
						end_x: (note?.stave?.end_x || 0) || 0,
						stepList: [] as number[],
						svgs: [] as any[],
					};
					// 2.统计小节的拍数
					// 3.统计小节的时长, 开始时间,结束时间
					// console.log(measureNumberXML,note.measures, times.filter((n: any) => n?.noteElement?.sourceMeasure?.measureListIndex == measureListIndex))
					if ([121].includes(state.subjectId)) {
						const _measures = times.filter((n: any) => n?.noteElement?.sourceMeasure?.measureListIndex == measureListIndex);
						note.measures = _measures;
						m.start = note.measures[0].time;
						m.end = note.measures[note.measures.length - 1].endtime;
						m.time = note.measures[note.measures.length - 1].endtime - note.measures[0].time;
						try {
							const tickables = note.noteElement.sourceMeasure.verticalMeasureList.reduce((arr: any[], value: any) => {
								arr.push(...value.vfVoices["1"].tickables);
								return arr;
							}, []);
							const xList: any[] = [];
							m.svgs = tickables
								.map((n: any) => {
									const x = n.getBoundingBox().x;
									if (!xList.includes(x) && n.duration !== "w") {
										xList.push(x);
										n._start_x = x;
										return n;
									}
								})
								.filter(Boolean)
								.sort((a: any, b: any) => a._start_x - b._start_x);
							// console.log(measureNumberXML, m.svgs)
						} catch (error) {
							console.log(error);
						}
						m.stepList = calculateMutilpleMetroStep(note.measures, m);
					} else {
						m.stepList = calculateMetroStep(note.measures, m);
					}
					measures.push(m);
					xmlNumber = measureNumberXML;
				}
			}
		}
		console.log(measures, measures.length,6667);

		let metroList: number[] = [];
		const metroMeasure: any[] = [];
		// 4.按照拍数将时长平均分配
		try {
			for (let i = 0; i < measures.length; i++) {
				const measure = measures[i];
				const noteStep = measure.time / measure.numerator;
				// console.log("🚀 ~ measure.measureNumberXML",measure.measureNumberXML, noteStep)
				const WIDTH = [121].includes(state.subjectId) ? 95 : 100;
				const widthStep = WIDTH / (measure.numerator + 1);
				metroMeasure[i] = [] as number[];
				// console.log('stepList', [...measure.stepList], measure.measureNumberXML)
				for (let j = 0; j < measure.numerator; j++) {
					const time = noteStep * j + measure.start;
					metroList.push(time);
					let left = "";
					if (measure.stepList[j] === -1 || (measure.measureNumberXML === 1 && !measure.stepList[j])) {
						continue
					}
					if (measure.stepList[j]) {
						left = measure.stepList[j] + "px";
					} else {
						const preLeft = measure.stepList[j - 1];
						left = !preLeft ? `${widthStep}%` : preLeft.toString().indexOf("%") > -1 ? `${preLeft} + ${widthStep}%` : `${preLeft}px + ${widthStep}%`;
						measure.stepList[j] = left;
					}
					metroMeasure[i].push({
						index: j,
						time,
						// left: (measure.stepList[j] ? measure.stepList[j] + 'px' : (j + 1) * widthStep + '%'),
						left: left?.indexOf("%") > -1 ? `calc(${left})` : left,
						measureNumberXML: measure.measureNumberXML,
					});
				}
			}
		} catch (error) {
			console.log(error);
		}
		// console.log(metroList, metroMeasure);
		// 5.得到所有的节拍时间
		metronomeData.metroList = metroList;
		metronomeData.metroMeasure = metroMeasure;
	}
}

// 计算拍子的时值
function calculateMetroStep(arr: any[], m: any): number[] {
	const measureLength = arr.reduce((total: number, item: any) => {
		total += item._noteLength;
		return total;
	}, 0);
	const clap = measureLength / m.numerator;
	if (arr.length === 1) {
		const wholeNote = arr[0].svgElelent
		if (wholeNote && !wholeNote.isRest()) {
			const measure_bbox = wholeNote?.attrs?.el?.parentElement?.parentElement?.getBoundingClientRect?.() || { x: 0, right: 0 };
			let bbox = wholeNote?.attrs?.el?.getBoundingClientRect?.() || { x: 0 };
			let stepWidth = Math.abs(measure_bbox.right - bbox.x) / m.numerator
			let stepList: number[] = [];
			for(let i = 0; i < m.numerator; i++){
				// 是第一个小节,并且不是全音符,是弱起
				if (m.measureNumberXML === 1 && wholeNote.duration !== "w") {
					stepList.push(i === 0 ? bbox.x - measure_bbox.x : -1)
				} else {
					stepList.push(bbox.x - measure_bbox.x + i * stepWidth)
				}
			}
			// console.log("🚀 ~ stepList:", stepList, m.measureNumberXML)
			return stepList;
		}
		try {
			// 开头是休止符
			if (m.measureNumberXML === 1 && wholeNote && wholeNote.isRest()) {
				const measure_bbox = wholeNote?.attrs?.el?.parentElement?.parentElement?.getBoundingClientRect?.() || { x: 0, right: 0 };
				let bbox = wholeNote?.attrs?.el?.getBoundingClientRect?.() || { x: 0 };
				let stepWidth = Math.abs(measure_bbox.right - bbox.x) / m.numerator
				let stepList: number[] = [];
				for(let i = -1; i < m.numerator - 1; i++){
					stepList.push(bbox.x - measure_bbox.x + i * stepWidth)
				}
				// console.log(wholeNote?.attrs?.el, m.measureNumberXML)
				// console.log("🚀 ~ stepList:", stepList, m.measureNumberXML)
				return stepList;
			}
		} catch (error) {
			console.log("🚀 ~ error:", error)
		}
		
		return [];
	}
	// console.log("🚀 ~ arr", [...arr],`小节总时值: ${measureLength}`, clap, m.measureNumberXML);
	let totalLength = 0;
	let notes: any[] = [];
	let stepList: number[] = [];
	for (let i = 0; i < arr.length; i++) {
		const item = arr[i];
		item.index = i;
		const noteLength = item._noteLength;
		totalLength += noteLength;
		// 大于一拍
		const exceedStep = totalLength / clap;
		// console.log(`note`, item?.svgElelent?.attrs?.el,notes.length,{noteLength, exceedStep,clap}, m.measureNumberXML)
		if (exceedStep >= 1) {
			totalLength -= clap;
			// 一拍
			const measure_bbox = item?.svgElelent?.attrs?.el?.parentElement?.parentElement?.getBoundingClientRect?.() || { x: 0 };
			if (notes.length > 0) {
				let bbox = notes[0]?.svgElelent?.attrs?.el?.querySelector('.vf-note')?.getBoundingClientRect?.() || { x: 0 };
				let x: any = bbox.x - measure_bbox.x;
				if ((notes[0]._noteLength / clap) >= 1) {
					const nextNote = arr[notes[0].index + 1]?.svgElelent?.attrs?.el?.getBoundingClientRect?.() || { x: measure_bbox.right } || { x: 0 };
					const stepWidth = Math.abs(bbox.x - nextNote.x) / 2;
					x = bbox.x - measure_bbox.x + stepWidth;
					// console.log(`音符超一拍`, notes[0]?.svgElelent?.attrs?.el, arr[notes[0].index + 1]?.svgElelent?.attrs?.el, bbox.x - nextNote.x, stepWidth, m.measureNumberXML);
				}
				// console.log(`一拍`, notes[0]?.svgElelent?.attrs?.el, m.measureNumberXML, notes[0]._noteLength , clap, 'aa')
				stepList.push(x);
			} else {
				let bbox = item?.svgElelent?.attrs?.el?.querySelector('.vf-note')?.getBoundingClientRect?.() || { x: 0 };
				let x: any = bbox.x - measure_bbox.x
				// console.log(`一拍`, item?.svgElelent?.attrs?.el, m.measureNumberXML)
				stepList.push(x);
			}
			notes = [];
			let bbox = item?.svgElelent?.attrs?.el?.querySelector('.vf-note')?.getBoundingClientRect?.() || { x: 0 };
			let x: any = bbox.x - measure_bbox.x;
			let stepWidth = 0;
			if (exceedStep > 1) {
				// 二拍以上
				const nextNote = arr[i + 1]?.svgElelent?.attrs?.el?.querySelector('.vf-note')?.getBoundingClientRect?.() || { x: measure_bbox.right } || { x: 0 };
				stepWidth = Math.abs(bbox.x - nextNote.x) / Math.ceil(exceedStep);
				// console.log("二拍以上 ~ nextNote:",bbox.x , nextNote.x,stepWidth, item?.svgElelent?.attrs?.el,arr[i + 1]?.svgElelent?.attrs?.el, exceedStep);
			}

			for (let j = 1; j < exceedStep; j++) {
				totalLength -= clap;
				// console.log(`超一拍`,item?.svgElelent?.attrs?.el, m.measureNumberXML)
				stepList.push(x + stepWidth * j);
			}
		}

		//有时值就将音符加入
		if (totalLength > Number.EPSILON && totalLength > 0) {
			notes.push(item);
		}
	}
	stepList = stepList.reduce((list: any[], n: number) => {
		if (list.includes(n)) {
			list.push(undefined as any);
		} else {
			list.push(n);
		}
		return list;
	}, []);
	// console.log("stepList", [...stepList], m.measureNumberXML);
	// for (let i in stepList) {
	// 	stepList[i] = stepList[i] / state.musicZoom
	// }
	// console.log('🚀 ~ stepList:',stepList)
	return stepList;
}
// 计算单声部多声轨的拍子的时值
function calculateMutilpleMetroStep(arr: any[], m: any): number[] {
	// console.log("🚀 ~ m:", [...m.svgs])
	const step = m.time / m.numerator;
	const measure_bbox = arr[0]?.svgElelent?.attrs?.el?.parentElement?.parentElement?.getBoundingClientRect?.() || { x: 0 };
	if (arr.length === 1) {
		const staveNote = m.svgs[0];
		// 大于一拍
		let bbox = staveNote?.attrs?.el?.getBoundingClientRect?.() || { x: 0 };
		if (staveNote && !staveNote.isRest()) {
			return [bbox.x - measure_bbox.x];
		}
		return [];
	}
	// console.log("🚀 ~ arr", arr, step, m.measureNumberXML);
	let total = 0;
	let notes: any[] = [];
	let stepList: number[] = [];
	for (let i = 0; i < arr.length; i++) {
		const item = arr[i];
		item._index = i;
		const noteTime = item.endtime - item.time;
		total += noteTime;
		let svgEle = m.svgs[i]?.attrs?.el;
		// 大于一拍
		let bbox = svgEle?.getBoundingClientRect?.() || { x: 0 };
		// console.log(m.measureNumberXML, svgEle, i)
		if (noteTime > step) {
			total -= step;
			// console.log('超过一拍了', notes, m.measureNumberXML)
			let x = bbox.x - measure_bbox.x;
			if (notes.length > 0) {
				svgEle = m.svgs[notes[0]._index]?.attrs?.el;
				bbox = svgEle?.getBoundingClientRect?.() || { x: 0 };
				x = bbox.x - measure_bbox.x;
			}
			stepList.push(x);
			notes = [];
		} else {
			notes.push(item);
		}
		// console.log(notes)
		if (Math.abs(total - step) < 0.001) {
			let x = bbox.x - measure_bbox.x;
			if (notes.length > 0) {
				svgEle = m.svgs[notes[0]._index]?.attrs?.el;
				bbox = svgEle?.getBoundingClientRect?.() || { x: 0 };
				x = bbox.x - measure_bbox.x;
			}
			// console.log("一拍",svgEle,notes,m.svgs, m.measureNumberXML);
			stepList.push(x);
			total = 0;
			notes = [];
		}
	}
	stepList = stepList.reduce((list: any[], n: number) => {
		if (list.includes(n)) {
			list.push(undefined as any);
		} else {
			list.push(n);
		}
		return list;
	}, []); //Array.from(new Set(stepList))
	// console.log('stepList', stepList, m.measureNumberXML)
	// for (let i in stepList) {
	// 	stepList[i] = stepList[i] / state.musicZoom
	// }
	// console.log('🚀 ~ stepList:',stepList)
	return stepList;
}

// 延迟兼容处理
function setCurrentTime(time: number) {
	if (browserInfo.huawei || browserInfo.xiaomi) {
		time += 0.125;
	} else if (browserInfo.android) {
		time += 0.11;
	} else if (browserInfo.ios) {
		time += 0.01;
	}
	return time;
}

// 自动隐藏光标提示
function hideCursorTip() {
	if (!tipsTimer) {
		tipsTimer = setTimeout(() => {
			metronomeData.cursorTips = ''
			clearTimeout(tipsTimer)
			tipsTimer = null
		}, 2000);
	} else {
		clearTimeout(tipsTimer)
		tipsTimer = setTimeout(() => {
			metronomeData.cursorTips = ''
			clearTimeout(tipsTimer)
			tipsTimer = null
		}, 2000);
	}
}

export default Metronome;
