<template>
  <view class="make-page">
    <NavBar title="祝福贺卡" />
    <!-- 顶部步骤条 -->
    <view class="top-steps">
      <view class="step-bar">
        <view
          v-for="(tool, idx) in tools"
          :key="idx"
          class="step-item"
          :class="{ active: activeTool === tool.type }"
          @tap="openTool(tool.type)"
        >
          <view class="step-num-wrap">
            <view class="step-line" v-if="idx > 0"></view>
            <view class="step-num">
              <text v-if="activeTool === tool.type && showPanel">{{
                tool.icon
              }}</text>
              <text v-else>{{ tool.step }}</text>
            </view>
          </view>
          <text class="step-text">{{ tool.text }}</text>
        </view>
      </view>
    </view>

    <!-- 预览卡片 -->
    <view class="card-preview">
      <view
        class="music-control"
        @tap.stop="openBgmList"
        :class="{ playing: isBgmPlaying }"
      >
        <text class="music-icon">{{ isBgmPlaying ? "🎵" : "🔇" }}</text>
      </view>
      <view class="premium-tag">
        <uni-icons type="info" size="12" color="#fff"></uni-icons>
        <text>分享或保存即可去除水印</text>
      </view>
      <image
        class="card-bg"
        :src="currentTemplate?.imageUrl"
        mode="aspectFill"
      />
      <view class="card-overlay">
        <view class="watermark">精美头像壁纸祝福</view>
        <!-- 选中的标题图片 -->
        <image
          v-if="currentTitle"
          class="selected-title-img"
          :src="currentTitle.imageUrl"
          mode="widthFix"
          :style="titleStyle"
          @touchstart.stop="handleTitleTouchStart"
          @touchmove.stop="handleTitleTouchMove"
          @touchend.stop="handleTitleTouchEnd"
        />
        <view
          class="bubble"
          @tap="openTool('text')"
          @touchstart.stop="handleBubbleTouchStart"
          @touchmove.stop="handleBubbleTouchMove"
          @touchend.stop="handleBubbleTouchEnd"
          :style="{
            marginTop: 140 + bubbleOffsetY + 'rpx',
            maxWidth: bubbleMaxWidth + 80 + 'rpx',
          }"
        >
          <text
            class="bubble-text"
            :style="{
              color: selectedColor,
              fontFamily: selectedFont.family,
              fontSize: fontSize + 'rpx',
              lineHeight: fontSize * 1.5 + 'rpx',
              fontWeight: fontWeight,
            }"
            >{{
              (targetName || "") + "\n  " + (blessingText.content || "")
            }}</text
          >
        </view>
        <view
          class="user"
          :style="{
            left: 160 + userOffsetX + 'rpx',
            bottom: 40 - userOffsetY + 'rpx',
          }"
          @touchstart.stop="handleUserTouchStart"
          @touchmove.stop="handleUserTouchMove"
          @touchend.stop="handleUserTouchEnd"
        >
          <image class="avatar" :src="userAvatar" mode="aspectFill" />
          <view class="user-info">
            <text
              class="user-name"
              :style="{ color: signatureColor, fontWeight: fontWeight }"
              >{{ signatureName }}</text
            >
            <text
              class="user-desc"
              :style="{ color: signatureColor, fontWeight: fontWeight }"
              >送上祝福</text
            >
          </view>
        </view>
      </view>
    </view>

    <view class="tip-line">
      <view class="interaction-tip">
        <uni-icons type="hand-up" size="14" color="#ff3b30"></uni-icons>
        <text>标题、祝福语、个人信息可拖动改变位置，双指可缩放标题</text>
      </view>
    </view>

    <!-- 底部固定按钮 -->
    <view class="bottom-actions-fixed">
      <view class="main-actions">
        <button class="btn secondary" @tap="preview">
          <uni-icons type="cloud-download" size="20" color="#888"></uni-icons>
          <view>保存</view>
        </button>
        <button open-type="share" class="btn primary">
          <uni-icons
            type="paperplane-filled"
            size="20"
            color="#fff"
          ></uni-icons>
          <view>分享给好友</view>
        </button>
      </view>
    </view>

    <!-- 弹出编辑面板 -->
    <view class="panel-container" :class="{ show: showPanel }">
      <view class="panel-mask" @tap="closePanel"></view>
      <scroll-view
        scroll-y
        class="panel-content"
        :class="{
          'glass-effect': activeTool === 'text' || activeTool === 'position',
        }"
        @scrolltolower="onPanelScrollToLower"
      >
        <view class="panel-inner">
          <view class="panel-handle" @tap="closePanel"></view>

          <!-- 标题选择区 -->
          <view v-if="activeTool === 'title'" class="section">
            <view class="section-title">
              <text>选择标题</text>
            </view>
            <view class="tpl-scroll">
              <view class="tpl-grid">
                <view
                  v-for="(title, i) in titles"
                  :key="i"
                  class="tpl-card title-card"
                  :class="{ selected: title?.id === currentTitle?.id }"
                  @tap="selectTitle(title)"
                >
                  <image
                    :src="getTitleThumbUrl(title.imageUrl)"
                    class="title-cover"
                    mode="aspectFit"
                  />
                  <view v-if="title?.id === currentTitle?.id" class="tpl-check"
                    >✔</view
                  >
                  <!-- Lock Overlay -->
                  <view
                    v-if="!title.isUnlock && title.unlockType"
                    class="lock-overlay"
                  >
                    <!-- Badge -->
                    <view class="unlock-badge" :class="title.unlockType">
                      {{ getUnlockLabel(title.unlockType) }}
                    </view>

                    <!-- Center Lock -->
                    <view class="center-lock">
                      <uni-icons type="locked-filled" size="18" color="#fff" />
                    </view>
                  </view>
                </view>
              </view>
              <view v-if="loadingTitles" class="loading-more">加载中...</view>
              <view
                v-else-if="!hasMoreTitles && titles.length > 0"
                class="no-more"
                >没有更多了</view
              >
            </view>
          </view>

          <!-- 模板区 -->
          <view v-if="activeTool === 'template'" class="section">
            <view class="section-title">
              <text>热门模板</text>
            </view>
            <view class="tpl-scroll">
              <view class="tpl-grid">
                <view
                  v-for="(tpl, i) in templates"
                  :key="i"
                  class="tpl-card"
                  :class="{ selected: tpl?.id === currentTemplate?.id }"
                  @tap="applyTemplate(tpl)"
                >
                  <image
                    :src="getThumbUrl(tpl.imageUrl)"
                    class="tpl-cover"
                    mode="aspectFill"
                  />
                  <view class="tpl-name">{{ tpl.name }}</view>
                  <view v-if="tpl?.id === currentTemplate?.id" class="tpl-check"
                    >✔</view
                  >
                  <!-- Lock Overlay -->
                  <view
                    v-if="!tpl.isUnlock && tpl.unlockType"
                    class="lock-overlay"
                  >
                    <!-- Badge -->
                    <view class="unlock-badge" :class="tpl.unlockType">
                      {{ getUnlockLabel(tpl.unlockType) }}
                    </view>

                    <!-- Center Lock -->
                    <view class="center-lock">
                      <uni-icons type="locked-filled" size="18" color="#fff" />
                    </view>
                  </view>
                </view>
              </view>
              <view v-if="loadingTemplates" class="loading-more"
                >加载中...</view
              >
              <view
                v-else-if="!hasMoreTemplates && templates.length > 0"
                class="no-more"
                >没有更多了</view
              >
            </view>
          </view>

          <!-- 文字编辑 -->
          <view v-if="activeTool === 'text'" class="section text-edit-section">
            <view class="form-item">
              <text class="label">祝福对象(可不填)</text>
              <input
                class="input-box"
                v-model="targetName"
                placeholder="请输入称呼"
                placeholder-style="color:#ccc"
                maxlength="10"
                @blur="handleTargetNameBlur"
              />
            </view>

            <!-- 署名 -->
            <view class="form-item">
              <text class="label">署名(可不填)</text>
              <view class="input-wrapper">
                <input
                  class="input-box"
                  v-model="signatureName"
                  placeholder="请输入署名"
                  placeholder-style="color:#ccc"
                  maxlength="10"
                  @blur="handleSignatureBlur"
                />
                <text class="edit-icon">✎</text>
              </view>
            </view>

            <!-- 祝福语库 -->
            <view class="form-item">
              <view class="label-row">
                <text class="label">祝福语库</text>
              </view>
              <view class="greeting-grid">
                <view
                  v-for="(text, index) in greetingLib"
                  :key="index"
                  class="greeting-card"
                  :class="{ active: blessingText.content === text.content }"
                  @tap="selectGreeting(text)"
                >
                  <text class="greeting-text">{{ text.content }}</text>
                  <view
                    v-if="blessingText.content === text.content"
                    class="check-mark"
                    >✔</view
                  >
                </view>
              </view>
              <view v-if="loadingBlessings" class="loading-more"
                >加载中...</view
              >
              <view
                v-else-if="!hasMoreBlessings && greetingLib.length > 0"
                class="no-more"
                >没有更多了</view
              >
            </view>
          </view>

          <!-- 样式与位置 -->
          <view
            v-if="activeTool === 'position'"
            class="section position-section"
          >
            <view class="section-title">
              <text>调整样式与位置</text>
            </view>

            <!-- 字体大小 -->
            <view class="form-item" style="margin-top: 20rpx">
              <text class="label">字体大小</text>
              <slider
                :value="fontSize"
                min="24"
                max="64"
                show-value
                @change="(e) => (fontSize = e.detail.value)"
                activeColor="#ff3b30"
              />
            </view>

            <!-- 字体粗细 -->
            <view class="form-item">
              <text class="label">字体粗细</text>
              <view class="weight-options">
                <view
                  class="weight-btn"
                  :class="{ active: fontWeight === 'normal' }"
                  @tap="fontWeight = 'normal'"
                >
                  <text>常规</text>
                </view>
                <view
                  class="weight-btn"
                  :class="{ active: fontWeight === 'bold' }"
                  @tap="fontWeight = 'bold'"
                >
                  <text style="font-weight: bold">加粗</text>
                </view>
              </view>
            </view>

            <view class="form-item">
              <text class="label">祝福语宽窄</text>
              <slider
                :value="bubbleMaxWidth"
                min="200"
                max="460"
                show-value
                @change="(e) => (bubbleMaxWidth = e.detail.value)"
                activeColor="#ff3b30"
              />
            </view>

            <!-- 字体选择 -->
            <view class="form-item">
              <text class="label">字体样式</text>
              <scroll-view scroll-x class="font-scroll" show-scrollbar="false">
                <view class="font-list">
                  <view
                    v-for="(font, index) in fontList"
                    :key="index"
                    class="font-item"
                    :class="{ active: selectedFont.family === font.family }"
                    @tap="changeFont(font)"
                  >
                    <text :style="{ fontFamily: font.family }">{{
                      font.name
                    }}</text>
                  </view>
                </view>
              </scroll-view>
            </view>

            <!-- 文字颜色 -->
            <view class="form-item">
              <text class="label">祝福语颜色</text>
              <view class="color-list">
                <view
                  v-for="(color, index) in textColors"
                  :key="index"
                  class="color-item"
                  :style="{ background: color }"
                  @tap="selectedColor = color"
                >
                  <view v-if="selectedColor === color" class="color-check"
                    >✔</view
                  >
                </view>
              </view>
            </view>

            <view class="form-item">
              <text class="label">署名颜色</text>
              <view class="color-list">
                <view
                  v-for="(color, index) in textColors"
                  :key="index"
                  class="color-item"
                  :style="{ background: color }"
                  @tap="signatureColor = color"
                >
                  <view v-if="signatureColor === color" class="color-check"
                    >✔</view
                  >
                </view>
              </view>
            </view>

            <!-- <view class="form-item">
            <text class="label">祝福语气泡 (上下)</text>
            <slider
              :value="bubbleOffsetY"
              min="-200"
              max="400"
              show-value
              @change="(e) => (bubbleOffsetY = e.detail.value)"
              activeColor="#ff3b30"
            />
          </view>

          <view class="form-item">
            <text class="label">个人信息 (上下)</text>
            <slider
              :value="userOffsetY"
              min="-300"
              max="600"
              show-value
              @change="(e) => (userOffsetY = e.detail.value)"
              activeColor="#ff3b30"
            />
          </view>

          <view class="form-item">
            <text class="label">个人信息 (左右)</text>
            <slider
              :value="userOffsetX"
              min="-200"
              max="400"
              show-value
              @change="(e) => (userOffsetX = e.detail.value)"
              activeColor="#ff3b30"
            />
          </view> -->
          </view>
        </view>
      </scroll-view>
    </view>

    <canvas
      type="2d"
      id="cardCanvas"
      class="hidden-canvas"
      style="width: 540px; height: 960px"
    />

    <LoginPopup
      ref="loginPopupRef"
      @logind="handleLogind"
      :share-token="shareToken"
    />

    <!-- Music List Popup -->
    <uni-popup ref="bgmPopup" type="bottom">
      <view class="bgm-popup">
        <view class="bgm-header">
          <text class="bgm-title">选择背景音乐</text>
          <view class="bgm-close" @tap="closeBgmList">✕</view>
        </view>
        <scroll-view scroll-y class="bgm-scroll">
          <view
            v-for="(item, index) in bgms"
            :key="index"
            class="bgm-item"
            :class="{ active: currentBgmIndex === index && isBgmPlaying }"
            @tap="selectBgm(index)"
          >
            <view class="bgm-info">
              <uni-icons
                :type="
                  currentBgmIndex === index && isBgmPlaying
                    ? 'sound-filled'
                    : 'sound'
                "
                size="18"
                :color="
                  currentBgmIndex === index && isBgmPlaying ? '#ff3b30' : '#333'
                "
              ></uni-icons>
              <text class="bgm-name">{{ item.name }}</text>
            </view>
            <view
              v-if="currentBgmIndex === index && isBgmPlaying"
              class="bgm-playing-icon"
            >
              <view class="bar bar1"></view>
              <view class="bar bar2"></view>
              <view class="bar bar3"></view>
            </view>
          </view>
        </scroll-view>
        <view class="bgm-footer" @tap="turnOffBgm">
          <text class="turn-off-text">关闭音乐</text>
        </view>
      </view>
    </uni-popup>

    <!-- Scene Selection Popup -->
    <uni-popup ref="scenePopup" type="center" :is-mask-click="false">
      <view class="scene-popup">
        <view class="scene-header">
          <text class="scene-title">选择祝福场景</text>
          <text class="scene-subtitle">挑选一个场景，开启专属祝福</text>
          <view class="scene-divider">
            <view class="line"></view>
            <uni-icons
              type="cloud-upload-filled"
              size="16"
              color="#E6B800"
            ></uni-icons>
            <view class="line"></view>
          </view>
        </view>
        <view class="scene-grid">
          <view
            class="scene-item"
            v-for="(scene, index) in scenes"
            :key="index"
            @tap="selectScene(scene)"
          >
            <view class="scene-icon-box" :style="{ background: scene.bgColor }">
              <image
                v-if="scene.icon && scene.icon.includes('/')"
                :src="scene.icon"
                mode="aspectFit"
                style="width: 52rpx; height: 52rpx"
              />
              <uni-icons
                v-else
                :type="scene.icon || 'star-filled'"
                size="26"
                :color="scene.color"
              ></uni-icons>
            </view>
            <text class="scene-name">{{ scene.name }}</text>
          </view>
        </view>
        <view class="skip-btn" @tap="skipScene">跳过，直接制作</view>
      </view>
    </uni-popup>
    <LoginPopup ref="loginPopupRef" @logind="handleLogind" />
    <RewardAd ref="rewardAdRef" @onReward="handleAdReward" />
  </view>
</template>

<script setup>
import { ref, computed, watch } from "vue";
import { generateObjectId, getShareToken } from "@/utils/common";
import {
  createCardTmp,
  updateCard,
  getCardTemplateList,
  getCardTemplateContentList,
  getCardTemplateTitleList,
  getCardMusicList,
} from "@/api/make";
import { getGreetingSceneList } from "@/api/card";
import { getShareReward, msgCheckApi, watchAdReward } from "@/api/system";
import { checkAbilityAndHandle, getUnlockLabel } from "@/utils/ability.js";
import {
  onShareAppMessage,
  onShareTimeline,
  onLoad,
  onReachBottom,
  onShow,
  onPullDownRefresh,
  onUnload,
  onHide,
} from "@dcloudio/uni-app";
import { useUserStore } from "@/stores/user";
import LoginPopup from "@/components/LoginPopup/LoginPopup.vue";
import { saveRecordRequest, uploadImage, trackRecord } from "@/utils/common.js";
import NavBar from "@/components/NavBar/NavBar.vue";

import RewardAd from "@/components/RewardAd/RewardAd.vue";

const userStore = useUserStore();
const loginPopupRef = ref(null);
const rewardAdRef = ref(null);
const isLoggedIn = computed(() => !!userStore.userInfo.nickName);

const DEFAULT_AVATAR =
  "https://file.lihailezzc.com/resource/96023631c6ab9c3496b7620097af3d6f.png";

const templatePage = ref(1);
const loadingTemplates = ref(false);
const hasMoreTemplates = ref(true);
const cardId = ref("");

// 标题相关
const titles = ref([]);
const currentTitle = ref(titles.value[0]);
const titlePage = ref(1);
const loadingTitles = ref(false);
const hasMoreTitles = ref(true);
const titleState = ref({
  offsetX: 0,
  offsetY: 0,
  scale: 1,
});

const bgms = ref([]);
const curBgm = ref(null);
const currentBgmIndex = ref(0);
const isBgmPlaying = ref(false);
const innerAudioContext = uni.createInnerAudioContext();
const bgmPopup = ref(null);

const initBgm = () => {
  if (bgms.value.length > 0) {
    playBgm(0);
  }
};

const openBgmList = () => {
  bgmPopup.value.open();
};

const closeBgmList = () => {
  bgmPopup.value.close();
};

const selectBgm = (index) => {
  if (index === currentBgmIndex.value && isBgmPlaying.value) {
    // 如果点击当前正在播放的，暂停
    // pauseBgm();
    // 这里用户可能想重播，或者什么都不做。暂时什么都不做
    return;
  }
  curBgm.value = bgms.value[index];
  playBgm(index);
  closeBgmList();
};

const turnOffBgm = () => {
  stopBgm();
  currentBgmIndex.value = -1; // -1 表示关闭
  curBgm.value = null;
  closeBgmList();
  uni.showToast({ title: "已关闭音乐", icon: "none" });
};

const playBgm = (index) => {
  if (index < 0 || index >= bgms.value.length) return;

  // 更新 index
  currentBgmIndex.value = index;

  innerAudioContext.stop();
  innerAudioContext.src = bgms.value[index].musicUrl;
  innerAudioContext.loop = true;
  innerAudioContext.autoplay = true;
  innerAudioContext.play();

  // 重新绑定事件（防止丢失）
  innerAudioContext.onPlay(() => {
    isBgmPlaying.value = true;
  });
  innerAudioContext.onPause(() => {
    isBgmPlaying.value = false;
  });
  innerAudioContext.onStop(() => {
    isBgmPlaying.value = false;
  });
  innerAudioContext.onError((res) => {
    console.error("BGM Error:", res.errMsg);
    isBgmPlaying.value = false;
  });
};

const stopBgm = () => {
  innerAudioContext.stop();
  isBgmPlaying.value = false;
};

onUnload(() => {
  innerAudioContext.destroy();
});

onHide(() => {
  innerAudioContext.stop();
});

const titleStyle = computed(() => {
  return {
    transform: `translate(${titleState.value.offsetX}rpx, ${titleState.value.offsetY}rpx) scale(${titleState.value.scale})`,
    top: "40rpx",
    pointerEvents: "auto",
    transition: "none",
  };
});

// 缓存比例转换
const sysInfo = uni.getSystemInfoSync();
const pxToRpx = 750 / sysInfo.windowWidth;

// 标题触摸交互相关
let startTouches = [];
let initialTitleState = {
  offsetX: 0,
  offsetY: 0,
  scale: 1,
};

const getDistance = (p1, p2) => {
  const x = p2.clientX - p1.clientX;
  const y = p2.clientY - p1.clientY;
  return Math.sqrt(x * x + y * y);
};

const handleTitleTouchStart = (e) => {
  if (!currentTitle.value) return;
  startTouches = e.touches;
  initialTitleState = { ...titleState.value };
};

const handleTitleTouchEnd = () => {
  startTouches = [];
};

// 个人信息触摸交互相关
let startUserTouches = [];
let initialUserState = {
  offsetX: 0,
  offsetY: 0,
};

const handleUserTouchStart = (e) => {
  startUserTouches = e.touches;
  initialUserState = {
    offsetX: userOffsetX.value,
    offsetY: userOffsetY.value,
  };
};

const handleUserTouchEnd = () => {
  startUserTouches = [];
};

const handleUserTouchMove = (e) => {
  if (!startUserTouches.length) return;

  if (e.touches.length === 1 && startUserTouches.length === 1) {
    // 单指拖拽
    const moveX = e.touches[0].clientX - startUserTouches[0].clientX;
    const moveY = e.touches[0].clientY - startUserTouches[0].clientY;

    userOffsetX.value = initialUserState.offsetX + moveX * pxToRpx;
    userOffsetY.value = initialUserState.offsetY + moveY * pxToRpx;
  }
};

// 祝福语触摸交互相关
let startBubbleTouches = [];
let initialBubbleOffsetY = 0;

const handleBubbleTouchStart = (e) => {
  startBubbleTouches = e.touches;
  initialBubbleOffsetY = bubbleOffsetY.value;
};

const handleBubbleTouchEnd = () => {
  startBubbleTouches = [];
};

const handleBubbleTouchMove = (e) => {
  if (!startBubbleTouches.length) return;

  if (e.touches.length === 1 && startBubbleTouches.length === 1) {
    // 单指拖拽 (仅上下)
    const moveY = e.touches[0].clientY - startBubbleTouches[0].clientY;
    let newY = initialBubbleOffsetY + moveY * pxToRpx;
    // 合理范围限制，参考 slider 的 min/max
    bubbleOffsetY.value = Math.min(Math.max(newY, -200), 400);
  }
};

const handleTitleTouchMove = (e) => {
  if (!currentTitle.value || !startTouches.length) return;

  if (e.touches.length === 1 && startTouches.length === 1) {
    // 单指拖拽
    const moveX = e.touches[0].clientX - startTouches[0].clientX;
    const moveY = e.touches[0].clientY - startTouches[0].clientY;

    titleState.value.offsetX = initialTitleState.offsetX + moveX * pxToRpx;
    titleState.value.offsetY = initialTitleState.offsetY + moveY * pxToRpx;
  } else if (e.touches.length === 2 && startTouches.length === 2) {
    // 双指缩放+平移
    const p1 = e.touches[0];
    const p2 = e.touches[1];
    const startP1 = startTouches[0];
    const startP2 = startTouches[1];

    // 缩放
    const currentDist = getDistance(p1, p2);
    const startDist = getDistance(startP1, startP2);
    if (startDist > 0) {
      const scale = initialTitleState.scale * (currentDist / startDist);
      titleState.value.scale = Math.min(Math.max(scale, 0.2), 3.0);
    }

    // 平移
    const currentCenterX = (p1.clientX + p2.clientX) / 2;
    const currentCenterY = (p1.clientY + p2.clientY) / 2;
    const startCenterX = (startP1.clientX + startP2.clientX) / 2;
    const startCenterY = (startP1.clientY + startP2.clientY) / 2;

    const moveX = currentCenterX - startCenterX;
    const moveY = currentCenterY - startCenterY;

    titleState.value.offsetX = initialTitleState.offsetX + moveX * pxToRpx;
    titleState.value.offsetY = initialTitleState.offsetY + moveY * pxToRpx;
  }
};

const targetName = ref("");
const oldTargetName = ref("");
const signatureName = ref(userStore?.userInfo?.nickName || "xxx");
const oldSignatureName = ref(userStore?.userInfo?.nickName || "xxx");

const handleTargetNameBlur = async () => {
  if (!targetName.value || targetName.value === oldTargetName.value) return;
  const res = await msgCheckApi(targetName.value);
  if (!res.success) {
    uni.showToast({
      title: res.message || "消息不符合发布规范，请稍作修改后再试",
      icon: "none",
    });
    targetName.value = oldTargetName.value;
  } else {
    oldTargetName.value = targetName.value;
  }
};

const handleSignatureBlur = async () => {
  if (!signatureName.value || signatureName.value === oldSignatureName.value)
    return;
  const res = await msgCheckApi(signatureName.value);
  if (!res.success) {
    uni.showToast({
      title: res.message || "消息不符合发布规范，请稍作修改后再试",
      icon: "none",
    });
    signatureName.value = oldSignatureName.value;
  } else {
    oldSignatureName.value = signatureName.value;
  }
};
const userAvatar = ref(userStore?.userInfo?.avatarUrl || DEFAULT_AVATAR);

const blessingText = ref({});
const fontSize = ref(38);
const fontWeight = ref("normal"); // 默认加粗

const textColors = [
  "#F8DA84",
  "#B4802C",
  "#000000",
  "#ffffff",
  "#ff3b30",
  "#F5A623",
  "#8B572A",
  "#D0021B",
  "#F8E71C",
  "#7ED321",
  "#4A90E2",
  "#9013FE",
  "#FFC0CB",
];
const selectedColor = ref("#000000");
const signatureColor = ref("#000000");

const fontList = [
  { name: "默认", family: "PingFang SC", url: "" },
  {
    name: "思源宋体",
    family: "SontTi SC",
    url: "https://file.lihailezzc.com/font/ddcd9621740449a29c329f573bc1d0c6.woff2", // 示例地址
  },
  {
    name: "思源黑体",
    family: "HeiTi SC",
    url: "https://file.lihailezzc.com/font/ddcd9621740449a29c329f573bc1d0c3.woff2", // 示例地址
  },
  {
    name: "仿宋",
    family: "FangSong",
    url: "https://file.lihailezzc.com/ddcd9621740449a29c329f573bc1d0c4.woff2", // 示例地址
  },
  {
    name: "中圆",
    family: "ZhongYuan",
    url: "https://file.lihailezzc.com/ddcd9621740449a29c329f573bc1d0c5.woff2", // 示例地址
  },
];
const selectedFont = ref(fontList[0]);
const loadedFonts = ref(new Set()); // 记录已加载的字体

const changeFont = (font) => {
  // 1. 如果是默认字体或已加载过的字体，直接应用
  if (!font.url || loadedFonts.value.has(font.family)) {
    selectedFont.value = font;
    return;
  }

  // 2. 否则加载字体
  uni.showLoading({ title: "加载字体中", mask: true });
  uni.loadFontFace({
    global: true,
    family: font.family,
    source: `url("${font.url}")`,
    scopes: ["webview", "native"],
    success: () => {
      selectedFont.value = font;
      loadedFonts.value.add(font.family); // 标记为已加载
      uni.hideLoading();
    },
    fail: (err) => {
      console.error(err);
      uni.hideLoading();
      // 如果加载失败，可以尝试直接设置（有些情况可能已经缓存或本地支持）
      // 或者提示用户
      uni.showToast({ title: "字体加载失败", icon: "none" });
    },
  });
};

const greetingLib = ref([]);
const blessingPage = ref(1);
const loadingBlessings = ref(false);
const hasMoreBlessings = ref(true);

const bubbleOffsetY = ref(0);
const bubbleMaxWidth = ref(400); // 默认宽度
const userOffsetX = ref(0);
const userOffsetY = ref(0);
const shareToken = ref("");

onLoad((options) => {
  if (options.shareToken) {
    shareToken.value = options.shareToken;
  }
  trackRecord({
    eventName: "make_page_visit",
    eventType: `visit`,
  });

  if (options.scene) {
    currentScene.value = options.scene;
    loadData();
  } else {
    setTimeout(() => {
      scenePopup.value.open();
    }, 200);
  }

  if (options.content) {
    blessingText.value = { content: decodeURIComponent(options.content) };
  }
  if (options.author) {
    signatureName.value = decodeURIComponent(options.author);
  }
  fetchSceneList();
});

const loadData = () => {
  getTemplateList();
  getTemplateContentList();
  getTemplateTitleList();
  getMusicList();
};

const currentScene = ref("");
const scenePopup = ref(null);
const scenes = ref([]);

const SCENE_PALETTE = [
  { color: "#FF3B30", bgColor: "#FFF5F5" },
  { color: "#FF9500", bgColor: "#FFF8E5" },
  { color: "#FFCC00", bgColor: "#FFFBE6" },
  { color: "#FF2D55", bgColor: "#FFF0F5" },
  { color: "#FF5E3A", bgColor: "#FFF2F0" },
  { color: "#8B572A", bgColor: "#F9F0E6" },
];

const fetchSceneList = async () => {
  try {
    const res = await getGreetingSceneList("daily");
    if (res && Array.isArray(res)) {
      scenes.value = res.map((item, index) => {
        const style = SCENE_PALETTE[index % SCENE_PALETTE.length];
        return {
          name: item.sceneName,
          value: item.scene,
          icon: item.imageUrl,
          color: style.color,
          bgColor: style.bgColor,
        };
      });
    }
  } catch (e) {
    console.error("fetchSceneList error", e);
  }
};

const selectScene = (scene) => {
  currentScene.value = scene.value;
  scenePopup.value.close();
  loadData();
};

const skipScene = () => {
  currentScene.value = "";
  scenePopup.value.close();
  loadData();
};

const syncUserInfo = (force = false) => {
  if (isLoggedIn.value) {
    if (signatureName.value === "xxx" || !signatureName.value) {
      signatureName.value = userStore.userInfo.nickName;
      oldSignatureName.value = userStore.userInfo.nickName;
    }
    if (force || userAvatar.value === DEFAULT_AVATAR || !userAvatar.value) {
      userAvatar.value = userStore.userInfo.avatarUrl;
    }
  }
};

watch(
  () => userStore.userInfo,
  (newVal) => {
    if (newVal?.nickName) {
      syncUserInfo(true);
    }
  },
  { deep: true },
);

onShow(() => {
  syncUserInfo(true);
  const recommendData = uni.getStorageSync("RECOMMEND_CARD_DATA");
  if (recommendData) {
    uni.removeStorageSync("RECOMMEND_CARD_DATA");
    if (recommendData.imageUrl) {
      const tpl = {
        id: recommendData.recommendId,
        imageUrl: recommendData.imageUrl,
        name: "推荐模板", // 暂时使用通用名称，如果需要可以从接口获取更多信息
      };

      // 切换到模板 Tab
      activeTool.value = "template";

      // 应用模板
      currentTemplate.value = tpl;

      // 如果模板列表中存在，更新引用
      const found = templates.value.find((t) => t.id === tpl.id);
      if (found) currentTemplate.value = found;
    }
  }

  const tempBlessing = uni.getStorageSync("TEMP_BLESSING_TEXT");
  if (tempBlessing) {
    blessingText.value = { content: tempBlessing, id: "" };
    uni.removeStorageSync("TEMP_BLESSING_TEXT");
    activeTool.value = "text";
  }
});

onReachBottom(() => {
  if (activeTool.value === "template") {
    loadMoreTemplates();
  } else if (activeTool.value === "title") {
    loadMoreTitles();
  } else if (activeTool.value === "text") {
    loadMoreBlessings();
  }
});

onPullDownRefresh(async () => {
  templatePage.value = 1;
  hasMoreTemplates.value = true;
  titlePage.value = 1;
  hasMoreTitles.value = true;
  blessingPage.value = 1;
  hasMoreBlessings.value = true;

  await Promise.all([
    getTemplateList(),
    getTemplateTitleList(),
    getTemplateContentList(),
  ]);
  uni.stopPullDownRefresh();
  uni.showToast({ title: "已为你更新内容", icon: "success" });
});

const handleLogind = async () => {
  syncUserInfo();
};

const createCard = () => {
  const id = generateObjectId();
  createCardTmp({ id });
  cardId.value = id;
  return id;
};

const getTemplateList = async (isLoadMore = false) => {
  if (loadingTemplates.value || (!hasMoreTemplates.value && isLoadMore)) return;

  loadingTemplates.value = true;
  try {
    const res = await getCardTemplateList(
      templatePage.value,
      currentScene.value,
    );

    // 兼容数组或对象列表格式
    const list = Array.isArray(res) ? res : res.list || [];

    if (list.length > 0) {
      if (isLoadMore) {
        templates.value = [...templates.value, ...list];
      } else {
        templates.value = list;
        // 初始加载时设置第一个为当前选中
        if (list.length > 0 && !currentTemplate.value) {
          currentTemplate.value = list[0];
        }
      }

      // 判断是否还有更多
      if (typeof res.hasNext !== "undefined") {
        hasMoreTemplates.value = res.hasNext;
      } else {
        // 如果没有 hasNext 字段，根据返回数量简单判断
        hasMoreTemplates.value = list.length >= 8; // 假设每页 10 条
      }

      if (hasMoreTemplates.value) {
        templatePage.value++;
      }
    } else {
      if (!isLoadMore) templates.value = [];
      hasMoreTemplates.value = false;
    }
  } catch (error) {
    console.error("加载模板失败:", error);
  } finally {
    loadingTemplates.value = false;
  }
};

const getMusicList = async () => {
  try {
    const res = await getCardMusicList();
    if (res && res.length > 0) {
      bgms.value = res.map((item) => ({
        id: item.id,
        name: item.name,
        musicUrl: item.musicUrl,
        // 兼容旧逻辑
        url: item.musicUrl,
      }));
      if (bgms.value.length > 0) {
        curBgm.value = bgms.value[0];
      }
      initBgm();
    }
  } catch (error) {
    console.error("加载音乐列表失败:", error);
  }
};

const getTemplateTitleList = async (isLoadMore = false) => {
  if (loadingTitles.value || (!hasMoreTitles.value && isLoadMore)) return;

  loadingTitles.value = true;
  try {
    const res = await getCardTemplateTitleList(
      titlePage.value,
      currentScene.value,
    );
    const list = Array.isArray(res) ? res : res.list || [];

    if (list.length > 0) {
      if (isLoadMore) {
        titles.value = [...titles.value, ...list];
      } else {
        titles.value = list;
        if (list.length > 0 && !currentTitle.value) {
          currentTitle.value = list[0];
        }
      }

      if (typeof res.hasNext !== "undefined") {
        hasMoreTitles.value = res.hasNext;
      } else {
        hasMoreTitles.value = list.length >= 8;
      }

      if (hasMoreTitles.value) {
        titlePage.value++;
      }
    } else {
      if (!isLoadMore) titles.value = [];
      hasMoreTitles.value = false;
    }
  } catch (error) {
    console.error("加载标题失败:", error);
  } finally {
    loadingTitles.value = false;
    if (!isLoadMore && hasMoreTitles.value) {
      getTemplateTitleList(true);
    }
  }
};

const loadMoreTitles = () => {
  getTemplateTitleList(true);
};

const getThumbUrl = (url) => {
  return `${url}?imageView2/1/w/340/h/600/q/80`;
};

const getTitleThumbUrl = (url) => {
  return `${url}?imageView2/2/w/200/h/200/q/80`;
};

const getTemplateContentList = async (isLoadMore = false) => {
  if (loadingBlessings.value || (!hasMoreBlessings.value && isLoadMore)) return;

  loadingBlessings.value = true;
  try {
    const res = await getCardTemplateContentList(
      blessingPage.value,
      currentScene.value,
    );
    const list = Array.isArray(res) ? res : res.list || [];

    if (list.length > 0) {
      if (isLoadMore) {
        greetingLib.value = [...greetingLib.value, ...list];
      } else {
        greetingLib.value = list;
        if (list.length > 0 && !blessingText.value.content) {
          blessingText.value = list[0];
        }
      }

      if (typeof res.hasNext !== "undefined") {
        hasMoreBlessings.value = res.hasNext;
      } else {
        hasMoreBlessings.value = list.length >= 8;
      }

      if (hasMoreBlessings.value) {
        blessingPage.value++;
      }
    } else {
      if (!isLoadMore) greetingLib.value = [];
      hasMoreBlessings.value = false;
    }
  } catch (error) {
    console.error("加载祝福语失败:", error);
  } finally {
    loadingBlessings.value = false;
  }
};

const loadMoreBlessings = () => {
  getTemplateContentList(true);
};

const loadMoreTemplates = () => {
  getTemplateList(true);
};

const onPanelScrollToLower = () => {
  if (activeTool.value === "template") {
    loadMoreTemplates();
  } else if (activeTool.value === "title") {
    loadMoreTitles();
  } else if (activeTool.value === "text") {
    loadMoreBlessings();
  }
};

onShareAppMessage(async (options) => {
  getShareReward({ scene: "card_generate" });
  if (options.from === "button") {
    if (!isLoggedIn.value) {
      loginPopupRef.value.open();
      return;
    }
    // 1. 确保有 cardId (如果内容有变动，最好是新建)
    const id = createCard();

    const shareToken = await getShareToken("card_generate", id);
    shareOrSave(id);
    return {
      title: "我刚做了一张祝福卡片，送给你",
      path: "/pages/detail/index?shareToken=" + shareToken,
      imageUrl:
        "https://file.lihailezzc.com/resource/bf9faeddb7ff55a5cd3d435779d56556.png",
    };
  } else {
    const shareToken = await getShareToken("card_generate_index", "");
    return {
      title: "快来制作祝福卡片🎉",
      path: `/pages/make/index?shareToken=${shareToken}`,
      imageUrl:
        "https://file.lihailezzc.com/resource/8dd026d76ef7a63d123b7fd698fb989b.png",
    };
  }
});

onShareTimeline(async () => {
  const shareToken = await getShareToken("card_timeline");
  return {
    title: "送你一张精美的祝福卡片 🎊",
    query: `shareToken=${shareToken}`,
    imageUrl:
      "https://file.lihailezzc.com/resource/8dd026d76ef7a63d123b7fd698fb989b.png",
  };
});

const selectGreeting = (text) => {
  trackRecord({
    eventName: "card_text_choose",
    eventType: "click",
    elementId: text?.id,
  });
  blessingText.value = text;
};

const tools = [
  { type: "template", text: "1. 选模板", icon: "🎨", step: 1 },
  { type: "title", text: "2. 选标题", icon: "🧧", step: 2 },
  { type: "text", text: "3. 写祝福", icon: "✍️", step: 3 },
  { type: "position", text: "4. 设样式", icon: "✨", step: 4 },
];
const activeTool = ref("template");
const showPanel = ref(false);

const openTool = (toolType) => {
  activeTool.value = toolType;
  showPanel.value = true;
};

const closePanel = () => {
  showPanel.value = false;
};

const templates = ref([]);

const currentTemplate = ref(templates.value[0]);
const currentUnlockTpl = ref(null);

const applyTemplate = (tpl) => {
  if (tpl.unlockType && !tpl.isUnlock) {
    handleUnlock(tpl);
    return;
  }
  trackRecord({
    eventName: "card_tpl_choose",
    eventType: "click",
    elementId: tpl?.id,
  });
  currentTemplate.value = tpl;
  closePanel();
};

const handleUnlock = (tpl) => {
  switch (tpl.unlockType) {
    case "vip":
      uni.navigateTo({
        url: "/pages/mine/vip",
      });
      break;
    case "ad":
      currentUnlockTpl.value = tpl;
      rewardAdRef.value.show();
      break;
    case "sing3":
      uni.showToast({
        title: "需要连续签到1天解锁",
        icon: "none",
      });
      break;
    case "sing5":
      uni.showToast({
        title: "需要连续签到5天解锁",
        icon: "none",
      });
      break;
    case "sing7":
      uni.showToast({
        title: "需要连续签到7天解锁",
        icon: "none",
      });
      break;
    default:
      uni.showToast({
        title: "未满足解锁条件",
        icon: "none",
      });
  }
};

const handleAdReward = async (token) => {
  try {
    const res = await watchAdReward(
      token,
      "unlock",
      activeTool.value === "template" ? "card_template" : "card_title_template",
      currentUnlockTpl.value.id,
    );
    if (res) {
      uni.showToast({
        title: "解锁成功",
        icon: "success",
      });
      // 解锁成功后，更新本地状态，允许使用
      if (currentUnlockTpl.value) {
        currentUnlockTpl.value.isUnlock = true;

        if (activeTool.value === "template") {
          // 同时更新列表中的状态
          const index = templates.value.findIndex(
            (t) => t.id === currentUnlockTpl.value.id,
          );
          if (index !== -1) {
            templates.value[index].isUnlock = true;
          }
          applyTemplate(currentUnlockTpl.value);
        } else if (activeTool.value === "title") {
          // 同时更新列表中的状态
          const index = titles.value.findIndex(
            (t) => t.id === currentUnlockTpl.value.id,
          );
          if (index !== -1) {
            titles.value[index].isUnlock = true;
          }
          selectTitle(currentUnlockTpl.value);
        }

        currentUnlockTpl.value = null;
      }
    }
  } catch (e) {
    console.error("Reward claim failed", e);
    uni.showToast({ title: "奖励发放失败", icon: "none" });
  }
};

const selectTitle = (title) => {
  if (title.unlockType && !title.isUnlock) {
    handleUnlock(title);
    return;
  }
  trackRecord({
    eventName: "card_title_choose",
    eventType: "click",
    elementId: title?.id,
  });
  if (currentTitle.value?.id === title?.id) {
    currentTitle.value = null;
  } else {
    currentTitle.value = title;

    // 切换标题时重置位置和缩放
    titleState.value = {
      offsetX: 0,
      offsetY: 0,
      scale: 1,
    };
    closePanel();
  }
};

const pickImage = () => {
  uni.chooseImage({
    count: 1,
    success: (res) => {
      const path = res.tempFilePaths?.[0];
      if (path)
        currentTemplate.value = { ...currentTemplate.value, cover: path };
    },
  });
};

const resetBackground = () => {
  currentTemplate.value = templates.value[0];
};

const toggleAvatarDecor = () => {
  uni.showToast({ title: "挂饰功能即将上线～", icon: "none" });
};

const preview = async () => {
  if (!isLoggedIn.value) {
    loginPopupRef.value.open();
    return;
  }
  const canProceed = await checkAbilityAndHandle("card_generate");
  if (!canProceed) return;

  const tempPath = await saveByCanvas(true);
  const id = createCard();
  shareOrSave(id);
  saveRecordRequest(tempPath, id, "card_generate");

  // uni.showToast({ title: '已保存到相册', icon: 'checkmarkempty' })
};

const shareOrSave = async (id) => {
  if (!id) id = createCard();

  const tempPath = await saveByCanvas(false);
  const imageUrl = await uploadImage(tempPath);

  updateCard({
    id,
    imageUrl,
    status: 1,
    blessingId: blessingText.value?.id || "",
    blessingTo: targetName.value,
    blessingFrom: signatureName.value,
    templateId: currentTemplate.value?.id || "",
    titleId: currentTitle?.value?.id || "",
    musicId: curBgm.value?.id || "",
  });
};

const showMore = () => {
  uni.showToast({ title: "更多模板即将上线～", icon: "none" });
};

const saveByCanvas = async (save = true) => {
  return new Promise((resolve, reject) => {
    const query = uni.createSelectorQuery();
    query
      .select("#cardCanvas")
      .fields({ node: true, size: true })
      .exec(async (res) => {
        if (!res[0] || !res[0].node) {
          reject("Canvas not found");
          return;
        }

        const canvas = res[0].node;
        const ctx = canvas.getContext("2d");

        // 初始化画布尺寸
        const dpr = uni.getSystemInfoSync().pixelRatio || 2;
        // 为了高清画质，将物理像素设置为逻辑像素的 dpr 倍
        const baseW = 540;
        const baseH = 960;
        canvas.width = baseW * dpr;
        canvas.height = baseH * dpr;

        // ⚠️ 关键修复：重置变换矩阵，防止多次调用导致 scale 累积
        // 支付宝小程序在设置 width/height 后可能未完全重置 Context 状态
        ctx.setTransform(1, 0, 0, 1, 0, 0);
        // 清空画布（使用物理像素尺寸）
        ctx.clearRect(0, 0, canvas.width, canvas.height);

        // 缩放上下文，使得后续绘制指令依然可以使用逻辑坐标 (baseW, baseH)
        ctx.scale(dpr, dpr);

        // 画布尺寸（逻辑像素）
        const W = baseW;
        const H = baseH;

        // 辅助函数：加载图片为 Image 对象
        const loadCanvasImage = (url) => {
          return new Promise((resolve, reject) => {
            const img = canvas.createImage();
            img.onload = () => resolve(img);
            img.onerror = (e) => reject(e);
            img.src = url;
          });
        };

        // 辅助函数：rpx 转 px (基于预览容器宽度 506rpx 对应 Canvas 540px)
        const r2p = (rpx) => (rpx * baseW) / 506;

        try {
          // #ifdef MP-ALIPAY
          // 支付宝环境：显式等待 Canvas 节点就绪，避免过早绘制
          await new Promise((resolve) => setTimeout(resolve, 300));
          // #endif

          // 1️⃣ 画背景
          // ⭐ 先加载背景图
          const [bgImg, avatarImg, titleImg] = await Promise.all([
            loadCanvasImage(currentTemplate?.value?.imageUrl),
            loadCanvasImage(userAvatar.value),
            currentTitle.value
              ? loadCanvasImage(currentTitle.value.imageUrl)
              : Promise.resolve(null),
          ]);

          ctx.drawImage(bgImg, 0, 0, W, H);

          // 2️⃣ 半透明遮罩
          ctx.fillStyle = "rgba(0,0,0,0.08)";
          ctx.fillRect(0, 0, W, H);

          // 3️⃣ 标题图片
          if (titleImg) {
            const previewBaseWidth = 400; // rpx
            const drawWidth = r2p(previewBaseWidth) * titleState.value.scale;
            const drawHeight = (titleImg.height / titleImg.width) * drawWidth;

            // 计算绘制起点：居中 + 偏移量
            const titleX = (W - drawWidth) / 2 + r2p(titleState.value.offsetX);
            const titleY = r2p(40) + r2p(titleState.value.offsetY);

            ctx.drawImage(titleImg, titleX, titleY, drawWidth, drawHeight);
          }

          // 4️⃣ 祝福语气泡
          // 预览中 .bubble 有 padding: 40rpx，且 .card-overlay 有 padding: 30rpx
          // 意味着文字距离容器边缘至少有 70rpx
          drawBubbleText(ctx, {
            text: targetName.value + "\n  " + blessingText.value.content,
            x: 0,
            y: r2p(230 + bubbleOffsetY.value),
            maxWidth: r2p(bubbleMaxWidth.value), // 预览中 bubble-text 的宽度
            canvasWidth: W,
            fontSize: r2p(fontSize.value),
            fontWeight: fontWeight.value,
            lineHeight: r2p(fontSize.value * 1.6), // 预览中是 1.6
            padding: r2p(40 + 30), // 内部 padding 40 + 容器 padding 30
            backgroundColor: "transparent",
            textColor: selectedColor.value,
            fontFamily: selectedFont.value.family,
          });

          // 5️⃣ 用户信息
          // 预览中 user 是 absolute, left: 160 + offsetX, bottom: 40 - offsetY
          drawUserBubble(ctx, {
            x: r2p(160 + userOffsetX.value),
            bottom: r2p(40 - userOffsetY.value),
            canvasHeight: H,
            avatarImg: avatarImg,
            username: signatureName.value,
            desc: "送上祝福",
            textColor: signatureColor.value,
            fontWeight: fontWeight.value,
            avatarSize: r2p(64),
            padding: r2p(15),
            fontSizeName: r2p(24),
            fontSizeDesc: r2p(20),
          });

          // 6️⃣ 输出
          // #ifdef MP-ALIPAY
          // 支付宝环境：等待绘制指令执行完毕，确保渲染完成
          await new Promise((resolve) => setTimeout(resolve, 300));
          // #endif

          uni.canvasToTempFilePath({
            canvas: canvas, // Canvas 2D 必须传 canvas 实例
            width: canvas.width,
            height: canvas.height,
            destWidth: canvas.width,
            destHeight: canvas.height,
            fileType: "jpg", // 使用 PNG 避免 JPG 压缩损耗
            quality: 0.85, // 最高质量
            success: (res) => {
              if (save) saveImage(res.tempFilePath);
              resolve(res.tempFilePath);
            },
            fail: (err) => reject(err),
          });
        } catch (error) {
          console.error("Canvas draw error:", error);
          reject(error);
        }
      });
  });
};

const loadImage = (url) => {
  // 此函数保留给其他可能用到的地方，但 saveByCanvas 内部使用 loadCanvasImage
  return new Promise((resolve, reject) => {
    uni.getImageInfo({
      src: url,
      success: (res) => {
        resolve(res.path); // 本地路径
      },
      fail: (err) => {
        reject(err);
      },
    });
  });
};

const saveImage = (path) => {
  uni.saveImageToPhotosAlbum({
    filePath: path,
    success() {
      uni.showToast({ title: "已保存到相册" });
    },
    fail() {
      uni.showModal({
        title: "提示",
        content: "请授权保存到相册",
      });
    },
  });
};

function drawBubbleText(ctx, options) {
  const {
    text,
    x,
    y,
    maxWidth = 400,
    padding = 24,
    lineHeight = 42,
    radius = 24,
    backgroundColor = "rgba(255,255,255,0.9)",
    textColor = "#fff",
    fontSize = 32,
    fontWeight = "normal",
    fontFamily = "PingFang SC",
    canvasWidth, // 新增：画布宽度，用于居中计算
  } = options;
  if (!text) return;

  ctx.fillStyle = textColor;
  ctx.font = `${fontWeight === "bold" ? "bold " : ""}${fontSize}px '${fontFamily}'`;
  ctx.textAlign = "left";
  ctx.textBaseline = "top";

  // 1️⃣ 文本自动换行
  const paragraphs = text.split("\n");

  const lines = [];

  /** ② 每一段再自动换行 */
  paragraphs.forEach((p) => {
    let line = "";
    for (let char of p) {
      const testLine = line + char;
      const { width } = ctx.measureText(testLine);
      if (width > maxWidth) {
        lines.push(line);
        line = char;
      } else {
        line = testLine;
      }
    }
    if (line) lines.push(line);
  });

  // 计算实际最大宽度以支持居中
  let maxLineWidth = 0;
  lines.forEach((line) => {
    const { width } = ctx.measureText(line);
    if (width > maxLineWidth) maxLineWidth = width;
  });

  // 如果提供了 canvasWidth，则自动计算居中的 x 坐标
  // 预览中文字是左对齐，但整个气泡容器是水平居中的
  let drawX = x;
  if (canvasWidth) {
    drawX = (canvasWidth - maxLineWidth) / 2;
  }

  // 4️⃣ 绘制文字
  ctx.fillStyle = textColor;

  lines.forEach((line, index) => {
    ctx.fillText(line, drawX, y + padding + index * lineHeight);
  });
}

function drawUserBubble(ctx, options) {
  const {
    x = 40, // 气泡起点 x
    y, // 气泡起点 y (如果传了 bottom 则优先计算)
    bottom, // 距离底部的距离
    canvasHeight,
    avatarImg, // CanvasImage 对象
    username = "zzc",
    desc = "送上祝福",
    avatarSize = 64, // 头像直径
    padding = 16, // 气泡内边距
    fontSizeName = 24,
    fontSizeDesc = 20,
    bubbleColor = "rgba(255,255,255,0.18)",
    textColor = "#000000",
    fontWeight = "normal",
  } = options;

  // 设置字体
  ctx.textBaseline = "top";
  ctx.font = `${fontWeight === "bold" ? "bold " : ""}${fontSizeName}px 'PingFang SC'`;

  // 测量文字宽度
  const nameWidth = ctx.measureText(username).width;
  ctx.font = `${fontWeight === "bold" ? "bold " : ""}${fontSizeDesc}px 'PingFang SC'`;
  const descWidth = ctx.measureText(desc).width;

  // 计算气泡宽度和高度
  const textWidth = Math.max(nameWidth, descWidth);
  const bubbleHeight =
    Math.max(avatarSize, fontSizeName + fontSizeDesc + 4) + padding * 2;
  const bubbleWidth = avatarSize + padding + textWidth + padding * 2;

  // 计算 y
  let drawY = y;
  if (typeof bottom !== "undefined" && canvasHeight) {
    drawY = canvasHeight - bottom - bubbleHeight;
  }

  // 1️⃣ 绘制气泡（左右半圆）
  drawRoundRect(
    ctx,
    x,
    drawY,
    bubbleWidth,
    bubbleHeight,
    bubbleHeight / 2,
    bubbleColor,
  );

  // 2️⃣ 绘制头像
  const avatarX = x + padding;
  const avatarY = drawY + (bubbleHeight - avatarSize) / 2;

  ctx.save();
  ctx.beginPath();
  ctx.arc(
    avatarX + avatarSize / 2,
    avatarY + avatarSize / 2,
    avatarSize / 2,
    0,
    Math.PI * 2,
  );
  ctx.clip();
  if (avatarImg) {
    ctx.drawImage(avatarImg, avatarX, avatarY, avatarSize, avatarSize);
  }
  ctx.restore();

  // 3️⃣ 绘制文字
  const textX = avatarX + avatarSize + padding;
  const totalTextHeight = fontSizeName + fontSizeDesc + 4;
  const textStartY = drawY + (bubbleHeight - totalTextHeight) / 2;

  ctx.fillStyle = textColor;
  ctx.font = `${fontWeight === "bold" ? "bold " : ""}${fontSizeName}px 'PingFang SC'`;
  ctx.fillText(username, textX, textStartY);

  ctx.font = `${fontWeight === "bold" ? "bold " : ""}${fontSizeDesc}px 'PingFang SC'`;
  ctx.globalAlpha = 0.8;
  ctx.fillText(desc, textX, textStartY + fontSizeName + 4);
  ctx.globalAlpha = 1;
}

function drawRoundRect(ctx, x, y, w, h, r, color) {
  ctx.beginPath();
  ctx.fillStyle = color || "rgba(255,255,255,0.18)";
  ctx.strokeStyle = "rgba(255,255,255,0.35)";
  ctx.lineWidth = 1;

  ctx.moveTo(x + r, y);
  ctx.lineTo(x + w - r, y);
  ctx.arcTo(x + w, y, x + w, y + r, r);
  ctx.lineTo(x + w, y + h - r);
  ctx.arcTo(x + w, y + h, x + w - r, y + h, r);
  ctx.lineTo(x + r, y + h);
  ctx.arcTo(x, y + h, x, y + h - r, r);
  ctx.lineTo(x, y + r);
  ctx.arcTo(x, y, x + r, y, r);
  ctx.closePath();
  ctx.fill();
}
</script>

<style lang="scss" scoped>
.make-page {
  min-height: 100vh;
  background: #fff;
  box-sizing: border-box;
}

/* 顶部提示 */
.tip-line {
  text-align: center;
  color: #999;
  font-size: 22rpx;
  margin-bottom: 140rpx; /* 为底部固定按钮留出空间 */
}

.interaction-tip {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8rpx;
  color: #ff3b30;
  font-size: 24rpx;
  font-weight: 500;
  margin-bottom: 12rpx;
  background: rgba(255, 59, 48, 0.05);
  padding: 8rpx 0;
  border-radius: 8rpx;
}

/* 卡片预览 */
.card-preview {
  margin: 30rpx auto 20rpx;
  height: 900rpx;
  width: 506rpx; /* 保持 9:16 比例并稍微缩小一点 */
  border-radius: 30rpx;
  overflow: hidden;
  position: relative;
  box-shadow: 0 16rpx 40rpx rgba(0, 0, 0, 0.12);
}

.premium-tag {
  position: absolute;
  top: 20rpx;
  right: -20rpx;
  background: linear-gradient(90deg, #ff8d42, #ff3b30);
  color: #fff;
  font-size: 20rpx;
  padding: 8rpx 30rpx 8rpx 20rpx;
  border-radius: 20rpx 0 0 20rpx;
  z-index: 10;
  display: flex;
  align-items: center;
  gap: 6rpx;
  box-shadow: 0 4rpx 12rpx rgba(255, 59, 48, 0.3);
  transform: translateX(10rpx);
}

.card-bg {
  width: 100%;
  height: 100%;
}
.card-overlay {
  position: absolute;
  inset: 0;
  padding: 30rpx;
  color: #fff;
  display: flex;
  flex-direction: column;
  align-items: center;
}
.watermark {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%) rotate(-45deg);
  font-size: 36rpx;
  color: rgba(255, 255, 255, 0.2);
  font-weight: bold;
  pointer-events: none;
  white-space: nowrap;
  z-index: 1;
}
.card-overlay .title {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin-top: 60rpx;
}
.title .main {
  font-size: 42rpx;
  font-weight: 700;
}
.title .sub {
  margin-top: 8rpx;
  font-size: 22rpx;
  opacity: 0.9;
}
.bubble {
  margin-top: 80rpx;
  padding: 40rpx;
  max-width: 500rpx;
}
.bubble-text {
  font-size: 26rpx;
  line-height: 1.6;
  white-space: pre-wrap;
  text-align: left;
}
.user {
  position: absolute;
  bottom: 40rpx;
  display: flex;
  align-items: center;
  background: rgba(255, 255, 255, 0.18);
  border: 1rpx solid rgba(255, 255, 255, 0.35);
  border-radius: 9999rpx;
  padding: 15rpx;
  padding-left: 20rpx;
  padding-right: 20rpx;
}
.avatar {
  width: 64rpx;
  height: 64rpx;
  border-radius: 50%;
  margin-right: 14rpx;
  border: 2rpx solid rgba(255, 255, 255, 0.6);
}
.user .user-info {
  display: flex;
  flex-direction: column;
}
.user-name {
  font-size: 24rpx;
  font-weight: 600;
}
.user-desc {
  font-size: 20rpx;
  opacity: 0.6;
  /* Lock Overlay - Modern Style */
  .lock-overlay {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    border-radius: 12rpx;
    z-index: 5;
    background: rgba(0, 0, 0, 0.05); /* very subtle dim */
  }

  .unlock-badge {
    position: absolute;
    top: 12rpx;
    right: 12rpx;
    padding: 4rpx 12rpx;
    border-radius: 20rpx;
    font-size: 18rpx;
    color: #fff;
    font-weight: bold;
    box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.2);

    &.vip {
      background: linear-gradient(135deg, #ffd700 0%, #ffa500 100%);
    }
    &.ad {
      background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
    }
    &.sing1,
    &.sing3,
    &.sing5,
    &.sing7 {
      background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);
    }
  }

  .center-lock {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 56rpx;
    height: 56rpx;
    background: rgba(0, 0, 0, 0.4);
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    backdrop-filter: blur(4px);
    border: 1px solid rgba(255, 255, 255, 0.2);
  }
}

/* 顶部步骤条 */
.top-steps {
  background: #fff;
  padding: 10rpx 0;
  box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05);
  position: relative;
  z-index: 10;
}
.step-bar {
  display: flex;
  justify-content: space-between;
  padding: 10rpx 40rpx;
  position: relative;
}

/* 底部固定按钮 */
.bottom-actions-fixed {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  background: #fff;
  padding-bottom: env(safe-area-inset-bottom);
  z-index: 90;
  box-shadow: 0 -10rpx 30rpx rgba(0, 0, 0, 0.05);
}

/* 弹出编辑面板 */
.panel-container {
  position: fixed;
  inset: 0;
  z-index: 100;
  visibility: hidden;
  pointer-events: none;
  transition: all 0.3s;
}
.panel-container.show {
  visibility: visible;
  pointer-events: auto;
}
.panel-mask {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.4);
  opacity: 0;
  transition: opacity 0.3s;
}
.panel-container.show .panel-mask {
  opacity: 1;
}
.panel-content {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  background: #fff;
  border-radius: 40rpx 40rpx 0 0;
  transform: translateY(100%);
  transition: transform 0.3s cubic-bezier(0.25, 1, 0.5, 1);
  height: 80vh;
}
.panel-inner {
  padding: 30rpx 40rpx calc(40rpx + env(safe-area-inset-bottom));
}
.panel-container.show .panel-content {
  transform: translateY(0);
}
.panel-content.glass-effect {
  background: rgba(255, 255, 255, 0.85);
  backdrop-filter: blur(20rpx);
  -webkit-backdrop-filter: blur(20rpx);
}
.panel-handle {
  width: 80rpx;
  height: 8rpx;
  background: #ddd;
  border-radius: 4rpx;
  margin: 0 auto 30rpx;
}
.step-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  flex: 1;
  position: relative;
  z-index: 1;
}
.step-num-wrap {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  position: relative;
  margin-bottom: 12rpx;
}
.step-line {
  position: absolute;
  right: 50%;
  top: 30rpx;
  width: 100%;
  height: 2rpx;
  background: #eee;
  z-index: -1;
}
.step-num {
  width: 60rpx;
  height: 60rpx;
  border-radius: 50%;
  background: #f5f5f5;
  color: #999;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 26rpx;
  font-weight: bold;
  border: 4rpx solid #fff;
  transition: all 0.3s;
}
.step-item.active .step-num {
  background: #ff3b30;
  color: #fff;
  transform: scale(1.1);
  box-shadow: 0 4rpx 12rpx rgba(255, 59, 48, 0.3);
}
.step-text {
  font-size: 24rpx;
  color: #999;
  font-weight: 500;
  transition: all 0.3s;
}
.step-item.active .step-text {
  color: #ff3b30;
  font-weight: bold;
}

/* 模板区 */
.section {
  padding: 12rpx 24rpx 0;
}
.section-title {
  display: flex;
  align-items: center;
}
.section-title .more {
  margin-left: auto;
  color: #ff3b30;
  font-size: 24rpx;
}
.tpl-scroll {
  margin-top: 12rpx;
}
.tpl-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16rpx;
  padding-bottom: 20rpx;
}
.tpl-card {
  width: 100%; /* 自适应 grid 宽度 */
  border-radius: 12rpx;
  overflow: hidden;
  background: #fff;
  position: relative;
  box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.06);
}
.title-card {
  height: 120rpx;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 10rpx;
}
.title-cover {
  width: 100%;
  height: 100%;
}
.selected-title-img {
  position: absolute;
  width: 400rpx;
  z-index: 2;
  /* 移除 transition，防止拖拽抖动 */
  transition: none;
}
.tpl-card.selected {
  outline: 4rpx solid #ff3b30;
}
.tpl-cover {
  width: 100%;
  height: 368rpx;
}
.tpl-name {
  font-size: 20rpx;
  color: #333;
  padding: 6rpx 8rpx;
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  position: relative;
}
.tpl-card .lock-overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  border-radius: 12rpx;
  z-index: 5;
  background: rgba(0, 0, 0, 0.05); /* very subtle dim */
}

.tpl-card .unlock-badge {
  position: absolute;
  top: 12rpx;
  right: 12rpx;
  padding: 4rpx 12rpx;
  border-radius: 20rpx;
  font-size: 18rpx;
  color: #fff;
  font-weight: bold;
  box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.2);

  &.vip {
    background: linear-gradient(135deg, #ffd700 0%, #ffa500 100%);
  }
  &.ad {
    background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
  }
  &.sing1,
  &.sing3,
  &.sing5,
  &.sing7 {
    background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);
  }
}

.tpl-card .center-lock {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 56rpx;
  height: 56rpx;
  background: rgba(0, 0, 0, 0.4);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  backdrop-filter: blur(4px);
  border: 1px solid rgba(255, 255, 255, 0.2);
}

.tpl-check {
  position: absolute;
  right: 6rpx;
  top: 6rpx;
  width: 32rpx;
  height: 32rpx;
  border-radius: 50%;
  background: #ff3b30;
  color: #fff;
  font-size: 20rpx;
  display: flex;
  align-items: center;
  justify-content: center;
}
.loading-more,
.no-more {
  text-align: center;
  font-size: 22rpx;
  color: #999;
  padding: 10rpx 0;
}

/* 文字编辑区 */
.text-edit-section {
  padding: 10rpx 24rpx 0;
}
.form-item {
  margin-bottom: 32rpx;
}
.label {
  font-size: 24rpx;
  color: #333;
  font-weight: 600;
  margin-bottom: 16rpx;
  display: block;
}
.input-box {
  background: #f9f9f9;
  border-radius: 12rpx;
  padding: 20rpx 24rpx;
  font-size: 28rpx;
  color: #333;
}
.label-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 16rpx;
}
.refresh-btn {
  font-size: 22rpx;
  color: #ff3b30;
  display: flex;
  align-items: center;
}
.refresh-icon {
  margin-right: 6rpx;
  font-size: 24rpx;
}
.greeting-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 16rpx;
  padding-bottom: 20rpx;
}
.greeting-card {
  width: 100%;
  height: 160rpx;
  background: #fff;
  border: 2rpx solid #eee;
  border-radius: 16rpx;
  padding: 20rpx;
  position: relative;
  box-sizing: border-box;
}
.greeting-card.active {
  background: #fff5f5;
  border-color: #ff3b30;
}
.greeting-text {
  font-size: 24rpx;
  color: #666;
  line-height: 1.5;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 4;
  overflow: hidden;
}

.position-section {
  margin-bottom: 40rpx;
}
.greeting-card.active .greeting-text {
  color: #ff3b30;
}
.check-mark {
  position: absolute;
  top: 10rpx;
  right: 10rpx;
  width: 32rpx;
  height: 32rpx;
  background: #ff3b30;
  border-radius: 50%;
  color: #fff;
  font-size: 20rpx;
  display: flex;
  align-items: center;
  justify-content: center;
}
.input-wrapper {
  position: relative;
}
.edit-icon {
  position: absolute;
  right: 24rpx;
  top: 50%;
  transform: translateY(-50%);
  color: #999;
}
.font-scroll {
  white-space: nowrap;
  width: 100%;
}

.font-list {
  display: flex;
  padding: 4rpx;
}

.font-item {
  padding: 12rpx 24rpx;
  background: #f5f5f5;
  border-radius: 8rpx;
  margin-right: 16rpx;
  border: 2rpx solid transparent;
  transition: all 0.3s;
}

.font-item.active {
  background: #fff5f5;
  border-color: #ff3b30;
  color: #ff3b30;
}

.color-list {
  display: flex;
  gap: 20rpx;
  flex-wrap: wrap;
}
.color-item {
  width: 64rpx;
  height: 64rpx;
  border-radius: 50%;
  position: relative;
  border: 2rpx solid rgba(0, 0, 0, 0.05);
}
.color-check {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  font-size: 32rpx;
  text-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.2);
}

.weight-options {
  display: flex;
  gap: 20rpx;
  flex: 1;
}
.weight-btn {
  flex: 1;
  height: 70rpx;
  background: #f5f5f5;
  border-radius: 12rpx;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 26rpx;
  color: #333;
  border: 2rpx solid transparent;
  transition: all 0.2s;
}
.weight-btn.active {
  background: #fff5f5;
  color: #ff3b30;
  border-color: #ff3b30;
}

/* 按钮区 */
.main-actions {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24rpx 32rpx 32rpx;
  background: #fff;
  position: relative;
}
.btn {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 96rpx;
  border-radius: 48rpx;
  margin: 0 12rpx;
  font-size: 30rpx;
  font-weight: 600;
  transition: all 0.2s active;
  position: relative;
  overflow: hidden;
  border: none;
}
.btn::after {
  border: none;
}
.btn:active {
  transform: scale(0.96);
  opacity: 0.9;
}

.btn.secondary {
  background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%);
  color: #333;
  box-shadow:
    0 8rpx 20rpx rgba(0, 0, 0, 0.05),
    inset 0 0 0 2rpx #eee;
}

.btn.primary {
  background: linear-gradient(135deg, #ff6b66 0%, #ff3b30 100%);
  color: #fff;
  box-shadow: 0 12rpx 30rpx rgba(255, 59, 48, 0.3);
  text-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.1);
}

.btn view {
  margin-left: 12rpx;
}
.hidden-canvas {
  position: fixed;
  left: -9999px;
  top: -9999px;
}

.music-control {
  position: absolute;
  top: 24rpx;
  left: 24rpx;
  width: 64rpx;
  height: 64rpx;
  background: rgba(0, 0, 0, 0.4);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 20;
  backdrop-filter: blur(4px);
  border: 1px solid rgba(255, 255, 255, 0.2);
  transition: all 0.3s;
}

.music-control.playing {
  background: rgba(255, 59, 48, 0.8);
  border-color: rgba(255, 59, 48, 0.5);
  animation: music-rotate 4s linear infinite;
}

@keyframes music-rotate {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

.bgm-popup {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  background: #fff;
  border-radius: 24rpx 24rpx 0 0;
  padding-bottom: env(safe-area-inset-bottom);
  max-height: 60vh;
  display: flex;
  flex-direction: column;
  z-index: 1000;
}

.bgm-header {
  padding: 30rpx;
  display: flex;
  align-items: center;
  justify-content: space-between;
  border-bottom: 1rpx solid #eee;
}

.bgm-title {
  font-size: 32rpx;
  font-weight: bold;
}

.bgm-close {
  font-size: 32rpx;
  color: #999;
  padding: 10rpx;
}

.bgm-scroll {
  max-height: 500rpx;
}

.bgm-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 30rpx;
  border-bottom: 1rpx solid #f5f5f5;
  transition: all 0.2s;
}

.bgm-item:active {
  background: #f9f9f9;
}

.bgm-item.active {
  background: #fff5f5;
}

.bgm-info {
  display: flex;
  align-items: center;
  gap: 20rpx;
}

.bgm-name {
  font-size: 28rpx;
  color: #333;
}

.bgm-item.active .bgm-name {
  color: #ff3b30;
  font-weight: 500;
}

.bgm-playing-icon {
  display: flex;
  align-items: flex-end;
  gap: 4rpx;
  height: 24rpx;
}

.bar {
  width: 4rpx;
  background: #ff3b30;
  animation: equalize 1s infinite;
}

.bar1 {
  animation-delay: 0s;
  height: 60%;
}
.bar2 {
  animation-delay: 0.2s;
  height: 100%;
}
.bar3 {
  animation-delay: 0.4s;
  height: 80%;
}

@keyframes equalize {
  0% {
    height: 40%;
  }
  50% {
    height: 100%;
  }
  100% {
    height: 40%;
  }
}

.bgm-footer {
  padding: 30rpx;
  display: flex;
  align-items: center;
  justify-content: center;
  border-top: 1rpx solid #eee;
}

.turn-off-text {
  color: #666;
  font-size: 28rpx;
}

/* 场景选择弹窗 */
.scene-popup {
  width: 520rpx;
  background: #fff;
  border-radius: 40rpx;
  padding: 40rpx 30rpx;
  display: flex;
  flex-direction: column;
  align-items: center;
  border: 4rpx solid #f8e71c; /* 金色边框 */
  box-shadow: 0 0 40rpx rgba(248, 231, 28, 0.2);
}

.scene-header {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin-bottom: 30rpx;
}

.scene-title {
  font-size: 38rpx;
  font-weight: bold;
  color: #d0021b; /* 深红色 */
  margin-bottom: 10rpx;
}

.scene-subtitle {
  font-size: 22rpx;
  color: #999;
  margin-bottom: 20rpx;
}

.scene-divider {
  display: flex;
  align-items: center;
  width: 100%;
  justify-content: center;
  gap: 16rpx;
}

.scene-divider .line {
  width: 80rpx;
  height: 2rpx;
  background: linear-gradient(
    90deg,
    rgba(230, 184, 0, 0),
    rgba(230, 184, 0, 0.5),
    rgba(230, 184, 0, 0)
  );
}

.scene-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 20rpx;
  width: 100%;
  margin-bottom: 30rpx;
}

.scene-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12rpx;
  background: #fff;
  padding: 24rpx 0;
  border-radius: 20rpx;
  box-shadow: 0 6rpx 16rpx rgba(0, 0, 0, 0.05);
  transition: all 0.2s;
}

.scene-item:active {
  transform: scale(0.98);
  box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.04);
}

.scene-icon-box {
  width: 80rpx;
  height: 80rpx;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 4rpx;
}

.scene-name {
  font-size: 26rpx;
  color: #333;
  font-weight: 600;
}

.skip-btn {
  font-size: 24rpx;
  color: #bbb;
  padding: 10rpx;
  text-decoration: underline;
}
</style>
