<template>
	<view class="add-program-container ">
		<!-- Hidden canvas for text measurement -->
		<canvas canvas-id="__temp_prepare_canvas"
			style="width: 0; height: 0; position: absolute; left: -9999px; top: -9999px;"></canvas>

		<!-- 画面预览（悬浮顶部） -->
		<view class="section preview-section">
			<view class="section-title blue">画面预览</view>
			<canvas class="preview-canvas" canvas-id="previewCanvas"></canvas>
		</view>


		<!-- 节目参数 -->
		<view class="zone-card">
			<view class="zone-title">节目参数</view>
			<view class="form-row">
				<view class="mini-label">模式</view>
				<view class="picker" style="margin-left: 90px;" @click="showModePicker = true">{{ modes[form.mode] }}
				</view>
				<u-picker :show="showModePicker" :columns="[modes]" @confirm="onModeConfirm"
					@cancel="showModePicker = false"></u-picker>
			</view>
			<view class="form-row">
				<view class="mini-label">时长</view>
				<u-input v-model="form.duration" type="number" placeholder="请输入节目时长"
					style="max-width:110px; margin-left: 60px;" />
				<view style="line-height: 36px; margin-right: 14px; color: #666;">秒</view>
			</view>
		</view>

		<!-- 分区1整体卡片 -->
		<view class="zone-card" v-for="(zone, index) in form.zones" :key="index">
			<view class="zone-title">分区{{ index + 1 }}</view>

			<!-- 项目选择卡片 -->
			<view class="group-card">
				<view class="group-title">项目选择</view>
				<view class="form-row ">
					<view class="form-label">播放类型</view>
					<view class="picker" @click="openPicker('showPlayTypePicker', index)">{{ playTypes[zone.playType] }}
					</view>
					<u-picker :show="showPlayTypePicker" :columns="[playTypes]" @confirm="onPlayTypeConfirm"
						@cancel="showPlayTypePicker = false"></u-picker>
				</view>
			</view>

			<!-- 文字参数卡片，仅文字类型显示 -->
			<view class="group-card" v-if="zone.playType == 0">
				<view class="group-title">文字参数</view>
				<view class="form-row">
					<view class="form-label">常用语句</view>
					<view class="picker" @click="openPicker('showPhrasePicker', index)">
						{{ commonPhrases[zone.commonPhrase] || '常用语句' }}
					</view>
					<u-picker :show="showPhrasePicker" :columns="[commonPhrases]" @confirm="onPhraseConfirm"
						@cancel="showPhrasePicker = false"></u-picker>
				</view>
				<view class="form-row">
					<u-input v-model="zone.displayText" type="textarea" placeholder="请输入展示信息" class="input-area" />
				</view>
				<view class="form-row">
					<view class="mini-label">字体</view>
					<view class="picker" @click="openPicker('showFontPicker', index)">{{ fonts[zone.font] }}</view>
					<u-picker :show="showFontPicker" :columns="[fonts]" @confirm="onFontConfirm"
						@cancel="showFontPicker = false"></u-picker>
				</view>
				<view class="form-row">
					<view class="mini-label">圆角</view>
					<view class="picker" @click="openPicker('showFontShapePicker', index)">
						{{ fontShapes[zone.fontShape] }}
					</view>
					<u-picker :show="showFontShapePicker" :columns="[fontShapes]" @confirm="onFontShapeConfirm"
						@cancel="showFontShapePicker = false"></u-picker>
				</view>
				<view class="form-row">
					<view class="mini-label">字号</view>
					<view class="picker" @click="openPicker('showFontSizePicker', index)">{{ fontSizes[zone.fontSize] }}
					</view>
					<u-picker :show="showFontSizePicker" :columns="[fontSizes]" @confirm="onFontSizeConfirm"
						@cancel="showFontSizePicker = false"></u-picker>
				</view>
				<view class="form-row">
					<view class="mini-label">颜色</view>
					<view class="picker" @click="openPicker('showFontColorPicker', index)">
						{{ fontColors[zone.fontColor] }}
					</view>
					<u-picker :show="showFontColorPicker" :columns="[fontColors]" @confirm="onFontColorConfirm"
						@cancel="showFontColorPicker = false"></u-picker>
				</view>
				<view class="form-row">
					<view class="mini-label">加粗</view>
					<view class="picker" @click="openPicker('showFontBoldPicker', index)">{{ fontBold[zone.fontBold] }}
					</view>
					<u-picker :show="showFontBoldPicker" :columns="[fontBold]" @confirm="onFontBoldConfirm"
						@cancel="showFontBoldPicker = false"></u-picker>
				</view>
				<view class="form-row">
					<view class="mini-label">拉伸</view>
					<view class="picker" @click="openPicker('showFontStretchPicker', index)">
						{{ fontStretch[zone.fontStretch] }}
					</view>
					<u-picker :show="showFontStretchPicker" :columns="[fontStretch]" @confirm="onFontStretchConfirm"
						@cancel="showFontStretchPicker = false"></u-picker>
				</view>
			</view>

			<!-- 图片参数卡片，仅图片类型显示 -->
			<view class="group-card" v-else>
				<view class="group-title">图片参数</view>
				<view class="form-row">
					<view class="picker" @click="openPicker('showImagePicker', index)">
						{{ zone.image ? zone.image : '请选择图片' }}
					</view>
					<u-picker
						:show="showImagePicker"
						:columns="[imageFiles]"
						@confirm="onImageConfirm"
						@cancel="showImagePicker = false"
					/>
				</view>
				<view class="form-row">
					<view class="mini-label">尺寸</view>
					<view class="picker" @click="openPicker('showImageSizePicker', index)">
						{{ imageSizes[zone.imageSize] }}
					</view>
					<u-picker :show="showImageSizePicker" :columns="[imageSizes]" @confirm="onImageSizeConfirm" @cancel="showImageSizePicker = false" />
				</view>
				<view class="form-row">
					<view class="mini-label">颜色</view>
					<view class="picker" @click="openPicker('showImageColorPicker', index)">
						{{ fontColors[zone.imageColor] }}
					</view>
					<u-picker :show="showImageColorPicker" :columns="[fontColors]" @confirm="onImageColorConfirm" @cancel="showImageColorPicker = false" />
				</view>
			</view>

			<!-- 显示参数卡片 -->
			<view class="group-card">
				<view class="group-title">显示参数</view>
				<view class="form-row">
					<view class="form-label">动画特效</view>
					<view class="picker" @click="openPicker('showEffectPicker', index)">
						{{ effects[zone.effect] || '动画特效' }}
					</view>
					<u-picker :show="showEffectPicker" :columns="[effects]" @confirm="onEffectConfirm"
						@cancel="showEffectPicker = false"></u-picker>
				</view>
				<view class="form-row">
					<view class="form-label">速度</view>
					<view class="picker" @click="openPicker('showSpeedPicker', index)">{{ speeds[zone.speed] || '速度' }}
					</view>
					<u-picker :show="showSpeedPicker" :columns="[speeds]" @confirm="onSpeedConfirm"
						@cancel="showSpeedPicker = false"></u-picker>
				</view>
				<view class="form-row">
					<view class="form-label">停留时间</view>
					<view class="picker" @click="openPicker('showStayTimePicker', index)">
						{{ stayTimes[zone.stayTime] || '停留时间' }}
					</view>
					<u-picker :show="showStayTimePicker" :columns="[stayTimes]" @confirm="onStayTimeConfirm"
						@cancel="showStayTimePicker = false"></u-picker>
				</view>
				<view class="form-row">
					<view class="form-label">水平对齐</view>
					<view class="picker" @click="openPicker('showHAlignPicker', index)">
						{{ horizontalAlign[zone.hAlign] || '水平对齐' }}
					</view>
					<u-picker :show="showHAlignPicker" :columns="[horizontalAlign]" @confirm="onHAlignConfirm"
						@cancel="showHAlignPicker = false"></u-picker>
				</view>
				<view class="form-row">
					<view class="form-label">垂直对齐</view>
					<view class="picker" @click="openPicker('showVAlignPicker', index)">
						{{ verticalAlign[zone.vAlign] || '垂直对齐' }}
					</view>
					<u-picker :show="showVAlignPicker" :columns="[verticalAlign]" @confirm="onVAlignConfirm"
						@cancel="showVAlignPicker = false"></u-picker>
				</view>
			</view>

			<!-- 高级参数卡片 -->
			<view class="group-card">
				<view class="group-title">高级参数</view>
				<view class="form-row">
					<view class="mini-label">X</view>
					<u-input v-model="zone.x" placeholder="0" />
					<view class="unit-label">PX</view>
				</view>
				<view class="form-row">
					<view class="mini-label">宽</view>
					<u-input v-model="zone.width" placeholder="32" />
					<view class="unit-label">PX</view>
				</view>
				<view class="form-row">
					<view class="mini-label">Y</view>
					<u-input v-model="zone.y" placeholder="0" />
					<view class="unit-label">PX</view>
				</view>
				<view class="form-row">
					<view class="mini-label">高</view>
					<u-input v-model="zone.height" placeholder="64" />
					<view class="unit-label">PX</view>
				</view>
			</view>
		</view>

		<!-- 底部按钮 -->
		<view class="button-row">
			<u-button type="default" class="btn" @click="onRead">读取</u-button>
			<u-button type="primary" class="btn" @click="onSet">设置</u-button>
		</view>
	</view>
</template>

<script>
	export default {
		name: 'AddProgram',
		onLoad() {
			// 从本地存储获取设备信息
			const device = uni.getStorageSync('currentDevice');
			const deviceInfo = uni.getStorageSync('currentDeviceInfo');

			if (device) {
				this.device = device;
			}
			if (deviceInfo) {
				this.deviceInfo = deviceInfo;
			}
		},
		onReady() {
			this.$nextTick(() => {
				this.initializeAnimations();
			});
		},
		onUnload() {
			if (this.animationFrameId) {
				cancelAnimationFrame(this.animationFrameId);
			}
			// Clear any remaining timers
			this.animationStates.forEach(state => {
				if (state.standTimer) clearTimeout(state.standTimer);
				if (state.pageTimer) clearTimeout(state.pageTimer);
			});
		},
		data() {
			return {
				device: null,
				deviceInfo: null,
				screenWidth: 32,
				screenHeight: 64,
				// picker弹窗控制
				showModePicker: false,
				showPlayTypePicker: false,
				showPhrasePicker: false,
				showFontPicker: false,
				showFontShapePicker: false,
				showFontSizePicker: false,
				showFontColorPicker: false,
				showFontBoldPicker: false,
				showFontStretchPicker: false,
				showEffectPicker: false,
				showHAlignPicker: false,
				showVAlignPicker: false,
				showSpeedPicker: false,
				showStayTimePicker: false,
				showImagePicker: false,
				showImageColorPicker: false,
				showImageSizePicker: false,
				// 选项数组
				playTypes: ['文字', '图片'],
				modes: ['模式1', '模式2(上下)', '模式3(左右)', '模式1114(上中下)', '模式5', '模式6'],
				commonPhrases: [
					'自定义',
					"公安交警正在巡逻",
					"公安交警停车检查",
					"前方事故减速慢行",
					"警察临检请您配合",
					"交警临检请您配合",
					"《《《《《",
					"》》》》》",
					"禁止停车",
					"交通管制禁止通行",
					"公安检查靠边停车",
					"前方事故道路封闭",
					"禁止掉头",
					"雨雪天气注意安全",
					"大雾天气减速慢行",
					"靠右停车接受检查",
					"警察临检靠边停车"
				],
				fonts: ['宋体(中)', '黑体(中)', '楷体(中)'],
				fontShapes: ['圆角(英)', '直角(英)'],
				fontSizes: ['16px', '24px', '32px', '48px', '64px'],
				fontColors: ['红色', '绿色', '蓝色'],
				fontBold: ['不加粗', '加粗'],
				fontStretch: ['不拉伸', '横向拉伸', '纵向拉伸'],
				effects: ['立即显示', '左移', '右移', '上移', '下移', '连续左移', '闪烁换页'],
				speeds: ['1X', '2X', '3X', '4X', '5X'],
				stayTimes: ['不停顿', '100毫秒', '500毫秒', '1秒', '2秒', '3秒', '4秒', '5秒', '6秒', '8秒', '10秒'],
				horizontalAlign: ['居左对齐', '居中对齐', '居右对齐'],
				verticalAlign: ['顶部对齐', '居中对齐', '底部对齐'],
				imageFiles: [
					'上箭头',
					'两侧道路变窄',
					'停车',
					'减速慢行',
					'减速让行',
					'前方事故',
					'前方施工',
					'右下箭头',
					'右侧道路变窄',
					'右箭头',
					'向右',
					'向右转弯',
					'向左',
					'向左向右转弯',
					'向左转弯',
					'左下箭头',
					'左侧道路变窄',
					'左右两侧绕行',
					'左箭头',
					'掉头',
					'检查',
					'注意安全',
					'禁止临时停车',
					'禁止停车',
					'禁止停车停',
					'禁止右转',
					'禁止左转',
					'禁止掉头',
					'禁止驶入',
					'禁止鸣笛',
					'箭头向上',
					'箭头向下',
					'解除限速',
					'限速',
					'靠右行驶',
					'靠左行驶'
				],
				imageSizes: ['16x16', '32x32', '64x64'],
				form: {
					mode: 0,
					duration: '',
					zones: [{
						playType: 0, // 0: 文字, 1: 图片
						commonPhrase: 0,
						displayText: '',
						font: 0,
						fontShape: 0,
						fontSize: 0,
						fontColor: 0,
						fontBold: 0,
						fontStretch: 0,
						image: '', // 图片参数
						effect: 0,
						speed: 4, // Default to 5X
						stayTime: 5, // Default to 3秒
						hAlign: 0,
						vAlign: 0,
						x: 0,
						y: 0,
						width: 32,
						height: 64,
						imageColor: 0, // 新增，图片颜色索引
						imageSize: 1 // 新增，图片尺寸索引，默认32x32
					}]
				},
				currentZoneIndex: 0, // To track which zone's picker is open
				animationFrameId: null,
				animationStates: [],
				imageCache: {} // 图片本地路径缓存
			};
		},
		watch: {
			'form.zones': {
				handler() {
					// Use nextTick to ensure canvas is ready after DOM updates
					this.$nextTick(() => {
						this.initializeAnimations();
					});
				},
				deep: true
			}
		},
		methods: {
			getIndex(e) {
				if (e && e.indexs && e.indexs[0] !== undefined) return e.indexs[0];
				if (e && e.index && e.index[0] !== undefined) return e.index[0];
				if (Array.isArray(e)) return e[0];
				return 0;
			},
			onModeConfirm(e) {
				console.log('onModeConfirm', e, e.index, e.value);
				this.form.mode = this.getIndex(e);
				console.log('form.mode', this.form.mode);
				this.updateZones();
				this.drawCanvas();
				this.showModePicker = false;
			},
			updateZones() {
				const zoneCounts = [1, 2, 2, 3, 1, 1];
				const count = zoneCounts[this.form.mode] || 1;
				const newZones = [];
				const screenW = this.screenWidth;
				const screenH = this.screenHeight;

				for (let i = 0; i < count; i++) {
					const templateZone = {
						playType: 0,
						commonPhrase: 0,
						displayText: '',
						font: 0,
						fontShape: 0,
						fontSize: 0,
						fontColor: 0,
						fontBold: 0,
						fontStretch: 0,
						image: '',
						effect: 0,
						speed: 4,
						stayTime: 5,
						hAlign: 0,
						vAlign: 0,
						x: 0,
						y: 0,
						width: screenW,
						height: screenH
					};

					switch (this.form.mode) {
						case 1: // Mode 2 (上下)
							templateZone.height = Math.floor(screenH / count);
							templateZone.y = i * templateZone.height;
							// Last zone takes remaining height
							if (i === count - 1) {
								templateZone.height = screenH - templateZone.y;
							}
							break;
						case 2: // Mode 3 (左右)
							templateZone.width = Math.floor(screenW / count);
							templateZone.x = i * templateZone.width;
							// Last zone takes remaining width
							if (i === count - 1) {
								templateZone.width = screenW - templateZone.x;
							}
							break;
						case 3: // Mode 4 (上中下)
							templateZone.height = Math.floor(screenH / count);
							templateZone.y = i * templateZone.height;
							// Last zone takes remaining height
							if (i === count - 1) {
								templateZone.height = screenH - templateZone.y;
							}
							break;
					}

					// Try to keep user-edited data if a zone already exists, but update geometry
					if (this.form.zones[i]) {
						newZones.push({
							...this.form.zones[i],
							x: templateZone.x,
							y: templateZone.y,
							width: templateZone.width,
							height: templateZone.height
						});
					} else {
						newZones.push(templateZone);
					}
				}
				this.form.zones = newZones;
			},
			async initializeAnimations() {
				if (this.animationFrameId) {
					cancelAnimationFrame(this.animationFrameId);
				}
				this.animationStates.forEach(state => {
					if (state.standTimer) clearTimeout(state.standTimer);
					if (state.pageTimer) clearTimeout(state.pageTimer);
				});

				this.animationStates = this.form.zones.map(zone => {
					const assetInfo = this.prepareZoneAssets(zone);
					return {
						...assetInfo,
						currentPage: 0,
						currentX: 0,
						currentY: 0,
						standTimer: null,
						pageTimer: null,
						...this.getInitialPosition(zone, assetInfo)
					};
				});

				this.animationLoop();
			},

			getInitialPosition(zone, assetInfo) {
				const pos = {
					currentX: 0,
					currentY: 0
				};
				const effect = zone.effect; // 0:立即显示, 1:左移, 2:右移, 3:上移, 4:下移, 5:连续左移
				if (effect === 1) pos.currentX = zone.width;
				if (effect === 2) pos.currentX = -assetInfo.assetWidth;
				if (effect === 3) pos.currentY = zone.height;
				if (effect === 4) pos.currentY = -assetInfo.assetHeight;
				if (effect === 5) pos.currentX = 0; // Start at the beginning for continuous scroll
				return pos;
			},

			animationLoop() {
				this.drawCanvas();
				this.animationFrameId = requestAnimationFrame(this.animationLoop.bind(this));
			},

			drawCanvas() {
				const ctx = uni.createCanvasContext('previewCanvas', this);
				const query = uni.createSelectorQuery().in(this);

				query.select('.preview-canvas').boundingClientRect(rect => {
					if (!rect) return;
					const canvasWidth = rect.width;
					const canvasHeight = rect.height;

					ctx.clearRect(0, 0, canvasWidth, canvasHeight);

					const scale = Math.min(canvasWidth / this.screenWidth, canvasHeight / this.screenHeight);
					const screenDrawWidth = this.screenWidth * scale;
					const screenDrawHeight = this.screenHeight * scale;
					const offsetX = (canvasWidth - screenDrawWidth) / 2;
					const offsetY = (canvasHeight - screenDrawHeight) / 2;

					ctx.fillStyle = '#000000';
					ctx.fillRect(offsetX, offsetY, screenDrawWidth, screenDrawHeight);

					this.form.zones.forEach((zone, index) => {
						const state = this.animationStates[index];
						if (!state) return;

						if (zone.playType === 1 && state.isImage && state.imageUrl) {
							// 计算绘制区域
							const zoneDrawX = offsetX + zone.x * scale;
							const zoneDrawY = offsetY + zone.y * scale;
							const zoneDrawWidth = zone.width * scale;
							const zoneDrawHeight = zone.height * scale;
							ctx.save();
							ctx.beginPath();
							ctx.rect(zoneDrawX, zoneDrawY, zoneDrawWidth, zoneDrawHeight);
							ctx.clip();
							// 优先用缓存
							const cachePath = this.imageCache[state.imageUrl];
							if (cachePath) {
								ctx.drawImage(cachePath, zoneDrawX, zoneDrawY, zoneDrawWidth, zoneDrawHeight);
								// 颜色叠加
								if (zone.imageColor !== undefined) {
									ctx.globalAlpha = 0.4;
									ctx.setFillStyle(this.mapColor(zone.imageColor));
									ctx.fillRect(zoneDrawX, zoneDrawY, zoneDrawWidth, zoneDrawHeight);
									ctx.globalAlpha = 1;
								}
								ctx.restore();
								return;
							}
							// 没缓存则异步加载
							uni.getImageInfo({
								src: state.imageUrl,
								success: (res) => {
									this.imageCache[state.imageUrl] = res.path;
									this.drawCanvas(); // 重新绘制
								}
							});
							ctx.restore();
							return;
						}

						ctx.save();
						const zoneDrawX = offsetX + zone.x * scale;
						const zoneDrawY = offsetY + zone.y * scale;
						const zoneDrawWidth = zone.width * scale;
						const zoneDrawHeight = zone.height * scale;

						ctx.beginPath();
						ctx.rect(zoneDrawX, zoneDrawY, zoneDrawWidth, zoneDrawHeight);
						ctx.clip();

						// Setup font for drawing
						const fontSize = parseInt(this.fontSizes[zone.fontSize] || '16px');
						const scaledFontSize = Math.max(1, Math.round(fontSize * scale));
						ctx.font =
							`${this.mapBold(zone.fontBold)} ${scaledFontSize}px ${this.mapFont(zone.font)}`;
						ctx.fillStyle = this.mapColor(zone.fontColor);

						// Get the lines for the current page
						const pageLines = state.pages[state.currentPage] || [];

						// --- Correct Vertical Alignment Calculation ---
						const blockHeight = pageLines.length * scaledFontSize;
						let blockStartY = zoneDrawY + state.currentY * scale; // Apply Y animation offset
						const verticalAlign = this.mapVAlign(zone.vAlign);

						if (verticalAlign === 'middle') {
							blockStartY = zoneDrawY + state.currentY * scale + (zoneDrawHeight -
								blockHeight) / 2;
						} else if (verticalAlign === 'bottom') {
							blockStartY = zoneDrawY + state.currentY * scale + zoneDrawHeight -
								blockHeight;
						}

						// Set textBaseline to top for consistent line-by-line drawing
						ctx.textBaseline = 'top';

						pageLines.forEach((line, lineIndex) => {
							// Horizontal alignment
							let xPos = zoneDrawX + state.currentX *
								scale; // Apply X animation offset
							const horizontalAlign = this.mapHAlign(zone.hAlign);
							if (horizontalAlign === 'center') {
								const lineWidth = this.calculateTextWidth(line, scaledFontSize);
								xPos = zoneDrawX + state.currentX * scale + (zoneDrawWidth -
									lineWidth) / 2;
							} else if (horizontalAlign === 'right') {
								const lineWidth = this.calculateTextWidth(line, scaledFontSize);
								xPos = zoneDrawX + state.currentX * scale + zoneDrawWidth -
									lineWidth;
							}

							const yPos = blockStartY + (lineIndex * scaledFontSize);
							ctx.fillText(line, xPos, yPos);
						});

						// For continuous scroll, draw a second copy
						if (zone.effect === 5) {
							const secondCopyX = zoneDrawX + state.currentX * scale + state.assetWidth *
								scale;
							pageLines.forEach((line, lineIndex) => {
								// Horizontal alignment for the second copy is always 'left' relative to its starting point
								const yPos = blockStartY + (lineIndex * scaledFontSize);
								ctx.fillText(line, secondCopyX, yPos);
							});
						}

						ctx.restore();
						this.updateAnimationState(zone, state, index);
					});

					// Drawing partition lines after all content
					ctx.strokeStyle = '#FFFFFF';
					ctx.lineWidth = 1;
					ctx.save();
					ctx.translate(offsetX, offsetY);
					const mode = this.form.mode;
					if (mode === 1) { //上下
						ctx.beginPath();
						ctx.moveTo(0, screenDrawHeight / 2);
						ctx.lineTo(screenDrawWidth, screenDrawHeight / 2);
						ctx.stroke();
					} else if (mode === 2) { //左右
						ctx.beginPath();
						ctx.moveTo(screenDrawWidth / 2, 0);
						ctx.lineTo(screenDrawWidth / 2, screenDrawHeight);
						ctx.stroke();
					} else if (mode === 3) { //上中下
						ctx.beginPath();
						ctx.moveTo(0, screenDrawHeight / 3);
						ctx.lineTo(screenDrawWidth, screenDrawHeight / 3);
						ctx.moveTo(0, (screenDrawHeight / 3) * 2);
						ctx.lineTo(screenDrawWidth, (screenDrawHeight / 3) * 2);
						ctx.stroke();
					}
					ctx.restore();

					ctx.draw();
				}).exec();
			},

			updateAnimationState(zone, state) {
				if (state.standTimer) return;

				const speedMap = [1, 2, 3, 4, 5];
				const animationSpeed = (speedMap[zone.speed] || 5) / 5; // Normalize speed
				const effect = zone.effect;

				// Handle multi-page text cycling for non-scroll effects
				if (effect !== 5 && state.pages.length > 1) {
					// If we don't have a timer yet, start one
					if (!state.pageTimer) {
						const stayTimeMap = [0, 100, 500, 1000, 2000, 3000, 4000, 5000, 6000, 8000, 10000];
						const stayTime = stayTimeMap[zone.stayTime] || 3000;

						state.pageTimer = setTimeout(() => {
							state.currentPage = (state.currentPage + 1) % state.pages.length;
							state.pageTimer = null; // Clear timer so it can be set again
						}, stayTime);
					}
				}

				switch (effect) {
					case 0: // 立即显示 - 不需要动画，只需要页面切换
						break;
					case 1: // Left
						if (state.currentX > 0) state.currentX = Math.max(0, state.currentX - animationSpeed);
						break;
					case 2: // Right
						if (state.currentX < 0) state.currentX = Math.min(0, state.currentX + animationSpeed);
						break;
					case 3: // Up
						if (state.currentY > 0) state.currentY = Math.max(0, state.currentY - animationSpeed);
						break;
					case 4: // Down
						if (state.currentY < 0) state.currentY = Math.min(0, state.currentY + animationSpeed);
						break;
					case 5: // Continuous Left
						state.currentX -= animationSpeed;
						if (state.currentX <= -state.assetWidth) {
							state.currentX = 0;
						}
						break;
					case 6: // 闪烁换页 - 特殊处理
						if (!state.pageTimer) {
							const stayTimeMap = [0, 100, 500, 1000, 2000, 3000, 4000, 5000, 6000, 8000, 10000];
							const stayTime = stayTimeMap[zone.stayTime] || 3000;

							state.pageTimer = setTimeout(() => {
								state.currentPage = (state.currentPage + 1) % state.pages.length;
								state.pageTimer = null;
							}, stayTime);
						}
						break;
				}
			},

			prepareZoneAssets(zone) {
				if (zone.playType === 1 && zone.image) {
					// 图片类型也返回assetWidth/assetHeight，防止动画参数undefined
					return {
						isImage: true,
						imageUrl: zone.image,
						assetWidth: zone.width || 32,
						assetHeight: zone.height || 32,
						pages: [[]], // 保证动画相关代码不报错
						currentPage: 0
					};
				}
				if (zone.playType !== 0 || !zone.displayText) {
					return {
						pages: [],
						assetWidth: 0,
						assetHeight: 0,
						isText: false
					};
				}

				const ctx = uni.createCanvasContext('__temp_prepare_canvas', this);
				const fontSize = parseInt(this.fontSizes[zone.fontSize] || '16px');
				ctx.font = `${this.mapBold(zone.fontBold)} ${fontSize}px ${this.mapFont(zone.font)}`;

				// For continuous scroll, treat as a single line
				if (zone.effect === 5) {
					const textWidth = this.calculateTextWidth(zone.displayText, fontSize);
					return {
						pages: [
							[zone.displayText]
						],
						assetWidth: textWidth,
						assetHeight: fontSize,
						isText: true
					};
				}

				// Word wrapping logic based on character code estimation
				const lines = [];
				let currentLine = '';
				const text = zone.displayText;
				for (let i = 0; i < text.length; i++) {
					const char = text[i];
					const testLine = currentLine + char;
					const lineWidth = this.calculateTextWidth(testLine, fontSize);

					if (lineWidth > zone.width && currentLine !== '') {
						lines.push(currentLine);
						currentLine = char;
					} else {
						currentLine = testLine;
					}
				}
				if (currentLine) {
					lines.push(currentLine);
				}

				const lineHeight = fontSize;
				const maxLinesPerPage = zone.height > 0 ? Math.floor(zone.height / lineHeight) : 1;
				const pages = [];

				// 确保至少有一页，即使高度不够
				if (maxLinesPerPage > 0) {
					for (let i = 0; i < lines.length; i += maxLinesPerPage) {
						pages.push(lines.slice(i, i + maxLinesPerPage));
					}
				} else {
					// 如果高度不够，将所有行放在一页中
					pages.push(lines);
				}

				// 确保至少有一页（即使是空的）
				if (pages.length === 0) {
					pages.push([]);
				}

				return {
					pages: pages,
					assetWidth: zone.width,
					assetHeight: zone.height,
					isText: true
				};
			},

			calculateTextWidth(text, fontSize) {
				let width = 0;
				for (let i = 0; i < text.length; i++) {
					// Treat non-ASCII characters as full-width (width = height)
					if (text.charCodeAt(i) > 127) {
						width += fontSize;
					} else {
						// Treat ASCII characters as half-width
						width += fontSize / 2;
					}
				}
				return width;
			},

			openPicker(pickerFlag, zoneIndex) {
				this.currentZoneIndex = zoneIndex;
				this[pickerFlag] = true;
			},
			onPlayTypeConfirm(e) {
				console.log('onPlayTypeConfirm', e, e.index, e.value);
				this.form.zones[this.currentZoneIndex].playType = this.getIndex(e);
				this.showPlayTypePicker = false;
			},
			onPhraseConfirm(e) {
				console.log('onPhraseConfirm', e, e.index, e.value);
				const index = this.getIndex(e);
				const phrase = this.commonPhrases[index];
				this.form.zones[this.currentZoneIndex].commonPhrase = index;
				if (index > 0) { // Not "自定义"
					this.form.zones[this.currentZoneIndex].displayText = phrase;
				}
				this.drawCanvas();
				this.showPhrasePicker = false;
			},
			onFontConfirm(e) {
				console.log('onFontConfirm', e, e.index, e.value);
				this.form.zones[this.currentZoneIndex].font = this.getIndex(e);
				console.log('form.font', this.form.zones[this.currentZoneIndex].font);
				this.drawCanvas();
				this.showFontPicker = false;
			},
			onFontShapeConfirm(e) {
				console.log('onFontShapeConfirm', e, e.index, e.value);
				this.form.zones[this.currentZoneIndex].fontShape = this.getIndex(e);
				console.log('form.fontShape', this.form.zones[this.currentZoneIndex].fontShape);
				this.drawCanvas();
				this.showFontShapePicker = false;
			},
			onFontSizeConfirm(e) {
				console.log('onFontSizeConfirm', e, e.index, e.value);
				this.form.zones[this.currentZoneIndex].fontSize = this.getIndex(e);
				console.log('form.fontSize', this.form.zones[this.currentZoneIndex].fontSize);
				this.drawCanvas();
				this.showFontSizePicker = false;
			},
			onFontColorConfirm(e) {
				console.log('onFontColorConfirm', e, e.index, e.value);
				this.form.zones[this.currentZoneIndex].fontColor = this.getIndex(e);
				console.log('form.fontColor', this.form.zones[this.currentZoneIndex].fontColor);
				this.drawCanvas();
				this.showFontColorPicker = false;
			},
			onFontBoldConfirm(e) {
				console.log('onFontBoldConfirm', e, e.index, e.value);
				this.form.zones[this.currentZoneIndex].fontBold = this.getIndex(e);
				console.log('form.fontBold', this.form.zones[this.currentZoneIndex].fontBold);
				this.drawCanvas();
				this.showFontBoldPicker = false;
			},
			onFontStretchConfirm(e) {
				console.log('onFontStretchConfirm', e, e.index, e.value);
				this.form.zones[this.currentZoneIndex].fontStretch = this.getIndex(e);
				console.log('form.fontStretch', this.form.zones[this.currentZoneIndex].fontStretch);
				this.drawCanvas();
				this.showFontStretchPicker = false;
			},
			onEffectConfirm(e) {
				console.log('onEffectConfirm', e, e.index, e.value);
				this.form.zones[this.currentZoneIndex].effect = this.getIndex(e);
				console.log('form.effect', this.form.zones[this.currentZoneIndex].effect);
				this.drawCanvas();
				this.showEffectPicker = false;
			},
			onHAlignConfirm(e) {
				console.log('onHAlignConfirm', e, e.index, e.value);
				this.form.zones[this.currentZoneIndex].hAlign = this.getIndex(e);
				console.log('form.hAlign', this.form.zones[this.currentZoneIndex].hAlign);
				this.drawCanvas();
				this.showHAlignPicker = false;
			},
			onVAlignConfirm(e) {
				console.log('onVAlignConfirm', e, e.index, e.value);
				this.form.zones[this.currentZoneIndex].vAlign = this.getIndex(e);
				console.log('form.vAlign', this.form.zones[this.currentZoneIndex].vAlign);
				this.drawCanvas();
				this.showVAlignPicker = false;
			},
			onSpeedConfirm(e) {
				console.log('onSpeedConfirm', e, e.index, e.value);
				this.form.zones[this.currentZoneIndex].speed = this.getIndex(e);
				console.log('form.speed', this.form.zones[this.currentZoneIndex].speed);
				// No direct draw call, watcher will handle it.
				this.showSpeedPicker = false;
			},
			onStayTimeConfirm(e) {
				console.log('onStayTimeConfirm', e, e.index, e.value);
				this.form.zones[this.currentZoneIndex].stayTime = this.getIndex(e);
				console.log('form.stayTime', this.form.zones[this.currentZoneIndex].stayTime);
				// No direct draw call, watcher will handle it.
				this.showStayTimePicker = false;
			},
			onRead() {
				this.$u.toast('读取功能待实现');
			},
			onSet() {
				// 构建要发送的数据
				const programData = {
					form: this.form,
					device: this.device,
					deviceInfo: this.deviceInfo
				};

				// 发送数据到父页面
				uni.$emit('programDataReady', programData);

				this.$u.toast('设置成功');

				// 返回上一页
				uni.navigateBack();
			},
			onImageConfirm(e) {
				const index = this.getIndex(e);
				const fileName = this.imageFiles[index];
				this.form.zones[this.currentZoneIndex].image = `https://xaznkj.cn/doc/traffic/${fileName}.png`;
				this.showImagePicker = false;
			},
			onImageSizeConfirm(e) {
				const idx = this.getIndex(e);
				this.form.zones[this.currentZoneIndex].imageSize = idx;
				// 自动赋值宽高
				const sizeMap = [
					{ w: 16, h: 16 },
					{ w: 32, h: 32 },
					{ w: 64, h: 64 }
				];
				this.form.zones[this.currentZoneIndex].width = sizeMap[idx].w;
				this.form.zones[this.currentZoneIndex].height = sizeMap[idx].h;
				this.showImageSizePicker = false;
				this.drawCanvas();
			},
			onImageColorConfirm(e) {
				console.log('onImageColorConfirm', e, e.index, e.value);
				this.form.zones[this.currentZoneIndex].imageColor = this.getIndex(e);
				console.log('form.imageColor', this.form.zones[this.currentZoneIndex].imageColor);
				this.drawCanvas();
				this.showImageColorPicker = false;
			},
			mapFont(index) {
				return ['SimSun', 'SimHei', 'KaiTi'][index] || 'SimSun';
			},
			mapColor(index) {
				return ['#FF0000', '#00FF00', '#0000FF'][index] || '#FF0000'; // Red, Green, Blue
			},
			mapBold(index) {
				return ['normal', 'bold'][index] || 'normal';
			},
			mapHAlign(index) {
				return ['left', 'center', 'right'][index] || 'left';
			},
			mapVAlign(index) {
				return ['top', 'middle', 'bottom'][index] || 'top';
			}
		}
	};
</script>
<style scoped>
	.preview-section {
		position: sticky;
		top: 0;
		z-index: 99;
	}

	.add-program-container {
		background: #f5f7fa;
		padding: 16px;
		/* margin-top: 160px; 增加顶部内边距，避免被标题栏遮挡 */
	}

	.section {
		background: #fff;
		border-radius: 10px;
		margin-bottom: 16px;
		box-shadow: 0 2px 8px #e0e0e0;
		padding: 12px 16px 16px 16px;
	}

	.section-title {
		font-weight: bold;
		font-size: 16px;
		margin-top: 10px;
		margin-bottom: 8px;
		color: #409eff;
	}

	.section-title.blue {
		background: #409eff;
		color: #fff;
		padding: 6px 12px;
		border-radius: 6px 6px 0 0;
		margin: -12px -16px 8px -16px;
	}

	.section-title.preview-fixed {
		position: fixed;
		top: 0;
		left: 0;
		width: 100vw;
		z-index: 999;
		box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
		border-radius: 0 0 12px 12px;
		padding-top: env(safe-area-inset-top, 0);
		background: linear-gradient(to bottom, #409eff, #5b9bd5);
		height: auto;
		/* 改为自动高度 */
		min-height: 160px;
		/* 设置最小高度 */
	}

	.preview-canvas {
		width: 100%;
		height: 120px;
		border: 2px solid #e0e0e0;
		border-radius: 8px;
		margin-bottom: 8px;
		box-shadow: inset 0 0 8px rgba(0, 0, 0, 0.2);
		display: block;
	}

	.zone-card {
		background: #fff;
		border-radius: 12px;
		box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
		margin-bottom: 20px;
		padding: 0 0 16px 0;
		border: 1px solid #eaeaea;
		overflow: hidden;
	}

	.zone-title {
		background: #409eff;
		color: #fff;
		font-size: 20px;
		font-weight: bold;
		border-radius: 12px 12px 0 0;
		padding: 10px 20px;
		margin-bottom: 8px;
		letter-spacing: 2px;
		box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
	}

	.group-card {
		background: #f8fafd;
		border-radius: 8px;
		box-shadow: 0 1px 4px #e0e0e0;
		margin: 16px 16px 0 16px;
		padding: 12px 16px 12px 16px;
		border: 1px solid #f0f0f0;
		transition: all 0.3s ease;
	}

	.group-card:hover {
		box-shadow: 0 6px 12px rgba(0, 0, 0, 0.1);
	}

	.group-title {
		color: #409eff;
		font-size: 15px;
		font-weight: bold;
		margin-bottom: 10px;
		letter-spacing: 1px;
	}

	/* 修改 form-row 的 justify-content 为 flex-start 使内容靠左 */
	.form-row {
		display: flex;
		align-items: center;
		justify-content: space-between;
		margin-bottom: 12px;
		padding: 8px 0;
	}


	/* 保留 row-3 的特殊布局 */
	.form-row.row-3 {
		display: flex;
		gap: 10px;
		margin-bottom: 12px;
		justify-content: flex-start;
		/* 左对齐 */
	}

	.form-label,
	.mini-label {
		color: #666;
		font-size: 20px;
		text-align: left;
		width: 90px;
		min-width: 90px;
		flex-shrink: 0;
		margin-right: 0;
		margin-left: 20px;
	}

	.picker {
		background: #fff;
		border-radius: 8px;
		border: 1.5px solid #d0d7e5;
		box-shadow: 0 2px 8px rgba(64, 158, 255, 0.06);
		padding: 8px 32px 8px 16px;
		min-width: 100px;
		font-size: 15px;
		color: #333;
		position: relative;
		transition: border-color 0.2s, box-shadow 0.2s;
		cursor: pointer;
		line-height: 1.6;
		display: flex;
		align-items: right;

		margin-left: 65px;
		max-width: 100%;
		text-align: right;
	}

	.picker:after {
		content: '';
		display: block;
		position: absolute;
		right: 14px;
		top: 50%;
		width: 0;
		height: 0;
		border-left: 6px solid transparent;
		border-right: 6px solid transparent;
		border-top: 7px solid #b0b0b0;
		transform: translateY(-50%);
		pointer-events: none;
	}

	.picker:hover,
	.picker:active {
		border-color: #409eff;
		box-shadow: 0 4px 12px rgba(64, 158, 255, 0.12);
		background: #f4faff;
		color: #2979ff;
	}

	.u-input,
	u-input {
		flex: 1;
		min-width: 80px;
		border-radius: 6px;
		font-size: 15px;
		border: 1px solid #eaeaea;
		background: #fafafa;
	}

	.input-area {
		width: 100%;
		min-height: 60px;
		border-radius: 6px;
		font-size: 16px;
		margin-top: 4px;
		border: 1px solid #eaeaea;
	}

	.button-row {
		display: flex;
		justify-content: space-around;
		margin-top: 24px;
		padding-top: 16px;
		border-top: 1px dashed #eaeaea;
	}

	.btn {
		width: 40%;
		border-radius: 20px;
		box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
		transition: all 0.3s;
	}

	.btn:active {
		transform: translateY(1px);
	}

	/* 特别为 right-picker 类添加样式，使 picker 靠右 */
	.right-picker {
		display: flex;
		justify-content: flex-end;
		/* 使整个容器内容靠右 */
		align-items: center;
		gap: 10px;
		margin-bottom: 12px;
		flex-wrap: wrap;
	}

	.right-picker .picker {
		margin-left: auto;
		/* 使 picker 元素自身向右对齐 */
		flex: 0 0 160px;
		/* 固定宽度，不伸缩 */
	}

	@media (max-width: 500px) {
		.zone-title {
			font-size: 16px;
			padding: 8px 16px;
		}

		.group-title {
			font-size: 14px;
		}

		.form-label {
			min-width: 50px;
			font-size: 13px;
		}

		.picker {
			min-width: 80px;
		}

		.btn {
			width: 45%;
			/* 在小屏幕上按钮占更多空间 */
		}

		/* 在小屏幕上调整 right-picker 的样式 */
		.right-picker {
			flex-direction: row;
			/* 确保水平排列 */
		}

		.right-picker .picker {
			flex: 0 0 auto;
			/* 不强制宽度，允许根据内容调整 */
			min-width: 70px;
			/* 最小宽度 */
		}
	}

	.picker-group,
	.form-row.row-3 {
		display: block;
		margin: 0;
		padding: 0;
	}

	.unit-label {
		font-size: 13px;
		color: #888;
		margin-left: 8px;
	}
</style>