<template>
	<view class="voice-input">
		<view class="voice-input-bar" :class="{ recording: recording }" id="voice-input-bar" @click.stop=""
			@touchstart.prevent="onStartRecord" @touchmove.prevent="onTouchMove" @touchend.prevent="onEndRecord">
			{{ recording ? '正在录音' : '长按 说话' }}
		</view>
		<view v-if="recording" class="voice-input-window" :style="recordWindowStyle">
			<view class="rc-wave">
				<text class="note" style="--d: 0"></text>
				<text class="note" style="--d: 1"></text>
				<text class="note" style="--d: 2"></text>
				<text class="note" style="--d: 3"></text>
				<text class="note" style="--d: 4"></text>
				<text class="note" style="--d: 5"></text>
				<text class="note" style="--d: 6"></text>
			</view>
			<view class="rc-tip">{{ recordTip }}</view>
			<view class="cancel-btn" @click="onCancel">
				<im-icon name="close" :color="moveToCancel ? 'red' : 'black'" :size="moveToCancel ? 45 : 40" />
			</view>
			<view class="opt-tip" :class="moveToCancel ? 'red' : 'black'">{{ moveToCancel ? '松手取消' : '松手发送,上划取消' }}
			</view>
		</view>

	</view>
</template>

<script setup lang="ts">
import { ref, computed, onUnmounted } from 'vue'
import { RecorderApp, RecorderH5 } from '../../index'
import ImIcon from '../im-icon/im-icon.vue'
import type { VoiceInputEmits } from '../../types/components/voice-input'

const recording = ref(false);
const moveToCancel = ref(false);
const recordBarTop = ref(0);
const druation = ref(0);
const rcTimer = ref<number | null>(null);

const getRecorder = () => {
	// #ifdef H5
	return new RecorderH5()
	// #endif

	// #ifndef H5
	return new RecorderApp()
	// #endif
}

let rc = getRecorder()


const emit = defineEmits<VoiceInputEmits>();

onUnmounted(() => {
	stopTimer();
	recording.value = false;
})

const onTouchMove = (e: any) => {
	const moveY = e.touches[0].clientY;
	moveToCancel.value = moveY < recordBarTop.value - 40;
};

const onCancel = () => {
	if (recording.value) {
		moveToCancel.value = true;
		onEndRecord();
	}
};

const onStartRecord = async () => {
	/* 用户第一次使用语音会唤醒录音权限请求，此时会导致@touchend失效，
	   一直处于录音状态，这里允许用户再次点击发送语音并结束录音 */
	if (recording.value) {
		return;
	}
	console.log("开始录音");
	moveToCancel.value = false;
	// await initRecordBar();

	// if (!rc.checkIsEnable()) {
	// 	return;
	// }

	rc.start().then(() => {
		recording.value = true;
		console.log("开始录音成功");
		// 开始计时
		startTimer();
	}).catch((e: any) => {
		console.log("录音失败" + JSON.stringify(e));
		uni.showToast({
			title: "录音失败",
			icon: "none"
		});
	});
};

const onEndRecord = () => {
	if (!recording.value) {
		return;
	}
	recording.value = false;
	// 停止计时
	stopTimer();
	// 停止录音
	rc.close();
	// 触屏位置是否移动到了取消区域
	if (moveToCancel.value) {
		console.log("录音取消");
		return;
	}
	// 大于1秒才发送
	if (druation.value <= 1) {
		uni.showToast({
			title: "说话时间太短",
			icon: 'none'
		});
		return;
	}

	rc.upload().then((data: any) => {
		emit("send", data);
	}).catch((e: any) => {
		console.error(e)
		uni.showToast({
			title: '录音上传失败',
			icon: 'none'
		});
	});
};

const startTimer = () => {
	druation.value = 0;
	stopTimer();
	rcTimer.value = Number(setInterval(() => {
		druation.value++;
		// 大于60s,直接结束
		if (druation.value >= 60) {
			onEndRecord();
		}
	}, 1000));
};

const stopTimer = () => {
	if (rcTimer.value) {
		clearInterval(rcTimer.value);
		rcTimer.value = null;
	}
};

// const initRecordBar = () => {
// 	const query = uni.createSelectorQuery().in(getCurrentInstance());
// 	query.select('#voice-input-bar').boundingClientRect((rect: any) => {
// 		// 顶部高度位置
// 		recordBarTop.value = rect.top;
// 	}).exec();
// };

/**
 * 初始化录音条位置信息
 * 兼容微信小程序和H5环境
 */
const initRecordBar = (): Promise<{ top: number; height: number; width: number }> => {
	return new Promise((resolve, reject) => {
		// 获取组件实例
		const instance = getCurrentInstance()
		if (!instance) {
			reject(new Error('无法获取组件实例'))
			return
		}

		// 创建选择器查询
		const query = uni.createSelectorQuery().in(instance)

		query.select('#voice-input-bar').boundingClientRect((rect: any) => {
			if (rect) {
				const positionInfo = {
					top: rect.top || 0,
					height: rect.height || 0,
					width: rect.width || 0,
					left: rect.left || 0,
					right: rect.right || 0,
					bottom: rect.bottom || 0
				}
				resolve(positionInfo)
			} else {
				reject(new Error('无法获取录音条位置信息'))
			}
		}).exec()
	})
}

const recordWindowStyle = computed(() => {
	const windowHeight = uni.getWindowInfo().windowHeight;
	const bottom = windowHeight - recordBarTop.value + 12;
	return `bottom:${bottom}px;`;
});

const recordTip = computed(() => {
	if (druation.value > 50) {
		return `${60 - druation.value}s后将停止录音`;
	}
	return `录音时长:${druation.value}s`;
});


</script>

<style lang="scss" scoped>
.voice-input {
	.rc-wave {
		display: flex;
		align-items: flex-end;
		justify-content: center;
		position: relative;
		height: 80rpx;

		.note {
			background: linear-gradient(to top, $im-color-primary-light-1 0%, $im-color-primary-light-6 100%);
			width: 4px;
			height: 50%;
			border-radius: 5rpx;
			margin-right: 4px;
			animation: loading 0.5s infinite linear;
			animation-delay: calc(0.1s * var(--d));

			@keyframes loading {
				0% {
					background-image: linear-gradient(to right, $im-color-primary-light-1 0%, $im-color-primary-light-6 100%);
					height: 20%;
					border-radius: 5rpx;
				}

				50% {
					background-image: linear-gradient(to top, $im-color-primary-light-1 0%, $im-color-primary-light-6 100%);
					height: 80%;
					border-radius: 5rpx;
				}

				100% {
					background-image: linear-gradient(to top, $im-color-primary-light-1 0%, $im-color-primary-light-6 100%);
					height: 20%;
					border-radius: 5rpx;
				}
			}
		}
	}

	.voice-input-bar {
		padding: 10rpx;
		margin: 10rpx;
		border-radius: 10rpx;
		text-align: center;
		box-shadow: $im-box-shadow;

		&.recording {
			background-color: $im-color-primary;
			color: #fff;
		}
	}

	.voice-input-window {
		position: fixed;
		left: 0;
		right: 0;
		height: 360rpx;
		background-color: rgba(255, 255, 255, 0.95);
		padding: 30rpx;

		.icon-microphone {
			text-align: center;
			font-size: 80rpx;
			padding: 10rpx;

		}

		.rc-tip {
			text-align: center;
			font-size: $im-font-size-small;
			color: $im-text-color-light;
			margin-top: 20rpx;
		}

		.cancel-btn {
			text-align: center;
			margin-top: 40rpx;
			height: 80rpx;

		}

		.opt-tip {
			text-align: center;
			font-size: 30rpx;
			padding: 20rpx;
		}

		.red {
			color: $im-color-danger !important;
		}

	}
}
</style>