<template>
  <view class="avatar-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">{{ tool.icon }}</text>
              <text v-else>{{ tool.step }}</text>
            </view>
          </view>
          <text class="step-text">{{ tool.text }}</text>
        </view>
      </view>
    </view>

    <view class="preview-card">
      <view class="premium-tag">
        <uni-icons type="info" size="12" color="#fff"></uni-icons>
        <text>分享或保存即可去除水印</text>
      </view>
      <view class="preview-square">
        <view class="watermark">年禧集.马年春节祝福</view>
        <image
          class="avatar-img"
          :src="currentAvatar?.imageUrl"
          mode="aspectFill"
        />
        <image
          v-if="selectedFrame"
          class="frame-img"
          :src="selectedFrame?.imageUrl"
          mode="aspectFill"
        />
        <image
          v-if="selectedDecor"
          class="decor-img"
          :src="selectedDecor?.imageUrl"
          mode="aspectFit"
          :style="decorStyle"
          @touchstart.stop="onTouchStart"
          @touchmove.stop="onTouchMove"
          @touchend.stop="onTouchEnd"
        />
      </view>
      <view v-if="selectedDecor" class="interaction-tip">
        <text>👆 单指拖动</text>
        <text class="tip-divider">|</text>
        <text>✌️ 双指缩放/旋转</text>
      </view>
      <text v-else class="preview-tip">实时预览效果</text>
    </view>

    <view class="action-buttons">
      <button class="btn secondary" @tap="saveAndUse">保存</button>
      <button class="btn primary" open-type="share">分享给朋友</button>
    </view>

    <!-- 资源选择区 -->
    <view class="resource-selector">
      <!-- 头像选择区 -->
      <view v-if="activeTool === 'avatar'" class="section">
        <view class="section-title">选择头像</view>
        <view class="grid">
          <view class="grid-item upload-card">
            <button
              class="wechat-avatar-btn"
              open-type="chooseAvatar"
              @chooseavatar="onChooseAvatar"
            >
              <view class="upload-icon">✨</view>
              <text class="upload-text">微信头像</text>
            </button>
          </view>
          <view
            v-for="item in systemAvatars"
            :key="item.id"
            class="grid-item"
            :class="{ active: currentAvatar?.id === item.id }"
            @tap="currentAvatar = item"
          >
            <image :src="item.imageUrl" class="grid-img" mode="aspectFill" />
            <view v-if="currentAvatar?.id === item.id" class="check">✓</view>
          </view>
        </view>
        <view v-if="avatarLoading" class="loading-more">加载中...</view>
        <view v-if="!avatarHasNext" class="no-more">没有更多了</view>
      </view>

      <!-- 头像框选择区 -->
      <view v-if="activeTool === 'frame'" class="section">
        <view class="section-title">选择头像框</view>
        <view class="grid">
          <view
            v-for="item in frames"
            :key="item.id"
            class="grid-item"
            :class="{ active: selectedFrame?.id === item.id }"
            @tap="toggleFrame(item)"
          >
            <image :src="item.imageUrl" class="grid-img" mode="aspectFill" />
            <view v-if="selectedFrame?.id === item.id" class="check">✓</view>
          </view>
        </view>
        <view v-if="frameLoading" class="loading-more">加载中...</view>
        <view v-if="!frameHasNext" class="no-more">没有更多了</view>
      </view>

      <!-- 挂饰选择区 -->
      <view v-if="activeTool === 'decor'" class="section">
        <view class="section-title">选择挂饰</view>
        <view class="grid">
          <view
            v-for="item in decors"
            :key="item.id"
            class="grid-item"
            :class="{ active: selectedDecor?.id === item.id }"
            @tap="toggleDecor(item)"
          >
            <image :src="item.imageUrl" class="grid-img" mode="aspectFill" />
            <view v-if="selectedDecor?.id === item.id" class="check">✓</view>
          </view>
        </view>
        <view v-if="decorLoading" class="loading-more">加载中...</view>
        <view v-if="!decorHasNext" class="no-more">没有更多了</view>
      </view>
    </view>

    <canvas
      type="2d"
      id="avatarCanvas"
      canvas-id="avatarCanvas"
      class="hidden-canvas"
      style="width: 600px; height: 600px"
    />

    <!-- Login Popup -->
    <LoginPopup ref="loginPopupRef" @logind="handleLogind" />

    <!-- More Avatar Popup -->
    <uni-popup ref="morePopup" type="bottom" background-color="#fff">
      <view class="popup-content">
        <view class="popup-header">
          <text class="popup-title">选择头像</text>
          <view class="close-btn" @tap="closeMorePopup">✕</view>
        </view>
        <scroll-view
          scroll-y
          class="popup-scroll"
          @scrolltolower="loadMoreAvatars"
        >
          <view class="popup-grid">
            <view
              v-for="(item, i) in moreAvatars"
              :key="i"
              class="popup-item"
              @tap="selectMoreAvatar(item)"
            >
              <image :src="item.imageUrl" class="popup-img" mode="aspectFill" />
            </view>
          </view>
          <view v-if="loading" class="loading-text">加载中...</view>
          <view v-if="!hasMore && moreAvatars.length > 0" class="no-more-text">
            没有更多了
          </view>
        </scroll-view>
      </view>
    </uni-popup>
  </view>
</template>

<script setup>
import { ref, computed } from "vue";
import { onShareAppMessage, onLoad, onReachBottom } from "@dcloudio/uni-app";
import { useUserStore } from "@/stores/user";
import {
  createShareToken,
  getShareReward,
  abilityCheck,
} from "@/api/system.js";
import {
  getAvatarSystemList,
  getAvatarFrameList,
  getAvatarDecorList,
  avatarCreateComplete,
} from "@/api/avatar.js";
import {
  saveRecordRequest,
  getShareToken,
  generateObjectId,
  uploadImage,
} from "@/utils/common.js";
import NavBar from "@/components/NavBar/NavBar.vue";
import { getBavBarHeight } from "@/utils/system";

const userStore = useUserStore();
const loginPopupRef = ref(null);

const isLoggedIn = computed(() => !!userStore.userInfo.nickName);

const systemAvatars = ref([]);
const frames = ref([]);
const decors = ref([]);

// Panel and steps logic
const activeTool = ref("avatar");
const tools = [
  { step: "01", text: "头像", type: "avatar", icon: "👤" },
  { step: "02", text: "头像框", type: "frame", icon: "🖼️" },
  { step: "03", text: "挂饰配件", type: "decor", icon: "✨" },
];

const openTool = (type) => {
  activeTool.value = type;
};

// Pagination states
const avatarPage = ref(1);
const avatarHasNext = ref(true);
const avatarLoading = ref(false);

const framePage = ref(1);
const frameHasNext = ref(true);
const frameLoading = ref(false);

const decorPage = ref(1);
const decorHasNext = ref(true);
const decorLoading = ref(false);

const currentAvatar = ref(null);
const selectedFrame = ref(null);
const selectedDecor = ref(null);

// More Popup logic
const morePopup = ref(null);
const moreAvatars = ref([]);

const loadAvatars = async () => {
  if (avatarLoading.value || !avatarHasNext.value) return;
  avatarLoading.value = true;
  try {
    const res = await getAvatarSystemList(avatarPage.value);
    const list = res?.list || [];
    if (list.length > 0) {
      systemAvatars.value.push(
        ...list.map((item) => ({
          id: item.id,
          imageUrl: item.imageUrl,
        })),
      );
      avatarPage.value++;
      // 默认选中第一个
      if (systemAvatars.value.length > 0 && !currentAvatar.value) {
        currentAvatar.value = systemAvatars.value[0];
      }
    }
    if (typeof res.hasNext !== "undefined") {
      avatarHasNext.value = res.hasNext;
    } else {
      if (list.length < 10) avatarHasNext.value = false;
    }
  } catch (e) {
    console.error("Failed to load avatars:", e);
  } finally {
    avatarLoading.value = false;
  }
};

const loadFrames = async () => {
  if (frameLoading.value || !frameHasNext.value) return;
  frameLoading.value = true;
  try {
    const res = await getAvatarFrameList(framePage.value);
    const list = res?.list || [];
    if (list.length > 0) {
      frames.value.push(
        ...list.map((item) => ({
          id: item.id,
          imageUrl: item.imageUrl,
        })),
      );
      framePage.value++;
    }
    if (typeof res.hasNext !== "undefined") {
      frameHasNext.value = res.hasNext;
    } else {
      if (list.length < 10) frameHasNext.value = false;
    }
  } catch (e) {
    console.error(e);
  } finally {
    frameLoading.value = false;
  }
};

const loadDecors = async () => {
  if (decorLoading.value || !decorHasNext.value) return;
  decorLoading.value = true;
  try {
    const res = await getAvatarDecorList(decorPage.value);
    const list = res?.list || [];
    if (list.length > 0) {
      decors.value.push(
        ...list.map((item) => ({
          id: item.id,
          imageUrl: item.imageUrl,
        })),
      );
      decorPage.value++;
    }
    if (typeof res.hasNext !== "undefined") {
      decorHasNext.value = res.hasNext;
    } else {
      if (list.length < 10) decorHasNext.value = false;
    }
  } catch (e) {
    console.error(e);
  } finally {
    decorLoading.value = false;
  }
};

onLoad((options) => {
  loadAvatars();
  loadFrames();
  loadDecors();

  // 处理推荐跳转参数
  if (options && options.recommendId && options.type && options.imageUrl) {
    const recommendItem = {
      id: options.recommendId,
      imageUrl: decodeURIComponent(options.imageUrl),
    };

    if (options.type === "frame") {
      activeTool.value = "frame";
      selectedFrame.value = recommendItem;
    } else if (options.type === "decor") {
      activeTool.value = "decor";
      selectedDecor.value = recommendItem;
    } else if (options.type === "avatar") {
      currentAvatar.value = recommendItem;
    }
  }
});

onReachBottom(() => {
  if (activeTool.value === "avatar") {
    loadAvatars();
  } else if (activeTool.value === "frame") {
    loadFrames();
  } else if (activeTool.value === "decor") {
    loadDecors();
  }
});

const goBack = () => {
  uni.navigateBack();
};

const toggleFrame = (frame) => {
  if (selectedFrame.value === frame) {
    selectedFrame.value = null;
  } else {
    selectedFrame.value = frame;
  }
};

const toggleDecor = (decor) => {
  if (selectedDecor.value === decor) {
    selectedDecor.value = null;
  } else {
    selectedDecor.value = decor;
  }
};

// 挂饰状态
const decorState = ref({
  x: 300, // 初始中心 X (rpx)
  y: 80, // 初始中心 Y (rpx)
  scale: 1,
  rotate: 0,
});

const decorStyle = computed(() => {
  return {
    transform: `translate(${decorState.value.x - 120}rpx, ${
      decorState.value.y - 120
    }rpx) rotate(${decorState.value.rotate}deg) scale(${
      decorState.value.scale
    })`,
  };
});

// 触摸状态
let startTouches = [];
let initialDecorState = {};

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

const getAngle = (p1, p2) => {
  const x = p1.clientX - p2.clientX;
  const y = p1.clientY - p2.clientY;
  return (Math.atan2(y, x) * 180) / Math.PI;
};

const onTouchStart = (e) => {
  startTouches = e.touches;
  initialDecorState = { ...decorState.value };
};

const onTouchMove = (e) => {
  if (e.touches.length === 1 && startTouches.length === 1) {
    // 单指移动
    const dx = e.touches[0].clientX - startTouches[0].clientX;
    const dy = e.touches[0].clientY - startTouches[0].clientY;

    // px 转 rpx
    const systemInfo = uni.getSystemInfoSync();
    const ratio = 750 / systemInfo.windowWidth;

    decorState.value.x = initialDecorState.x + dx * ratio;
    decorState.value.y = initialDecorState.y + dy * ratio;
  } 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);

    const currentAngle = getAngle(p1, p2);
    const startAngle = getAngle(startP1, startP2);

    decorState.value.scale =
      initialDecorState.scale * (currentDist / startDist);
    decorState.value.rotate =
      initialDecorState.rotate + (currentAngle - startAngle);
  }
};

const onTouchEnd = () => {
  // 可以在这里做边界检查等
};

const handleLogind = async () => {
  // Logic after successful login if needed
};

const onChooseAvatar = async (e) => {
  const avatarUrl = e.detail.avatarUrl;
  if (!avatarUrl) return;

  uni.showLoading({ title: "上传中...", mask: true });
  try {
    const imageUrl = await uploadImage(avatarUrl);

    currentAvatar.value = {
      id: "wechat_" + Date.now(),
      imageUrl: imageUrl,
    };
    uni.hideLoading();
  } catch (e) {
    uni.hideLoading();
    uni.showToast({ title: e || "上传失败", icon: "none" });
    console.error("Upload avatar error", e);
  }
};

const createAvatarId = () => {
  const id = generateObjectId();
  return id;
};

const saveByCanvas = async (save = true) => {
  return new Promise((resolve, reject) => {
    const query = uni.createSelectorQuery();
    query
      .select("#avatarCanvas")
      .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 loadCanvasImage = (url) => {
          return new Promise((resolve, reject) => {
            const img = canvas.createImage();
            img.onload = () => resolve(img);
            img.onerror = (e) => reject(e);
            img.src = url;
          });
        };

        // 初始化画布尺寸
        const size = 600;
        canvas.width = size;
        canvas.height = size;
        const avatarPath = await loadCanvasImage(currentAvatar.value.imageUrl);
        ctx.clearRect(0, 0, size, size);
        ctx.drawImage(avatarPath, 0, 0, size, size);
        if (selectedFrame.value) {
          const framePath = await loadCanvasImage(selectedFrame.value.imageUrl);
          ctx.drawImage(framePath, 0, 0, size, size);
        }
        if (selectedDecor.value) {
          const decorPath = await loadCanvasImage(selectedDecor.value.imageUrl);
          ctx.save();
          // 映射 rpx 坐标到 Canvas 坐标 (假设 1rpx = 1 unit for 600x600 canvas logic)
          // Canvas size is 600, Preview is 600rpx. Ratio is 1:1 in logical space.
          ctx.translate(decorState.value.x, decorState.value.y);
          ctx.rotate((decorState.value.rotate * Math.PI) / 180);
          const scale = decorState.value.scale;
          // 绘制图片，宽高 240
          ctx.drawImage(
            decorPath,
            -120 * scale,
            -120 * scale,
            240 * scale,
            240 * scale,
          );
          ctx.restore();
        }
        uni.canvasToTempFilePath({
          canvas: canvas, // Canvas 2D 必须传 canvas 实例
          width: 600,
          height: 600,
          destWidth: 600,
          destHeight: 600,
          success: (res) => {
            if (save) saveImage(res.tempFilePath);
            resolve(res.tempFilePath);
          },
          fail: (err) => reject(err),
        });
        // ctx.draw(false, () => {
        //   uni.canvasToTempFilePath({
        //     canvasId: "avatarCanvas",
        //     success: (res) => {
        //       uni.saveImageToPhotosAlbum({
        //         filePath: res.tempFilePath,
        //         success: () => {
        //           uni.showToast({ title: "已保存到相册", icon: "success" });
        //         },
        //       });
        //     },
        //   });
        // });
      });
  });
};

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

const saveAndUse = async () => {
  if (!isLoggedIn.value) {
    loginPopupRef.value.open();
    return;
  }
  const abilityRes = await abilityCheck("avatar_download");
  if (!abilityRes.canUse) {
    if (
      abilityRes?.blockType === "need_share" &&
      abilityRes?.message === "分享可继续"
    ) {
      uni.showToast({
        title: "分享到群聊可继续使用",
        icon: "none",
      });
      return;
    }
    uni.showToast({
      title: "您今日头像下载次数已用完，明日再试",
      icon: "none",
    });
    return;
  }

  const tempPath = await saveByCanvas(true);
  const id = createAvatarId();
  saveRecordRequest(tempPath, id, "avatar_download");
  completeCardInfo(id);
  return;
  // 调用avatarDownloadRecord API记录下载次数
  // await avatarDownloadRecord({
  //   avatarUrl: currentAvatar.value,
  // });
  // saveRecordRequest('', )
  // const ctx = uni.createCanvasContext("avatarCanvas");
  // const size = 600;
  // const avatarPath = await loadImage(currentAvatar.value);
  // ctx.clearRect(0, 0, size, size);
  // ctx.drawImage(avatarPath, 0, 0, size, size);
  // if (selectedFrame.value) {
  //   const framePath = await loadImage(selectedFrame.value);
  //   ctx.drawImage(framePath, 0, 0, size, size);
  // }
  // if (selectedDecor.value) {
  //   const decorPath = await loadImage(selectedDecor.value);
  //   ctx.save();
  //   // 映射 rpx 坐标到 Canvas 坐标 (假设 1rpx = 1 unit for 600x600 canvas logic)
  //   // Canvas size is 600, Preview is 600rpx. Ratio is 1:1 in logical space.
  //   ctx.translate(decorState.value.x, decorState.value.y);
  //   ctx.rotate((decorState.value.rotate * Math.PI) / 180);
  //   const scale = decorState.value.scale;
  //   // 绘制图片，宽高 240
  //   ctx.drawImage(
  //     decorPath,
  //     -120 * scale,
  //     -120 * scale,
  //     240 * scale,
  //     240 * scale,
  //   );
  //   ctx.restore();
  // }
  // ctx.draw(false, () => {
  //   uni.canvasToTempFilePath({
  //     canvasId: "avatarCanvas",
  //     success: (res) => {
  //       uni.saveImageToPhotosAlbum({
  //         filePath: res.tempFilePath,
  //         success: () => {
  //           uni.showToast({ title: "已保存到相册", icon: "success" });
  //         },
  //       });
  //     },
  //   });
  // });
};

const completeCardInfo = async (id) => {
  const tempPath = await saveByCanvas(false);
  const imageUrl = await uploadImage(tempPath);
  avatarCreateComplete({
    id,
    imageUrl,
    avatarId: currentAvatar?.value?.id,
    decorId: selectedDecor?.value?.id,
    frameId: selectedFrame?.value?.id,
  });
  return imageUrl;
};

onShareAppMessage(async () => {
  getShareReward({ scene: "avatar_download" });
  if (!isLoggedIn.value) {
    const shareTokenRes = await getShareToken("avatar_download_not_login", "");
    return {
      title: "新春祝福",
      path: `/pages/index/index?shareToken=${shareTokenRes.shareToken}`,
    };
  }
  uni.showLoading({ title: "分享中...", mask: true });
  const id = createAvatarId();
  const shareTokenRes = await getShareToken("avatar_download", id);
  const imageUrl = await completeCardInfo(id);
  uni.hideLoading();
  return {
    title: "我做了一个新头像，真的太好看了",
    path: `/pages/avatar/detail?shareToken=${shareTokenRes.shareToken}`,
    imageUrl, // 使用默认封面或 popularCards 的封面
  };
});

// onShareTimeline(() => {
//   return {
//     title: "制作我的新春头像",
//     imageUrl:
//       "https://file.lihailezzc.com/resource/b48c41054c2633c478463ac1b1f1ca23.png",
//   };
// });
</script>

<style lang="scss" scoped>
.avatar-page {
  min-height: 100vh;
  background: #f8f8f8;
  padding-bottom: 200rpx;
}

.top-steps {
  background: #fff;
  padding: 30rpx 0;
  margin-bottom: 20rpx;
  position: sticky;
  z-index: 100;

  .step-bar {
    display: flex;
    justify-content: center;
    align-items: center;
    padding: 0 40rpx;
  }

  .step-item {
    display: flex;
    flex-direction: column;
    align-items: center;
    position: relative;
    flex: 1;

    .step-num-wrap {
      display: flex;
      align-items: center;
      width: 100%;
      justify-content: center;
      margin-bottom: 12rpx;
    }

    .step-line {
      position: absolute;
      left: -50%;
      right: 50%;
      top: 20rpx;
      height: 2rpx;
      background: #eee;
      z-index: 1;
    }

    .step-num {
      width: 40rpx;
      height: 40rpx;
      background: #f5f5f5;
      border-radius: 50%;
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: 20rpx;
      color: #999;
      position: relative;
      z-index: 2;
      transition: all 0.3s;
    }

    .step-text {
      font-size: 24rpx;
      color: #999;
      transition: all 0.3s;
    }

    &.active {
      .step-num {
        background: #ff3b30;
        color: #fff;
        transform: scale(1.2);
        box-shadow: 0 4rpx 12rpx rgba(255, 59, 48, 0.3);
      }
      .step-text {
        color: #ff3b30;
        font-weight: bold;
      }
    }
  }
}

.preview-card {
  background: #fff;
  margin: 0 30rpx 30rpx;
  padding: 40rpx;
  border-radius: 32rpx;
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05);

  .premium-tag {
    position: absolute;
    top: 20rpx;
    right: 0rpx;
    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);
  }

  .preview-square {
    position: relative;
    width: 600rpx;
    height: 600rpx;
    background: #fff;
    border-radius: 32rpx;
    overflow: hidden;
    box-shadow: 0 8rpx 30rpx rgba(0, 0, 0, 0.1);

    .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: 10;
    }

    .avatar-img {
      width: 100%;
      height: 100%;
    }

    .frame-img {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      z-index: 2;
    }

    .decor-img {
      position: absolute;
      width: 240rpx;
      height: 240rpx;
      z-index: 3;
      top: 0;
      left: 0;
    }
  }

  .interaction-tip {
    margin-top: 30rpx;
    font-size: 24rpx;
    color: #ff3b30;
    background: rgba(255, 59, 48, 0.1);
    padding: 10rpx 30rpx;
    border-radius: 100rpx;

    .tip-divider {
      margin: 0 15rpx;
      opacity: 0.3;
    }
  }

  .preview-tip {
    margin-top: 30rpx;
    font-size: 24rpx;
    color: #999;
  }
}

.action-buttons {
  padding: 0 30rpx;
  display: flex;
  gap: 20rpx;
  margin-bottom: 30rpx;

  .btn {
    flex: 1;
    height: 88rpx;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 44rpx;
    font-size: 30rpx;
    font-weight: bold;

    &.primary {
      background: #ff3b30;
      color: #fff;
    }

    &.secondary {
      background: #fff;
      color: #333;
      border: 2rpx solid #eee;
    }
  }
}

.resource-selector {
  background: #fff;
  margin: 0 30rpx 30rpx;
  padding: 30rpx;
  border-radius: 32rpx;
  box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05);

  .section-title {
    font-size: 30rpx;
    font-weight: bold;
    margin-bottom: 24rpx;
    color: #333;
    display: flex;
    align-items: center;

    &::before {
      content: "";
      width: 8rpx;
      height: 32rpx;
      background: #ff3b30;
      border-radius: 4rpx;
      margin-right: 16rpx;
    }
  }
}

.grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 20rpx;

  .grid-item {
    aspect-ratio: 1;
    background: #f5f5f5;
    border-radius: 20rpx;
    overflow: hidden;
    position: relative;
    border: 4rpx solid transparent;

    &.active {
      border-color: #ff3b30;
    }

    .grid-img {
      width: 100%;
      height: 100%;
    }

    .check {
      position: absolute;
      top: 0;
      right: 0;
      background: #ff3b30;
      color: #fff;
      font-size: 20rpx;
      padding: 4rpx 8rpx;
      border-radius: 0 0 0 16rpx;
    }

    &.upload-card {
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      background: #fdf2f2;
      border: 2rpx dashed #ffcbcb;

      .wechat-avatar-btn {
        width: 100%;
        height: 100%;
        padding: 0;
        background: transparent;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        line-height: 1.2;

        &::after {
          border: none;
        }
      }

      .upload-icon {
        font-size: 40rpx;
        margin-bottom: 8rpx;
      }

      .upload-text {
        font-size: 20rpx;
        color: #ff3b30;
      }
    }
  }
}

.loading-more,
.no-more {
  text-align: center;
  font-size: 24rpx;
  color: #999;
  padding: 30rpx 0;
}

.hidden-canvas {
  position: fixed;
  left: -9999px;
  top: -9999px;
}
</style>
"}]} ```
