<template>
	<view class="page" :class="{ big: isH5 }">
		<view class="panel">
			<view class="section-title">模拟识别</view>
			<input class="input" v-model="simulateText" placeholder="输入模拟识别文本，例如：打开预警中心 / 去监区看板 / 打开个体画像" />
			<view class="chips">
				<view class="chip" v-for="t in quickTexts" :key="t" @click="useQuickText(t)">{{ t }}</view>
			</view>
			<view class="actions single">
				<button class="btn full" type="primary" :disabled="!simulateText || loading" @click="onSimulate">模拟识别并跳转</button>
			</view>
			<view v-if="errorMsg" class="error">{{ errorMsg }}</view>
		</view>

		<view class="panel">
			<view class="section-title">识别文本</view>
			<view class="text-box" :class="{ empty: !recognizedText }">
				<text v-if="recognizedText">{{ recognizedText }}</text>
				<text v-else>暂无识别结果</text>
			</view>
			<view v-if="errorMsg" class="error">{{ errorMsg }}</view>

			<view class="actions">
				<button class="btn" type="primary" :disabled="!recognizedText || loading" @click="onExecute">执行</button>
				<button class="btn" :disabled="recording || loading" @click="onClear">清空</button>
			</view>
		</view>

		<view class="record-wrap">
			<view class="status">{{ recording ? '录音中…' : '按住说话' }}</view>
			<view class="record-btn"
				:class="{ recording: recording }"
				@touchstart="startRecord"
				@touchend="stopRecord"
				@touchcancel="stopRecord">
				<text class="record-btn-text">{{ loading ? '识别中…' : (recording ? '松开结束' : '按住说话') }}</text>
			</view>
		</view>

		<view class="panel">
			<view class="section-title">执行结果</view>
			<view class="text-box" :class="{ empty: !commandResult }">
				<text v-if="commandResult">{{ commandResult }}</text>
				<text v-else>暂无</text>
			</view>
		</view>
	</view>
</template>

<script>
	import { request, uploadFile } from '../../utils/request'

	const TEMPLATE_EXPIRE_MS = 30 * 1000

	const SCENE_TEMPLATES = [
		{
			id: 'morning_brief',
			name: '早会汇报模板',
			triggers: ['调用早会汇报模板', '打开早会汇报模板', '早会汇报模板'],
			options: [
				{ label: '1. 汇报昨日预警情况', action: { type: 'voice_command', text: '打开预警中心' } },
				{ label: '2. 展示本周测评完成率', action: { type: 'navigate', url: '/pages/chart/templates' } }
			]
		},
		{
			id: 'duty_patrol',
			name: '值班巡查模板',
			triggers: ['调用值班巡查模板', '打开值班巡查模板', '值班巡查模板', '值班巡查'],
			options: [
				{ label: '1. 打开监区看板', action: { type: 'navigate', url: '/pages/index/index' } },
				{ label: '2. 查看预警中心', action: { type: 'voice_command', text: '打开预警中心' } }
			]
		}
	]

	function normalizeText(text) {
		return String(text || '').trim()
	}

	function parseSelection(text) {
		const s = normalizeText(text)
		const m1 = s.match(/^(?:选|选择)?\s*(\d{1,2})\s*(?:项|号)?$/)
		if (m1 && m1[1]) return parseInt(m1[1], 10)
		const map = { '一': 1, '二': 2, '三': 3, '四': 4, '五': 5, '六': 6, '七': 7, '八': 8, '九': 9, '十': 10 }
		const m2 = s.match(/^(?:选|选择)?\s*([一二三四五六七八九十])\s*(?:项|号)?$/)
		if (m2 && m2[1] && map[m2[1]]) return map[m2[1]]
		return null
	}

	export default {
		data() {
			return {
				isH5: false,
				recording: false,
				loading: false,
				autoStart: false,
				simulateText: '',
				quickTexts: ['打开预警中心', '去监区看板', '打开个体画像', '打开图表模板', '打开干预任务'],
				recognizedText: '',
				commandResult: '',
				errorMsg: '',
				audioPath: '',
				activeTemplateId: '',
				activeTemplateOptions: [],
				templateExpireAt: 0
			}
		},
		onLoad(options) {
			try {
				const info = uni.getSystemInfoSync()
				const p = info ? (info.uniPlatform || info.platform) : ''
				this.isH5 = p === 'web' || p === 'h5'
			} catch (e) {
				this.isH5 = false
			}
			this.autoStart = !!(options && (options.autostart === '1' || options.autostart === 1 || options.autostart === 'true'))
			this.recorder = uni.getRecorderManager()
			this.recorder.onStop((res) => {
				this.onRecorderStop(res)
			})
			this.recorder.onError((err) => {
				this.loading = false
				this.recording = false
				this.errorMsg = (err && err.errMsg) ? err.errMsg : '录音失败'
			})

			if (this.autoStart) {
				setTimeout(() => {
					if (!this.recording && !this.loading) this.startRecord()
				}, 300)
			}
		},
		methods: {
			clearTemplateSession() {
				this.activeTemplateId = ''
				this.activeTemplateOptions = []
				this.templateExpireAt = 0
			},
			getActiveTemplate() {
				if (!this.activeTemplateId) return null
				const now = Date.now()
				if (!this.templateExpireAt || now > this.templateExpireAt) {
					this.clearTemplateSession()
					return null
				}
				for (let i = 0; i < SCENE_TEMPLATES.length; i++) {
					if (SCENE_TEMPLATES[i].id === this.activeTemplateId) return SCENE_TEMPLATES[i]
				}
				return null
			},
			findTemplateByText(text) {
				const s = normalizeText(text)
				if (!s) return null
				for (let i = 0; i < SCENE_TEMPLATES.length; i++) {
					const t = SCENE_TEMPLATES[i]
					const triggers = t && t.triggers ? t.triggers : []
					for (let j = 0; j < triggers.length; j++) {
						if (s.includes(triggers[j])) return t
					}
				}
				return null
			},
			openTemplateMenu(tpl) {
				if (!tpl || !tpl.options || !tpl.options.length) return
				this.activeTemplateId = tpl.id
				this.activeTemplateOptions = tpl.options
				this.templateExpireAt = Date.now() + TEMPLATE_EXPIRE_MS
				this.commandResult = `已进入${tpl.name}，请说“选1/选2”…（${Math.floor(TEMPLATE_EXPIRE_MS / 1000)}秒内有效）`

				uni.showActionSheet({
					itemList: tpl.options.map(o => o.label),
					success: (res) => {
						const idx = (res && typeof res.tapIndex === 'number') ? res.tapIndex + 1 : null
						if (!idx) return
						this.executeTemplateSelection(idx)
					}
				})
			},
			executeVoiceCommandText(text) {
				return request({
					url: '/voice/command',
					method: 'POST',
					data: { text }
				})
			},
			executeTemplateSelection(selIndex) {
				const tpl = this.getActiveTemplate()
				if (!tpl) {
					this.commandResult = '模板已失效，请重新说“调用XX模板”'
					return Promise.resolve()
				}
				const opt = this.activeTemplateOptions[selIndex - 1]
				if (!opt) {
					this.commandResult = `未找到选项${selIndex}，请重试`
					return Promise.resolve()
				}
				this.clearTemplateSession()
				if (opt.action && opt.action.type === 'navigate' && opt.action.url) {
					uni.navigateTo({ url: opt.action.url })
					this.commandResult = '已跳转：' + opt.action.url
					return Promise.resolve()
				}
				if (opt.action && opt.action.type === 'voice_command' && opt.action.text) {
					this.loading = true
					return this.executeVoiceCommandText(opt.action.text).then((res) => {
						this.loading = false
						return this.handleCommandResponse(res)
					}).catch((e) => {
						this.loading = false
						this.errorMsg = e && e.message ? e.message : '网络错误'
					})
				}
				this.commandResult = opt.label
				return Promise.resolve()
			},
			handleCommandResponse(res) {
				const data = res && res.data ? res.data : null
				if (!data || data.code !== 200) {
					this.errorMsg = (data && data.msg) ? data.msg : '执行失败'
					return
				}
				const type = data.type
				const payload = data.payload || {}
				if (type === 'analysis') {
					this.commandResult = payload.result || '暂无分析结果'
					return
				}
				if (type === 'navigate' && payload.url) {
					uni.navigateTo({ url: payload.url })
					this.commandResult = '已跳转：' + payload.url
					return
				}
				if (type === 'ask_clarify') {
					this.commandResult = payload.message || '需要澄清指令'
					return
				}
				this.commandResult = JSON.stringify(data, null, 2)
			},
			executeAnalyzeText(text) {
				return request({
					url: '/voice/analyze',
					method: 'POST',
					data: { text }
				})
			},
			matchAnalyze(text) {
				const s = normalizeText(text)
				if (!s) return null
				const m = s.match(/^分析\s*([\s\S]{1,64}?)(?:数据)?$/)
				if (!m) return null
				const topic = normalizeText(m[1])
				return { topic: topic || '相关' }
			},
			tryHandleSceneTemplate(text) {
				const s = normalizeText(text)
				if (!s) return false

				// 1) 识别到模板唤起
				const tpl = this.findTemplateByText(s)
				if (tpl) {
					this.openTemplateMenu(tpl)
					return true
				}

				// 2) 识别到“选1/选2”
				const sel = parseSelection(s)
				if (sel != null) {
					const activeTpl = this.getActiveTemplate()
					if (activeTpl) {
						this.executeTemplateSelection(sel)
						return true
					}
				}

				// 3) 识别到“分析xx数据”
				const analyze = this.matchAnalyze(s)
				if (analyze) {
					this.loading = true
					this.executeAnalyzeText(s).then((res) => {
						this.loading = false
						this.handleCommandResponse(res)
					}).catch((e) => {
						this.loading = false
						this.errorMsg = e && e.message ? e.message : '网络错误'
					})
					return true
				}

				return false
			},
			useQuickText(t) {
				this.simulateText = t
			},
			onSimulate() {
				this.errorMsg = ''
				this.commandResult = ''
				const text = (this.simulateText || '').trim()
				if (!text) return
				this.recognizedText = text
				const analyze = this.matchAnalyze(text)
				if (analyze) {
					this.loading = true
					this.executeAnalyzeText(text).then((res) => {
						this.loading = false
						this.handleCommandResponse(res)
					}).catch((e) => {
						this.loading = false
						this.errorMsg = e && e.message ? e.message : '网络错误'
					})
					return
				}
				if (this.tryHandleSceneTemplate(text)) return
				const match = this.matchNavigate(text)
				if (!match) {
					this.commandResult = '未匹配到跳转：' + text
					return
				}
				uni.navigateTo({ url: match.url })
				this.commandResult = '已跳转：' + match.name
			},
			matchNavigate(text) {
				const s = String(text || '').toLowerCase()
				const reportQueryMatch = String(text || '').match(/查询\s*([^\s的]{1,32})\s*的?报告/)
				if (reportQueryMatch && reportQueryMatch[1]) {
					const keyword = String(reportQueryMatch[1]).trim()
					return { name: '报告列表', url: '/pages/report/index?keyword=' + encodeURIComponent(keyword) }
				}
				const rules = [
					{ name: '预警中心', url: '/pages/warning/index', keys: ['预警', '风险', '告警', '预警中心'] },
					{ name: '监区看板', url: '/pages/index/index', keys: ['看板', '监区', 'dashboard'] },
					{ name: '个体画像', url: '/pages/profile/index', keys: ['画像', '个体', '人员', '档案', 'profile'] },
					{ name: '图表模板', url: '/pages/chart/templates', keys: ['图表模板', '模板', '图表', 'charts'] },
					{ name: '自定义图表', url: '/pages/chart/custom', keys: ['自定义图表', '自定义', 'custom'] },
					{ name: '干预任务', url: '/pages/interventionTask/index', keys: ['干预', '任务', 'intervention'] },
					{ name: '测评列表', url: '/pages/assessment/index', keys: ['测评', '量表', 'assessment'] },
					{ name: '报告列表', url: '/pages/report/index', keys: ['报告', 'report'] },
					{ name: '综合报告', url: '/pages/comprehensive/index', keys: ['综合报告', '综合', 'comprehensive'] }
				]
				for (let i = 0; i < rules.length; i++) {
					const r = rules[i]
					if (!r || !r.keys) continue
					for (let j = 0; j < r.keys.length; j++) {
						const k = String(r.keys[j]).toLowerCase()
						if (k && s.includes(k)) return { name: r.name, url: r.url }
					}
				}
				return null
			},
			startRecord() {
				if (this.loading) return
				this.errorMsg = ''
				this.commandResult = ''
				this.recording = true
				this.recognizedText = ''
				this.audioPath = ''
				this.recorder.start({
					duration: 60000,
					sampleRate: 16000,
					numberOfChannels: 1,
					encodeBitRate: 96000,
					format: 'mp3'
				})
			},
			stopRecord() {
				if (!this.recording) return
				this.recording = false
				this.loading = true
				this.recorder.stop()
			},
			onRecorderStop(res) {
				if (!res || !res.tempFilePath) {
					this.loading = false
					this.errorMsg = '未获取到录音文件'
					return
				}
				this.uploadAndAsr(res.tempFilePath)
			},
			onExecute() {
				this.errorMsg = ''
				if (this.tryHandleSceneTemplate(this.recognizedText)) return
				const analyze = this.matchAnalyze(this.recognizedText)
				if (analyze) {
					this.loading = true
					this.executeAnalyzeText(this.recognizedText).then((res) => {
						this.loading = false
						this.handleCommandResponse(res)
					}).catch((e) => {
						this.loading = false
						this.errorMsg = e && e.message ? e.message : '网络错误'
					})
					return
				}
				this.loading = true
				this.executeVoiceCommandText(this.recognizedText).then((res) => {
					this.loading = false
					this.handleCommandResponse(res)
				}).catch((e) => {
					this.loading = false
					this.errorMsg = e && e.message ? e.message : '网络错误'
				})
			},
			onClear() {
				this.simulateText = ''
				this.recognizedText = ''
				this.commandResult = ''
				this.errorMsg = ''
				this.audioPath = ''
				this.clearTemplateSession()
			},
			uploadAndAsr(tempFilePath) {
				uploadFile({
					url: '/voice/asr',
					filePath: tempFilePath,
					name: 'file',
					formData: { language: 'zh' }
				}).then((res) => {
					this.loading = false
					let data = null
					try {
						data = JSON.parse(res.data)
					} catch (e) {
						this.errorMsg = '服务返回格式错误'
						return
					}
					if (!data || data.code !== 200) {
						this.errorMsg = (data && data.msg) ? data.msg : '识别失败'
						return
					}
					this.recognizedText = data.text || ''
					this.audioPath = data.audioPath || ''
					if (!this.recognizedText) {
						this.errorMsg = '未识别到有效文本'
					}
				}).catch((e) => {
					this.loading = false
					this.errorMsg = e && e.message ? e.message : '上传失败'
				})
			}
		}
	}
</script>

<style>
	.page {
		min-height: 100vh;
		padding: 24rpx 24rpx 120rpx;
		box-sizing: border-box;
		background: #F4F6FB;
	}
	.page.big {
		min-height: 100vh;
		padding: 14rpx 14rpx 120rpx;
		box-sizing: border-box;
		position: relative;
		overflow: hidden;
		--neon-a: rgba(0, 240, 255, 0.95);
		--neon-b: rgba(60, 140, 255, 0.95);
		--neon-soft: rgba(0, 240, 255, 0.18);
		--glass: rgba(7, 13, 28, 0.42);
		--glass-2: rgba(10, 18, 38, 0.52);
		background-image:
			radial-gradient(1100rpx 520rpx at 50% 14%, rgba(43, 107, 255, 0.30) 0%, rgba(6, 16, 40, 0.0) 65%),
			linear-gradient(180deg, rgba(5, 11, 24, 0.90) 0%, rgba(8, 20, 45, 0.85) 42%, rgba(6, 16, 40, 0.92) 100%),
			url('/static/bg.png');
		background-size: auto, auto, cover;
		background-position: center, center, center;
		background-repeat: no-repeat, no-repeat, no-repeat;
		color: rgba(242, 252, 255, 0.96);
		font-size: 24rpx;
		line-height: 1.5;
		text-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.55);
	}
	.page.big:before {
		content: none;
	}

	.panel {
		background: rgba(255, 255, 255, 0.95);
		border-radius: 18rpx;
		padding: 24rpx;
		border: 1px solid rgba(15, 23, 42, 0.06);
		box-shadow: 0 10rpx 22rpx rgba(15, 23, 42, 0.05);
		margin-bottom: 18rpx;
	}
	.page.big .panel {
		position: relative;
		z-index: 1;
		border-radius: 18rpx;
		padding: 26rpx 26rpx 22rpx;
		border: 1px solid rgba(0, 240, 255, 0.16);
		background-image:
			linear-gradient(135deg, rgba(0, 240, 255, 0.08) 0%, rgba(60, 140, 255, 0.05) 35%, rgba(165, 90, 255, 0.06) 100%),
			linear-gradient(180deg, rgba(7, 13, 28, 0.72) 0%, rgba(7, 13, 28, 0.56) 100%);
		background-repeat: no-repeat;
		background-size: cover;
		backdrop-filter: blur(6px);
		box-shadow: 0 14rpx 26rpx rgba(0, 0, 0, 0.42);
	}

	.section-title {
		font-size: 28rpx;
		font-weight: 700;
		color: #111827;
		margin-bottom: 16rpx;
	}
	.page.big .section-title {
		color: rgba(242, 252, 255, 0.94);
		font-weight: 900;
		letter-spacing: 1rpx;
		text-shadow: 0 0 16rpx rgba(0, 240, 255, 0.16);
	}

	.text-box {
		min-height: 120rpx;
		border-radius: 16rpx;
		padding: 18rpx;
		box-sizing: border-box;
		background: rgba(15, 23, 42, 0.04);
		color: #111827;
		font-size: 26rpx;
		line-height: 40rpx;
		border: 1px solid rgba(15, 23, 42, 0.06);
	}
	.page.big .text-box {
		background: rgba(7, 13, 28, 0.55);
		color: rgba(242, 252, 255, 0.92);
		border: 1px solid rgba(116, 216, 255, 0.14);
	}

	.text-box.empty {
		color: #94A3B8;
	}
	.page.big .text-box.empty {
		color: rgba(242, 252, 255, 0.62);
	}

	.error {
		margin-top: 14rpx;
		font-size: 24rpx;
		color: #ff4d4f;
		line-height: 36rpx;
	}

	.actions {
		margin-top: 18rpx;
		display: flex;
		justify-content: space-between;
		gap: 14rpx;
	}

	.actions.single {
		justify-content: flex-start;
	}

	.btn {
		width: 48%;
		border-radius: 16rpx;
	}
	.page.big .btn {
		border-radius: 14rpx;
	}

	.btn.full {
		width: 100%;
	}

	.input {
		width: 100%;
		background: rgba(15, 23, 42, 0.04);
		border-radius: 16rpx;
		padding: 22rpx 20rpx;
		font-size: 28rpx;
		box-sizing: border-box;
		border: 1px solid rgba(15, 23, 42, 0.06);
		min-height: 92rpx;
		line-height: 92rpx;
	}
	.page.big .input {
		background: rgba(7, 13, 28, 0.78);
		border-radius: 14rpx;
		border: 1px solid rgba(116, 216, 255, 0.18);
		color: rgba(242, 252, 255, 0.92);
	}

	.chips {
		display: flex;
		flex-wrap: wrap;
		margin-top: 14rpx;
		gap: 14rpx;
	}

	.chip {
		padding: 12rpx 18rpx;
		border-radius: 999rpx;
		font-size: 24rpx;
		color: #64748B;
		background: rgba(15, 23, 42, 0.04);
		border: 1px solid rgba(15, 23, 42, 0.06);
	}
	.page.big .chip {
		color: rgba(242, 252, 255, 0.82);
		background: rgba(7, 13, 28, 0.55);
		border: 1px solid rgba(0, 240, 255, 0.16);
		box-shadow: 0 0 16rpx rgba(0, 166, 255, 0.08);
	}

	.record-wrap {
		align-items: center;
		display: flex;
		flex-direction: column;
		margin: 30rpx 0 24rpx;
	}

	.status {
		font-size: 24rpx;
		color: #94A3B8;
		margin-bottom: 18rpx;
	}
	.page.big .status {
		color: rgba(242, 252, 255, 0.72);
	}

	.record-btn {
		width: 420rpx;
		height: 420rpx;
		border-radius: 210rpx;
		display: flex;
		align-items: center;
		justify-content: center;
		background: #1677ff;
		box-shadow: 0 18rpx 40rpx rgba(22, 119, 255, 0.22);
	}
	.page.big .record-btn {
		border: 1px solid rgba(0, 240, 255, 0.22);
		background: radial-gradient(circle at 30% 30%, rgba(0, 240, 255, 0.22) 0%, rgba(7, 13, 28, 0.82) 60%, rgba(2, 8, 22, 0.92) 100%);
		box-shadow: 0 0 26rpx rgba(0, 240, 255, 0.14), 0 18rpx 40rpx rgba(0, 0, 0, 0.45);
	}

	.record-btn.recording {
		background: #F56C6C;
		box-shadow: 0 18rpx 40rpx rgba(245, 108, 108, 0.22);
	}
	.page.big .record-btn.recording {
		border-color: rgba(255, 72, 92, 0.35);
		background: radial-gradient(circle at 30% 30%, rgba(255, 72, 92, 0.22) 0%, rgba(7, 13, 28, 0.82) 60%, rgba(2, 8, 22, 0.92) 100%);
		box-shadow: 0 0 26rpx rgba(255, 72, 92, 0.14), 0 18rpx 40rpx rgba(0, 0, 0, 0.45);
	}

	.record-btn-text {
		color: #ffffff;
		font-size: 30rpx;
		font-weight: 700;
	}


</style>
