<template>
	<view class="ss-recording-wrapper">
		<view class="ss-recording" @tap="clickMicBtn">
			<uni-icons :type="micIcon" size="24" color="#101333"></uni-icons>
		</view>
		<uni-popup ref="recordPopup" background-color="#fff" :is-mask-click="false">
		<view class="record-dialog">
			<view class="record-title">录音将在{{ countDown }}秒后自动结束</view>
			<view class="record-animation" :class="'show-bg-' + decibel">
				<view class="mic p-center">
					<uni-icons type="mic" :size="24" color="#2943d6" />
				</view>
				<template v-for="i in 10">
					<view class="mic-bg p-center" :class="'bg-' + i"></view>
				</template>
			</view>
			<view class="record-buttons">
				<button class="record-cancel" @tap="cancelRecord">取消</button>
				<button class="record-start" @tap="recorded">
					<view v-if="recordStatus == 3" class="record-loading">
						<uni-icons type="spinner-cycle" size="32rpx" color="#ffffff" />
					</view>
					<view v-if="recordStatus == 2" class="record-stop"></view>
					{{ recordStatus == 2 ? '我说完了' : recordStatus == 3 ? '音频处理中' : '开始录音' }}
				</button>
			</view>
		</view>
		</uni-popup>
	</view>
</template>

<script>
import { RequestApi } from '@/api/requestApi';

export default {
	data() {
		return {
			recordFlag: true,
			recordStatus: 1, // 1、待开始录音；2、录音中；3、处理中；
			recorderManager: null,
			isRecording: false,
			recordOption: {
				sampleRate: 8000, // 采样率
				numberOfChannels: 1, // 单声道
				format: 'mp3', // 格式为mp3获取原始音频数据
				frameSize: 1, // 帧大小
				frameBufferSize: 10 // 每次回调积累的帧数
			},
			recordDuration: 60,
			useTime: 0,
			countDownTimeout: null
		};
	},
	computed: {
		micIcon() {
			return this.recordFlag ? 'mic' : 'micoff';
		},
		maxDuration() {
			return this.recordDuration;
		},
		countDown() {
			let residue = this.maxDuration - parseInt(this.useTime / 10);
			return residue > 0 ? residue : 0;
		},
		decibel() {
			return this.useTime % 10;
		}
	},
	mounted() {
		this.canvasContext = uni.createCanvasContext('waveCanvas', this);
		this.initRecorder();
	},
	methods: {
		initRecorder() {
			this.recorderManager = uni.getRecorderManager();
			// 录音完成，上传解析
			this.recorderManager.onStop((res) => {
				this.stopCountDown();
				if (this.recordStatus == 2) {
					this.recordStatus = 3;
					console.log('临时文件路径:', res.tempFilePath);
					this.sendVideoFile(res.tempFilePath);
				}
			});
		},
		sendVideoFile(filePath) {
			RequestApi.transcribe(filePath)
				.then((res) => {
					this.recordStatus = 1;
					if (res.text == '（空内容）') {
						uni.showToast({
							title: '未检测到你说了什么',
							icon: 'none'
						});
					} else {
						this.$emit('setMessage', res.text);
					}
				})
				.catch((error) => {
					uni.showToast({
						title: '语音识别错误',
						icon: 'none'
					});
				})
				.finally(() => {
					if (this.$refs.recordPopup) {
						this.$refs.recordPopup.close();
					}
				});
		},
		clickMicBtn() {
			if (this.recordStatus == 1) {
				this.startRecord();
			}
		},
		startCountDown() {
			if (this.countDownTimeout) {
				clearTimeout(this.countDownTimeout);
			}
			this.countDownTimeout = setTimeout(() => {
				this.useTime++;
				this.countDownTimeout = null;
				if (this.useTime >= this.maxDuration * 10) {
					this.recorderManager.stop();
				} else {
					this.startCountDown();
				}
			}, 99);
		},
		stopCountDown() {
			if (this.countDownTimeout) {
				clearTimeout(this.countDownTimeout);
			}
		},
		startRecord() {
			uni.authorize({
				scope: 'scope.record',
				success: () => {
					this.recordFlag = true;
					this.isRecording = true;
					this.recordStatus = 2;
					this.recorderManager.start({
						...this.recordOption,
						duration: this.recordDuration * 1000,
						success: () => {
							this.useTime = 0;
							this.startCountDown();
							if (this.$refs.recordPopup) {
								this.$refs.recordPopup.open('bottom');
							}
						},
						fail: () => {
							uni.showToast({
								title: '录音启动失败',
								icon: 'none'
							});
						}
					});
				},
				fail: () => {
					this.recordStatus = 1;
					this.recordFlag = false;
					uni.showToast({
						title: '请授权麦克风权限',
						icon: 'none'
					});
				}
			});
		},
		recorded() {
			if (this.recordStatus == 1) {
				this.startRecord();
			}
			if (this.recordStatus == 2) {
				this.recorderManager.stop();
			}
		},
		cancelRecord() {
			this.recordStatus = 1;
			this.recorderManager.stop();
			if (this.animationId) {
				cancelAnimationFrame(this.animationId);
			}
			if (this.$refs.recordPopup) {
				this.$refs.recordPopup.close();
			}
		}
	}
};
</script>

<style scoped lang="scss">
@keyframes spin {
	0% {
		transform: rotate(0deg);
	}
	100% {
		transform: rotate(360deg);
	}
}

.ss-recording-wrapper {
	display: inline-flex;
	align-items: center;
}

.ss-recording {
	display: inline-flex;
	align-items: center;
}

.record-dialog {
	background-color: #ffffff;
	overflow: hidden;
	padding: 32rpx;

	.record-title {
		font-size: 32rpx;
		color: #101333;
		margin-bottom: 32rpx;
	}

	.record-animation {
		height: 280rpx;
		margin-bottom: 32rpx;
		position: relative;

		.p-center {
			position: absolute;
			top: 50%;
			left: 50%;
			transform: translate(-50%, -50%);
		}

		.mic {
			width: 64rpx;
			height: 64rpx;
			border-radius: 64rpx;
			border: 4rpx solid #2943d6;
			line-height: 64rpx;
			text-align: center;
			z-index: 100;
		}

		@for $i from 1 through 10 {
			&.show-bg-#{$i} {
				@for $j from 1 through 10 {
					.mic-bg {
						&.bg-#{$j} {
							opacity: if($j < $i, 1, 0);
						}
					}
				}
			}
		}

		.mic-bg {
			border: 2rpx solid #2943d6;
			transition: opacity 100ms linear;

			@for $i from 1 through 10 {
				&.bg-#{$i} {
					z-index: 100 - $i;
					width: 80rpx + $i * 20;
					height: 80rpx + $i * 20;
					border-radius: 40rpx + $i * 10;
					border-color: rgba(41, 67, 214, 1 - ($i * 0.1));
					opacity: 0;
				}
			}
		}
	}

	.record-canvas {
		width: 100%;
		height: 240rpx;
		margin-bottom: 60rpx;
	}
	.record-buttons {
		display: flex;
		justify-content: center;

		.record-cancel {
			border-radius: 50rpx;
			border: 1px solid #2943d6;
			color: #2943d6;
			margin-right: 16rpx;
			padding: 0 56rpx;
			background-color: #ffffff;

			&::after {
				background-color: transparent;
			}
		}

		.record-start {
			display: flex;
			align-items: center;
			justify-content: center;
			border-radius: 50rpx;
			border: 0;
			color: #ffffff;
			background-color: #2943d6;
			padding: 0 32rpx;
			width: 340rpx;

			.record-stop {
				width: 32rpx;
				height: 32rpx;
				background-color: #ffffff;
				margin-right: 16rpx;
				border-radius: 6rpx;
			}

			.record-loading {
				margin-right: 8rpx;
				animation: spin 3s linear infinite;
			}

			&::after {
				background-color: transparent;
			}
		}
	}
}
</style>
