<template>
  <view class="page">
    <image
      class="bg-wrapper"
      src="/static/castlove/beijingban.png"
      mode="aspectFill"
    ></image>
    <view class="main-container">
      <view
        class="cards-container"
        @touchstart="onTouchStart"
        @touchmove="onTouchMove"
        @touchend="onTouchEnd"
      >
        <!-- 1. 加载中:背景图照常显示,卡片区显示半透明 loading,不要白屏 -->
        <view v-if="loading" class="loading-state">
          <image class="loading-spinner" src="/static/common/loading.png" />
        </view>

        <!-- 2. 加载失败:点击重试 -->
        <view v-else-if="loadError" class="error-state" @tap="loadConfig">
          <text class="error-text">{{ loadError }}</text>
          <text class="error-hint">点击重试</text>
        </view>

        <!-- 3. 全空:后台把所有分类都软删了 -->
        <view v-else-if="categories.length === 0" class="empty-state">
          <image class="empty-state-icon" src="/static/castlove/jinqingqidai.png" mode="aspectFit" />
          <text class="empty-state-title">暂无内容</text>
        </view>

        <!-- 4. 某分类下卡片为空 -->
        <view v-else-if="currentCardList.length === 0" class="empty-state">
          <image class="empty-state-icon" src="/static/castlove/jinqingqidai.png" mode="aspectFit" />
          <text class="empty-state-title">{{ currentCategoryName }}敬请期待</text>
        </view>

        <!-- 5. 正常:渲染卡片 -->
        <view v-else>
          <view
            v-for="(card, index) in currentCardList"
            :key="card.id"
            class="card-item"
            :class="{ 'no-transition': disableTransition }"
            :style="getCardStyle(index)"
          >
            <view
              class="card-frame"
              :class="{
                'no-border': !card.route_path,
                'card-frame--tappable': !!card.route_path,
              }"
              @tap.stop="onCardFrameTap(card)"
            >
              <image
                class="card-image"
                :src="card.image_url"
                mode="aspectFill"
                @error="onImageError"
              />
              <!-- "开发中"角标:仅当卡片名就是"开发中"时才显示(避免对其他未配置路由的卡片误显示) -->
              <image
                v-if="card.name === '开发中'"
                class="coming-soon-badge"
                src="/static/castlove/jinqingqidai.png"
              />
            </view>
            <text class="card-name">{{ card.name }}</text>
          </view>
        </view>
      </view>

      <!-- 右侧分类菜单:仅在数据正常时显示 -->
      <view
        v-if="!loading && !loadError && categories.length"
        class="text-panel"
      >
        <view
          class="arrow-btn arrow-up"
          :class="{ 'arrow-btn--disabled': selectedCategoryIndex === 0 }"
          @click="scrollUp"
        >
          <image
            class="arrow-icon"
            src="/static/castlove/jiantou.png"
            style="transform: rotate(180deg)"
          />
        </view>
        <view class="text-list">
          <view
            v-for="(category, index) in categories"
            :key="category.id"
            class="text-item"
            :class="{ active: selectedCategoryIndex === index }"
            @click="selectCategory(index)"
          >
            <text>{{ category.name }}</text>
          </view>
        </view>
        <view
          class="arrow-btn arrow-down"
          :class="{
            'arrow-btn--disabled':
              selectedCategoryIndex === categories.length - 1,
          }"
          @click="scrollDown"
        >
          <image class="arrow-icon" src="/static/castlove/jiantou.png" />
        </view>
      </view>
    </view>
  </view>
</template>

<script>
import { getCastloveConfigApi } from "@/utils/api.js";

export default {
  // 作为组件被 mall.vue 引入时的入参
  // (作为页面被 navigateTo 直接打开时不传值,走 onLoad 读取 URL 参数)
  props: {
    // 初始分类:star_card | badge | poster
    type: {
      type: String,
      default: "",
    },
  },
  watch: {
    // 关键入口:组件模式下(被 mall.vue 引用),onLoad 不会触发
    // 必须在这里同时拉配置 + 应用 type。immediate: true 保证 mount 时就跑一次
    type: {
      immediate: true,
      async handler(val) {
        // 先等数据回来,再定位分类(findIndex 需要 categories 已加载)
        await this.loadConfig();
        this.applyType(val);
      },
    },
  },

  onShow() {
    try {
      uni.hideToast();
      uni.hideLoading();
    } catch (e) {}
  },

  // 作为页面被直接打开(不走 mall.vue)的兜底入口
  // 作为组件被 mall.vue 引入时,onLoad 不会触发,由 watch.type 接管
  async onLoad(options) {
    await this.loadConfig();
    if (options && options.type) {
      this.applyType(options.type);
    }
  },

  data() {
    return {
      // 是否显示右侧分类菜单栏
      // - 作为组件(mall.vue 中)使用时,默认 true
      // - 作为页面被直接打开时,onLoad 会把它置为 false
      showMenu: true,
      selectedCategoryIndex: 0,

      // ↓ 全部来自后端,含 route_path / route_params
      // [{ id, name, type_key, sort_order, crafts: [{ id, name, image_url, route_path, route_params, sort_order }] }]
      categories: [],
      loading: true,
      loadError: "",

      // 原有交互/动效状态保留
      selectedIndex: 1, // 默认第 2 张(切换分类时由 defaultSelectedIndex 动态重算)
      touchStartY: 0,
      dragOffset: 0,
      isDragging: false,
      disableTransition: false,
      SWIPE_STEP: 100,
    };
  },

  computed: {
    currentCategoryName() {
      return this.categories[this.selectedCategoryIndex]?.name || "";
    },
    currentCardList() {
      return this.categories[this.selectedCategoryIndex]?.crafts || [];
    },
    currentCardCount() {
      return this.currentCardList.length;
    },
    currentCenterIndex() {
      return Math.floor(this.currentCardCount / 2);
    },
    // 切换分类时的默认选中卡片
    // 原本固定 = 1(默认第 2 张),但卡片数 < 2 时会越界
    // 卡片 0 张 → 0;卡片 1 张 → 0;卡片 ≥ 2 张 → 1
    // 后台动态删卡也安全:卡片数变化后重新计算
    defaultSelectedIndex() {
      return Math.min(1, Math.max(0, this.currentCardCount - 1));
    },
  },

  methods: {
    /**
     * 拉取后端配置(进入页面 / 点击重试时调用)
     * 强制鉴权(token 由 utils/api.js 统一注入)
     */
    async loadConfig() {
      try {
        this.loading = true;
        this.loadError = "";
        const res = await getCastloveConfigApi();
        this.categories = (res && res.data && res.data.categories) || [];
      } catch (e) {
        this.loadError = e?.message || "配置加载失败";
        this.categories = [];
      } finally {
        this.loading = false;
      }
    },

    /**
     * 根据 type 字符串定位到对应分类索引
     * 在线 findIndex(不再依赖前端硬编码的 categoryTypeMap)
     */
    applyType(type) {
      if (!type) return;
      const idx = this.categories.findIndex((c) => c.type_key === type);
      if (idx >= 0) this.selectedCategoryIndex = idx;
      // 找不到则保持 0,不报错
    },

    /** 切换大分类 */
    selectCategory(index) {
      this.selectedCategoryIndex = index;
      // 用计算属性而不是写死 1(防止卡片数 < 2 越界)
      this.selectedIndex = this.defaultSelectedIndex;
      this.dragOffset = 0;
      this.isDragging = false;
    },

    /** 触摸开始 */
    onTouchStart(e) {
      this.touchStartY = e.touches[0].clientY;
      this.isDragging = true;
      this.disableTransition = true;
    },

    /** 触摸移动 */
    onTouchMove(e) {
      if (!this.isDragging) return;
      const moveY = e.touches[0].clientY;
      this.dragOffset = moveY - this.touchStartY;
    },

    /** 触摸结束 - 切换卡片 */
    onTouchEnd() {
      if (!this.isDragging) return;
      this.isDragging = false;
      this.disableTransition = false;

      const N = this.currentCardCount;
      if (N === 0) return;

      const moveCount = Math.round(-this.dragOffset / this.SWIPE_STEP);
      let newIdx = this.selectedIndex + moveCount;
      newIdx = ((newIdx % N) + N) % N;
      this.selectedIndex = newIdx;
      this.dragOffset = 0;
    },

    // ====================== 核心修复:z-index + 层级 + 循环 ======================
    // 返回当前分类对应的扇形位置
    // 规则:基础 5 个位置保持原样不动
    //  - N <= 5:取前 N 个
    //  - N  > 5:基础 5 个 + (N-5) 个在末尾沿用底部样式追加
    // 这样新增/删减小类型卡片时,既有的位置不会被打乱重组
    getStackPositions(count) {
      if (count <= 0) return [];
      // 基础 5 张卡片的扇形布局(保持原状)
      const basePositions = [
        { left: 288, top: 64, rotate: 25, scale: 0.75 },
        { left: 120, top: 288, rotate: 12, scale: 0.95 },
        { left: 60, top: 580, rotate: 0, scale: 1 },
        { left: 120, top: 888, rotate: -12, scale: 0.95 },
        { left: 224, top: 1096, rotate: -25, scale: 0.75 },
      ];
      if (count <= basePositions.length) {
        // 卡片少于 5 张:直接取前 N 个,不动基础数组
        return basePositions.slice(0, count);
      }
      // 卡片多于 5 张:在末尾追加,沿用第 5 张的样式继续向下延伸
      const positions = [...basePositions];
      const tail = basePositions[basePositions.length - 1];
      for (let i = basePositions.length; i < count; i++) {
        const extra = i - basePositions.length + 1;
        positions.push({
          left: tail.left,
          top: tail.top + extra * 208, // 沿用 888→1096 的间距
          rotate: tail.rotate - extra * 12, // 沿用 -12°→-25° 的旋转步长
          scale: tail.scale,
        });
      }
      return positions;
    },

    getCardStyle(index) {
      const N = this.currentCardCount;
      if (N === 0) return {};

      const positions = this.getStackPositions(N);
      const centerInt = this.currentCenterIndex; // 扇形中心索引(N=5→2;N=4→2;N=6→3)
      const centerPos = positions[centerInt] ?? positions[0];

      const progress = -this.dragOffset / this.SWIPE_STEP;
      const centerIdx = this.selectedIndex + progress;

      // 循环最短差值(关键):以 N/2 作为环绕阈值,适配任意 N
      let diff = index - centerIdx;
      const half = N / 2;
      if (diff > half) diff -= N;
      if (diff < -half) diff += N;
      const cardPos = diff + centerInt;

      // 插值计算(支持首尾环绕)
      let pos;
      const lowerRaw = Math.floor(cardPos);
      const t = cardPos - lowerRaw;
      const lowerIdx = ((lowerRaw % N) + N) % N;
      const upperIdx = (lowerIdx + 1) % N;

      if (t === 0 && lowerIdx >= 0 && lowerIdx < N) {
        pos = positions[lowerIdx] ?? centerPos;
      } else {
        const p = positions[lowerIdx] ?? centerPos;
        const n = positions[upperIdx] ?? centerPos;
        pos = {
          left: p.left + (n.left - p.left) * t,
          top: p.top + (n.top - p.top) * t,
          rotate: p.rotate + (n.rotate - p.rotate) * t,
          scale: p.scale + (n.scale - p.scale) * t,
        };
      }

      // ====================== Z‑INDEX 终极修复 ======================
      const distance = Math.abs(cardPos - centerInt);
      const zIndex = Math.round(100 - distance * 30); // 越靠近中间层级越高
      const isCenter = distance < 0.02;

      if (isCenter) {
        return {
          left: pos.left + "rpx",
          top: pos.top + "rpx",
          transform: `scale(${pos.scale * 1.15}) rotate(${pos.rotate}deg)`,
          zIndex: 999, // 中心永远最高
        };
      }

      return {
        left: pos.left + "rpx",
        top: pos.top + "rpx",
        transform: `scale(${pos.scale}) rotate(${pos.rotate}deg)`,
        zIndex,
      };
    },

    /** 当前叠卡在弧形布局中的槽位(2=正中,1=中上,0=最上...) */
    getCardStackPosition(index) {
      const N = this.currentCardCount;
      if (N === 0) return 0;
      const centerInt = this.currentCenterIndex;
      const centerIdx = this.selectedIndex + -this.dragOffset / this.SWIPE_STEP;
      let diff = index - centerIdx;
      const half = N / 2;
      if (diff > half) diff -= N;
      if (diff < -half) diff += N;
      return diff + centerInt;
    },

    /**
     * 点击卡图区域
     * - 正中主图(槽位 ≈ 中心)→ 读 card.route_path / route_params 跳转
     * - 其余叠层 → 仅切换选中(把卡片移到中间)
     *
     * 跳转规则:
     * 1. route_path 为空/null → 弹 "激情开发中" toast,不跳转
     * 2. route_path 非空 → 拼上 route_params 作为 query
     *    目标页面必须在 pages.json 中已注册,否则 uni.navigateTo 失败 → 弹 "页面不存在" toast
     */
    onCardFrameTap(card) {
      if (!card) return;
      const pos = this.getCardStackPosition(this.currentCardList.indexOf(card));
      // 只处理正中位置
      if (Math.abs(pos - this.currentCenterIndex) >= 0.2) {
        this.selectedIndex = this.currentCardList.indexOf(card);
        return;
      }
      // 1. route_path 为空/null → toast
      if (!card.route_path) {
        uni.showToast({ title: "激情开发中", icon: "none" });
        return;
      }
      // 2. 拼 query
      // const query = this.buildQueryString(card.route_params);
      // const url = query ? `${card.route_path}?name=${encodeURIComponent(card.name)}` : card.route_path;
      const url = `${card.route_path}?name=${encodeURIComponent(card.name)}`;
      console.log(url)
      uni.navigateTo({
        url,
        fail: (err) => {
          // 路径写错 / pages.json 未注册 → 兜底 toast,不闪退
          console.error("[castlove] navigateTo fail", card.route_path, err);
          uni.showToast({ title: "功能待开发", icon: "none" });
        },
      });
    },

    /**
     * 把 route_params(JSON 字符串或对象)转成 query string
     * - null/undefined/空对象 → ""
     * - 嵌套对象/数组已被后端兜底清空,这里再做一次防御性过滤
     */
    buildQueryString(params) {
      if (!params) return "";
      // 后端统一返回 JSON 字符串;同时兼容前端 mock 或老代码传对象的情况
      let obj = params;
      if (typeof params === "string") {
        try {
          obj = JSON.parse(params);
        } catch (e) {
          return "";
        }
      }
      if (!obj || typeof obj !== "object" || Array.isArray(obj)) return "";
      return Object.keys(obj)
        .filter(
          (k) =>
            obj[k] !== undefined &&
            obj[k] !== null &&
            typeof obj[k] !== "object"
        )
        .map(
          (k) =>
            `${encodeURIComponent(k)}=${encodeURIComponent(String(obj[k]))}`
        )
        .join("&");
    },

    /** 图片加载失败兜底 */
    onImageError(e) {
      console.warn("[craft-select] image load failed", e);
      // 这里如果以后想换占位图,直接换 src
    },

    /** 右侧菜单上箭头 */
    scrollUp() {
      if (this.selectedCategoryIndex > 0) {
        this.selectCategory(this.selectedCategoryIndex - 1);
      }
    },

    /** 右侧菜单下箭头 */
    scrollDown() {
      if (this.selectedCategoryIndex < this.categories.length - 1) {
        this.selectCategory(this.selectedCategoryIndex + 1);
      }
    },
  },
};
</script>

<style lang="scss" scoped>
.page {
  height: 100vh;
  position: relative;
  overflow: hidden;
}

.bg-wrapper {
  position: fixed;
  top: -16rpx;
  left: 0;
  width: 100%;
  height: 110%;
  z-index: 0;
}

.main-container {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  display: flex;
  z-index: 10;
}

.cards-container {
  flex: 1;
  position: relative;
}

.card-item {
  position: absolute;
  width: 312rpx;
  height: 312rpx;
  transition: all 0.5s cubic-bezier(0.4, 0, 0.2, 1);
  will-change: transform, z-index;
}

.card-item.no-transition {
  transition: none !important;
}

.card-frame {
  position: relative;
  width: 100%;
  height: 100%;
  border-radius: 24rpx;
  padding: 24rpx;
  background-image: url("/static/square/cangpinkuang1.png");
  background-size: cover;
}

.card-frame.no-border {
  background-image: none;
}

.card-frame--tappable {
  cursor: pointer;
}

.card-image {
  width: 100%;
  height: 100%;
  border-radius: 24rpx;
  object-fit: cover;
}

.coming-soon-badge {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 160rpx;
  height: 160rpx;
}

.card-name {
  position: absolute;
  bottom: -16rpx;
  left: 32rpx;
  background: linear-gradient(
    93.1deg,
    rgba(224, 180, 247, 0.71) -12.06%,
    rgba(178, 246, 204, 0.71) 52.09%,
    rgba(98, 178, 244, 0.71) 163.5%
  );
  backdrop-filter: blur(11.699999809265137px);
  color: #fffabd;
  text-shadow: -1px 1px 4px #ce0909d6;
  font-size: 28rpx;
  font-weight: 400;
  padding: 0 16rpx;
  border-radius: 16rpx;
}

// ===== 5 个状态分支(loading / error / empty / 正常)=====
.loading-state {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
}

.loading-spinner {
  width: 96rpx;
  height: 96rpx;
  opacity: 0.7;
}

.error-state {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: 80%;
  pointer-events: auto;
}

.error-text {
  color: #fff;
  font-size: 32rpx;
  margin-bottom: 16rpx;
  text-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.35);
}

.error-hint {
  color: rgba(255, 255, 255, 0.7);
  font-size: 26rpx;
}

// ===== 右侧分类菜单(自适应高度)=====
.text-panel {
  position: absolute;
  right: 30rpx;
  top: 50%;
  transform: translateY(-50%);
  width: 200rpx;
  min-height: 392rpx; // 保留 3 项时的视觉高度
  max-height: 80vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background: url("/static/castlove/xiahualan.png") no-repeat center;
  background-size: 130%;
  border-radius: 20rpx;
  padding: 16rpx 0;
}

.arrow-btn {
  width: 60rpx;
  height: 32rpx;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0.8;
}

.arrow-btn--disabled {
  opacity: 0.25;
  pointer-events: none; // 已禁用时不再触发点击
}

.arrow-icon {
  width: 48rpx;
  height: 48rpx;
}

.text-list {
  display: flex;
  flex-direction: column;
  padding: 0 20rpx;
  // 超过 5 项时启用滚动(spec §6.7)
  max-height: 60vh;
  overflow-y: auto;
}

.text-item {
  color: #fff;
  font-size: 28rpx; // 统一字号,不再写 font-large / font-mid
  font-weight: 500;
  padding: 14rpx 20rpx;
  border-radius: 14rpx;
  display: flex;
  justify-content: center;
  transition: font-size 0.2s;
}

.text-item.active {
  font-weight: bold;
  font-size: 34rpx; // 选中项放大(spec §6.7)
  background: url("/static/nft/dingbutubiao_liang.png") no-repeat center;
  background-size: 100% 100%;
}

.empty-state {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: 80%;
  padding: 40rpx 0;
  pointer-events: none;
}

.empty-state-icon {
  width: 200rpx;
  height: 200rpx;
  opacity: 0.85;
  margin-bottom: 32rpx;
}

.empty-state-title {
  color: #fff;
  font-size: 36rpx;
  font-weight: 600;
  margin-bottom: 16rpx;
  text-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.35);
}

.empty-state-desc {
  color: rgba(255, 255, 255, 0.7);
  font-size: 26rpx;
  text-align: center;
}
</style>
