<template>
	<view class="voice-call-container">
		<!-- 状态栏占位 -->
		<view :style="{ height: statusBarHeight + 'px' }"></view>
		
		<!-- 返回按钮 -->
		<view class="back-btn" @click="endCall">
			<image src="/static/images/back.png" mode="aspectFit"></image>
		</view>
		
		<!-- 恋人形象 -->
		<view class="lover-avatar-container">
			<image 
				class="lover-avatar" 
				:class="{ 'speaking': isSpeaking, 'listening': isListening }"
				:src="loverAvatar" 
				mode="aspectFill">
			</image>
			
			<!-- 状态指示器 -->
			<view class="status-indicator">
				<view class="status-dot" :class="callStatus"></view>
				<text class="status-text">{{ statusText }}</text>
			</view>
			
			<!-- 音频波形动画 -->
			<view class="audio-wave" v-if="isSpeaking">
				<view class="wave-bar" v-for="i in 5" :key="i"></view>
			</view>
		</view>
		
		<!-- 对话文本显示 -->
		<view class="conversation-text">
			<view class="text-bubble user" v-if="userText">
				<text>{{ userText }}</text>
			</view>
			<view class="text-bubble ai" v-if="aiText">
				<text>{{ aiText }}</text>
			</view>
		</view>
		
		<!-- 控制按钮 -->
		<view class="control-buttons">
			<view class="control-btn" @touchstart="startTalk" @touchend="stopTalk" @touchcancel="stopTalk">
				<image src="/static/images/mic.png" mode="aspectFit"></image>
				<text>{{ micEnabled ? '松开结束' : '按住说话' }}</text>
			</view>
			
			<view class="control-btn end-call" @click="endCall">
				<image src="/static/images/phone_end.png" mode="aspectFit"></image>
				<text>挂断</text>
			</view>
		</view>
	</view>
</template>

<script>
import { LoverBasic } from '@/utils/api.js';
import { baseURLPy } from '@/utils/request.js';

export default {
	data() {
		return {
			statusBarHeight: uni.getWindowInfo().statusBarHeight,
			websocket: null,
			loverAvatar: '',
			callStatus: 'connecting', // connecting, connected, speaking, listening
			isSpeaking: false,
			isListening: false,
			micEnabled: false,
			userText: '',
			aiText: '',
			recorderManager: null,
			audioContext: null,
		};
	},
	computed: {
		statusText() {
			const statusMap = {
				connecting: '连接中...',
				connected: '已连接',
				speaking: 'AI正在说话',
				listening: '正在聆听',
			};
			return statusMap[this.callStatus] || '未知状态';
		}
	},
	onLoad() {
		this.initCall();
	},
	onUnload() {
		this.cleanup();
	},
	methods: {
		async initCall() {
			// 获取恋人信息
			try {
				const res = await LoverBasic();
				if (res.code === 1 && res.data) {
					this.loverAvatar = res.data.avatar_url || '/static/images/default_avatar.png';
				}
			} catch (e) {
				console.error('获取恋人信息失败', e);
			}
			
			// 初始化录音管理器
			// #ifndef H5
			try {
				this.recorderManager = uni.getRecorderManager();
				
				// 录音停止时处理
				this.recorderManager.onStop((res) => {
					console.log('📝 录音结束', res);
					
					if (!res.tempFilePath) {
						console.error('❌ 没有录音文件路径');
						return;
					}
					
					// 读取录音文件并发送
					const fs = uni.getFileSystemManager();
					fs.readFile({
						filePath: res.tempFilePath,
						// 不指定 encoding，返回 ArrayBuffer
						success: (fileRes) => {
							console.log('✅ 文件读取成功');
							console.log('📊 数据类型:', typeof fileRes.data);
							console.log('📊 是否为 ArrayBuffer:', fileRes.data instanceof ArrayBuffer);
							
							// 验证数据类型
							if (!(fileRes.data instanceof ArrayBuffer)) {
								console.error('❌ 数据不是 ArrayBuffer');
								return;
							}
							
							const actualSize = fileRes.data.byteLength;
							console.log('📊 文件大小:', actualSize, 'bytes');
							console.log('📊 预计录音时长:', (actualSize / 32000).toFixed(2), '秒');
							
							// 验证文件大小（至少1秒）
							if (actualSize < 32000) {
								console.error('❌ 文件太小（< 1秒），可能录音失败');
								uni.showToast({
									title: '录音太短，请重试',
									icon: 'none'
								});
								return;
							}
							
							// 分片发送音频数据
							this.sendAudioInChunks(fileRes.data);
						},
						fail: (err) => {
							console.error('❌ 文件读取失败:', err);
							uni.showToast({
								title: '文件读取失败',
								icon: 'none'
							});
						}
					});
				});
				
				// 录音错误处理
				this.recorderManager.onError((err) => {
					console.error('❌ 录音错误:', err);
					uni.showToast({
						title: '录音失败',
						icon: 'none'
					});
				});
				
			} catch (e) {
				console.warn('录音管理器初始化失败', e);
			}
			// #endif
			
			// 初始化音频播放器
			try {
				this.audioContext = uni.createInnerAudioContext();
				this.audioContext.onPlay(() => {
					this.isSpeaking = true;
					this.callStatus = 'speaking';
				});
				this.audioContext.onEnded(() => {
					this.isSpeaking = false;
					this.callStatus = 'connected';
				});
			} catch (e) {
				console.warn('音频播放器初始化失败', e);
			}
			
			// 连接WebSocket
			this.connectWebSocket();
		},
		
		connectWebSocket() {
			const token = uni.getStorageSync('token');
			// 将 http:// 替换为 ws://，https:// 替换为 wss://
			const wsBaseUrl = baseURLPy.replace('http://', 'ws://').replace('https://', 'wss://');
			const wsUrl = `${wsBaseUrl}/voice/call?token=${token}&ptt=true`;
			
			console.log('WebSocket URL:', wsUrl);
			
			this.websocket = uni.connectSocket({
				url: wsUrl,
				success: () => {
					console.log('WebSocket连接成功');
				},
				fail: (err) => {
					console.error('WebSocket连接失败', err);
					uni.showToast({
						title: '连接失败',
						icon: 'none'
					});
				}
			});
			
			this.websocket.onOpen(() => {
				console.log('WebSocket已打开');
				this.callStatus = 'connected';
			});
			
			this.websocket.onMessage((res) => {
				console.log('收到消息', res);
				if (typeof res.data === 'string') {
					try {
						const data = JSON.parse(res.data);
						this.handleSignal(data);
					} catch (e) {
						console.error('解析消息失败', e);
					}
				} else {
					// 二进制音频数据
					this.playAudio(res.data);
				}
			});
			
			this.websocket.onError((err) => {
				console.error('WebSocket错误', err);
				this.callStatus = 'error';
			});
			
			this.websocket.onClose(() => {
				console.log('WebSocket已关闭');
				this.callStatus = 'disconnected';
			});
		},
		
		handleSignal(data) {
			switch (data.type) {
				case 'ready':
					console.log('通话准备就绪');
					break;
				case 'partial_asr':
					this.userText = data.text;
					break;
				case 'reply_text':
					this.aiText = data.text;
					break;
				case 'reply_end':
					this.isSpeaking = false;
					this.callStatus = 'connected';
					break;
				case 'interrupt':
					console.log('AI被打断');
					break;
				case 'error':
					uni.showToast({
						title: data.msg || '发生错误',
						icon: 'none'
					});
					break;
			}
		},
		
		startTalk() {
			this.micEnabled = true;
			this.isListening = true;
			this.callStatus = 'listening';
			this.userText = '';
			
			// 发送PTT开始信号
			if (this.websocket) {
				this.websocket.send({
					data: 'ptt_on'
				});
			}
			
			// #ifndef H5
			if (this.recorderManager) {
				this.recorderManager.start({
					format: 'pcm',
					sampleRate: 16000,
					numberOfChannels: 1,
					encodeBitRate: 48000,
					frameSize: 5
				});
			}
			// #endif
		},
		
		stopTalk() {
			this.micEnabled = false;
			this.isListening = false;
			this.callStatus = 'connected';
			
			// 停止录音（会触发 onStop 回调，在那里发送音频和 ptt_off）
			// #ifndef H5
			if (this.recorderManager) {
				this.recorderManager.stop();
			}
			// #endif
		},
		
		playAudio(audioData) {
			// 播放接收到的音频数据
			// 注意：实际实现需要处理音频格式转换
			console.log('播放音频', audioData);
		},
		
		// 分片发送音频数据（按照官方推荐参数）
		async sendAudioInChunks(audioData) {
			// 官方推荐：每包3200字节（约100ms音频），延迟100ms
			// PCM 16kHz 单声道：16000 * 2 * 0.1 = 3200 bytes/100ms
			const chunkSize = 3200; // 3.2KB per chunk（官方推荐）
			const chunkDelay = 100; // 100ms（官方推荐）
			
			// 确保 audioData 是 ArrayBuffer
			if (!(audioData instanceof ArrayBuffer)) {
				console.error('❌ audioData 不是 ArrayBuffer，类型:', typeof audioData);
				uni.showToast({
					title: '音频数据格式错误',
					icon: 'none'
				});
				return;
			}
			
			const totalSize = audioData.byteLength;
			let offset = 0;
			let chunkCount = 0;
			
			console.log('📦 开始分片发送（官方推荐参数）');
			console.log('📊 总大小:', totalSize, 'bytes');
			console.log('📊 每片大小:', chunkSize, 'bytes');
			console.log('📊 发送间隔:', chunkDelay, 'ms');
			console.log('📊 预计录音时长:', (totalSize / 32000).toFixed(2), '秒');
			
			// 显示加载提示
			uni.showLoading({
				title: '发送中...',
				mask: true
			});
			
			// 使用 Promise 确保顺序发送
			const sendChunk = (chunk, index) => {
				return new Promise((resolve, reject) => {
					console.log(`📤 发送第 ${index} 片，大小: ${chunk.byteLength} bytes`);
					
					this.websocket.send({
						data: chunk,
						success: () => {
							console.log(`✅ 第 ${index} 片发送成功`);
							resolve();
						},
						fail: (err) => {
							console.error(`❌ 第 ${index} 片发送失败:`, err);
							reject(err);
						}
					});
				});
			};
			
			try {
				// 顺序发送所有片段
				while (offset < totalSize) {
					const end = Math.min(offset + chunkSize, totalSize);
					const chunk = audioData.slice(offset, end);
					chunkCount++;
					
					await sendChunk(chunk, chunkCount);
					
					offset = end;
					
					// 延迟，模拟实时流
					if (offset < totalSize) {
						await new Promise(resolve => setTimeout(resolve, chunkDelay));
					}
				}
				
				console.log('✅ 所有音频片段发送完成，共', chunkCount, '片');
				
				// 发送 ptt_off 信号，告诉服务器录音结束
				this.websocket.send({
					data: 'ptt_off',
					success: () => {
						console.log('✅ ptt_off 信号发送成功');
					}
				});
				
				uni.hideLoading();
				
			} catch (err) {
				console.error('❌ 发送音频失败:', err);
				uni.hideLoading();
				uni.showToast({
					title: '发送失败',
					icon: 'none'
				});
			}
		},
		
		endCall() {
			this.cleanup();
			uni.navigateBack();
		},
		
		cleanup() {
			if (this.websocket) {
				this.websocket.close();
				this.websocket = null;
			}
			if (this.recorderManager) {
				this.recorderManager.stop();
			}
			if (this.audioContext) {
				this.audioContext.stop();
				this.audioContext.destroy();
			}
		}
	}
};
</script>

<style scoped>
.voice-call-container {
	width: 100vw;
	height: 100vh;
	background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
	display: flex;
	flex-direction: column;
	align-items: center;
	position: relative;
}

.back-btn {
	position: absolute;
	top: 60rpx;
	left: 30rpx;
	width: 60rpx;
	height: 60rpx;
	z-index: 10;
}

.back-btn image {
	width: 100%;
	height: 100%;
	filter: brightness(0) invert(1);
}

.lover-avatar-container {
	margin-top: 150rpx;
	display: flex;
	flex-direction: column;
	align-items: center;
	position: relative;
}

.lover-avatar {
	width: 400rpx;
	height: 400rpx;
	border-radius: 50%;
	border: 8rpx solid rgba(255, 255, 255, 0.3);
	transition: all 0.3s ease;
}

.lover-avatar.speaking {
	transform: scale(1.05);
	border-color: rgba(255, 255, 255, 0.8);
	box-shadow: 0 0 40rpx rgba(255, 255, 255, 0.6);
}

.lover-avatar.listening {
	border-color: rgba(102, 126, 234, 0.8);
	box-shadow: 0 0 40rpx rgba(102, 126, 234, 0.6);
}

.status-indicator {
	margin-top: 40rpx;
	display: flex;
	align-items: center;
	gap: 15rpx;
}

.status-dot {
	width: 20rpx;
	height: 20rpx;
	border-radius: 50%;
	background: #fff;
}

.status-dot.connecting {
	animation: pulse 1.5s ease-in-out infinite;
}

.status-dot.connected {
	background: #4ade80;
}

.status-dot.speaking {
	background: #f59e0b;
	animation: pulse 0.8s ease-in-out infinite;
}

.status-dot.listening {
	background: #3b82f6;
	animation: pulse 1s ease-in-out infinite;
}

.status-text {
	color: #fff;
	font-size: 28rpx;
}

.audio-wave {
	display: flex;
	align-items: center;
	gap: 10rpx;
	margin-top: 30rpx;
	height: 80rpx;
}

.wave-bar {
	width: 8rpx;
	background: rgba(255, 255, 255, 0.8);
	border-radius: 4rpx;
	animation: wave 1s ease-in-out infinite;
}

.wave-bar:nth-child(1) { animation-delay: 0s; }
.wave-bar:nth-child(2) { animation-delay: 0.1s; }
.wave-bar:nth-child(3) { animation-delay: 0.2s; }
.wave-bar:nth-child(4) { animation-delay: 0.3s; }
.wave-bar:nth-child(5) { animation-delay: 0.4s; }

@keyframes wave {
	0%, 100% { height: 20rpx; }
	50% { height: 80rpx; }
}

@keyframes pulse {
	0%, 100% { opacity: 1; transform: scale(1); }
	50% { opacity: 0.5; transform: scale(1.2); }
}

.conversation-text {
	flex: 1;
	width: 90%;
	margin-top: 60rpx;
	display: flex;
	flex-direction: column;
	gap: 20rpx;
	overflow-y: auto;
}

.text-bubble {
	padding: 20rpx 30rpx;
	border-radius: 20rpx;
	max-width: 80%;
	word-wrap: break-word;
}

.text-bubble.user {
	align-self: flex-end;
	background: rgba(255, 255, 255, 0.9);
	color: #333;
}

.text-bubble.ai {
	align-self: flex-start;
	background: rgba(255, 255, 255, 0.2);
	color: #fff;
	backdrop-filter: blur(10rpx);
}

.control-buttons {
	width: 100%;
	padding: 40rpx;
	display: flex;
	justify-content: space-around;
	align-items: center;
	gap: 40rpx;
}

.control-btn {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 15rpx;
}

.control-btn image {
	width: 120rpx;
	height: 120rpx;
	padding: 30rpx;
	background: rgba(255, 255, 255, 0.2);
	border-radius: 50%;
	backdrop-filter: blur(10rpx);
	transition: all 0.3s ease;
}

.control-btn:active image {
	transform: scale(0.95);
	background: rgba(255, 255, 255, 0.3);
}

.control-btn.end-call image {
	background: rgba(239, 68, 68, 0.8);
}

.control-btn text {
	color: #fff;
	font-size: 24rpx;
}
</style>
