<script setup>
import { computed, ref, onBeforeUnmount } from "vue";
import { onShow } from "@dcloudio/uni-app";
import Container from "@/components/Container.vue";
import Signin from "@/components/Signin.vue";
import { createOrderAPI, getAppConfig, getHomeData } from "@/apis";
import { capsuleHeight } from "@/util";
import useStore from "@/store";
import { storeToRefs } from "pinia";

const store = useStore();
const { user, config } = storeToRefs(store);
const { updateConfig, updateUser } = store;

const currentTypeIndex = ref(1);
const selectedPackageIndex = ref(0);
const showModal = ref(false);
const loadingConfig = ref(false);
const paying = ref(false);
const refreshing = ref(false);
const timer = ref(null);
const lastDate = ref(user.value.expiredAt || 0);
const maxRefreshTimes = 12;

// 会员页核心展示数据：视觉、权益、套餐均按蓝湖当前两张设计稿拆分。
const memberTypes = [
  {
    key: "normal",
    tab: "VIP",
    title: "普通会员",
    prefix: "成为射灵星球",
    desc: "特享约战竞技次数包、专属会员标识",
    benefitTitle: "普通会员专属权益",
    themeClass: "vip-page--normal",
    heroCard: "https://static.shelingxingqiu.com/shootmini/static/vip/vip-title.png",
    activeHeroCard: "https://static.shelingxingqiu.com/shootmini/static/vip/vip-title2.png",
    orderIcon: "../../static/vip/vip-order.png",
    heroBadge: "../../static/vip/normal-hero-badge.png",
    buttonClass: "activate-btn--normal",
    benefits: [
      { label: "专属会员标识", icon: "../../static/vip/vip-badge.png" },
      { label: "教练点评", icon: "../../static/vip/vip-comment.png" },
      { label: "专享VIP客服", icon: "../../static/vip/vip-service.png" },
      { label: "排位赛\n每日+20次", icon: "../../static/vip/vip-rank.png" },
      { label: "约战\n每日+20次", icon: "../../static/vip/vip-battle.png" },
    ],
    packages: [
      { name: "连续包月", price: "20", original: "35" },
      { name: "12个月", price: "300", original: "420" },
      { name: "3个月", price: "84", original: "105" },
    ],
  },
  {
    key: "super",
    tab: "SVIP",
    title: "超级会员",
    prefix: "成为射灵星球",
    desc: "尊享专属特效、无限制约战竞技、专属会员标识",
    benefitTitle: "超级会员专属权益",
    themeClass: "vip-page--super",
    heroCard: "https://static.shelingxingqiu.com/shootmini/static/vip/svip-title.png",
    activeHeroCard: "https://static.shelingxingqiu.com/shootmini/static/vip/svip-title2.png",
    orderIcon: "../../static/vip/svip-order.png",
    heroBadge: "../../static/vip/super-hero-badge.png",
    buttonClass: "activate-btn--super",
    benefits: [
      { label: "专属落点标识", icon: "../../static/vip/svip-point.png" },
      { label: "专属命中效果", icon: "../../static/vip/svip-hit.png" },
      { label: "专属射箭效果", icon: "../../static/vip/svip-arrow.png" },
      { label: "专属会员标识", icon: "../../static/vip/svip-badge.png" },
      { label: "教练点评", icon: "../../static/vip/svip-comment.png" },
      { label: "约战无限制", icon: "../../static/vip/svip-battle.png" },
      { label: "排位赛无限制", icon: "../../static/vip/svip-rank.png" },
      { label: "专享SVIP客服", icon: "../../static/vip/svip-service.png" },
    ],
    packages: [
      { name: "连续包月", price: "20", original: "35" },
      { name: "12个月", price: "300", original: "420" },
      { name: "3个月", price: "84", original: "105" },
    ],
  },
];

const currentType = computed(() => memberTypes[currentTypeIndex.value]);

// 后端到期时间可能是秒级时间戳、毫秒级时间戳或日期字符串，这里统一转成毫秒。
const toTimestamp = (value) => {
  if (!value) return 0;
  const numberValue = Number(value);
  if (!Number.isNaN(numberValue)) {
    return numberValue < 1000000000000 ? numberValue * 1000 : numberValue;
  }
  const time = new Date(value).getTime();
  return Number.isNaN(time) ? 0 : time;
};

// 当前卡片只关心本 tab 对应的会员到期时间，普通会员和超级会员互不兜底。
const getVipExpiredValue = (type, source = user.value) => {
  if (!source) return 0;
  return type.key === "super" ? source.superVipExpiredAt : source.normalVipExpiredAt;
};

// 支付后轮询需要比较最新会员到期时间，兼容旧字段 expiredAt。
const getLatestVipExpiredTime = (source = user.value) => {
  if (!source) return 0;
  return Math.max(
    toTimestamp(source.normalVipExpiredAt),
    toTimestamp(source.superVipExpiredAt),
    toTimestamp(source.expiredAt)
  );
};

// 未过期才展示“会员生效中”样式，已过期或无值继续展示未开通样式。
const isVipActive = (type) => {
  return toTimestamp(getVipExpiredValue(type)) > Date.now();
};

// 会员卡片展示完整到期时间。
const formatVipDate = (value) => {
  const timestamp = toTimestamp(value);
  if (!timestamp) return "";
  const date = new Date(timestamp);
  const year = date.getFullYear();
  const month = String(date.getMonth() + 1).padStart(2, "0");
  const day = String(date.getDate()).padStart(2, "0");
  const hour = String(date.getHours()).padStart(2, "0");
  const minute = String(date.getMinutes()).padStart(2, "0");
  const second = String(date.getSeconds()).padStart(2, "0");
  return `${year}-${month}-${day} ${hour}:${minute}:${second}`;
};

// 会员生效时使用 title2 切图，未生效时沿用原来的开通引导图。
const getHeroCard = (type) => {
  return isVipActive(type) ? type.activeHeroCard : type.heroCard;
};

const getActiveVipExpiredDate = (type) => {
  return formatVipDate(getVipExpiredValue(type));
};

// 设计稿里的“下期自动续费”按到期日前一天展示。
const getActiveVipRenewDate = (type) => {
  const timestamp = toTimestamp(getVipExpiredValue(type));
  if (!timestamp) return "";
  return formatVipDate(timestamp - 24 * 60 * 60 * 1000);
};

const configMenus = computed(() => {
  return config.value.vipMenus || [];
});

const getMenuName = (item) => {
  return item.name || item.vipName || item.title || "";
};

const getMenuPrice = (item) => {
  const value = item.price || item.total || item.amount || item.money;
  return value ? String(value).replace("￥", "").replace("¥", "") : "";
};

const getMenuType = (item) => {
  const vipType = Number(item.vipType);
  if (vipType === 1) return "normal";
  if (vipType === 2) return "super";

  const type = String(item.type || "").toLowerCase();
  if (["super", "svip"].includes(type)) return "super";
  if (["normal", "vip"].includes(type)) return "normal";

  const name = getMenuName(item);
  if (/超级|SVIP/i.test(name)) return "super";
  if (/普通|VIP|会员/i.test(name)) return "normal";
  return "";
};

const getPackageMonths = (name) => {
  if (/连续包月/.test(name)) return 1;
  const match = String(name || "").match(/(\d+)\s*个?月/);
  return match ? Number(match[1]) : 0;
};

const matchPackageSource = (type, pack, index) => {
  const menus = configMenus.value;
  const typedMenus = menus.filter((item) => {
    const menuType = getMenuType(item);
    if (type.key === "super") return menuType === "super";
    return menuType === "normal";
  });
  const pool = typedMenus.length ? typedMenus : menus;
  const packMonths = getPackageMonths(pack.name);
  return (
    pool.find((item) => getMenuName(item).indexOf(pack.name) !== -1) ||
    pool.find((item) => packMonths && getPackageMonths(getMenuName(item)) === packMonths) ||
    pool.find((item) => getMenuPrice(item) === pack.price) ||
    pool[index]
  );
};

const getPackages = (type) => {
  return type.packages.map((item, index) => {
    const source = matchPackageSource(type, item, index);
    return {
      ...item,
      source,
      name: source ? getMenuName(source) || item.name : item.name,
      price: source ? getMenuPrice(source) || item.price : item.price,
      icon: source && source.icon,
      id: source && source.id,
    };
  });
};

const currentPackages = computed(() => {
  return getPackages(currentType.value);
});

const selectedPackage = computed(() => {
  return currentPackages.value[selectedPackageIndex.value] || currentPackages.value[0];
});

const switchType = (index) => {
  currentTypeIndex.value = index;
  selectedPackageIndex.value = 0;
};

const onSwiperChange = (event) => {
  currentTypeIndex.value = event.detail.current;
  selectedPackageIndex.value = 0;
};

const selectPackage = (index) => {
  selectedPackageIndex.value = index;
};

const toPackageDesc = () => {
  uni.navigateTo({
    url: "/pages/member/vip-intro",
  });
};

const toOrderPage = () => {
  uni.navigateTo({
    url: "/pages/member/orders",
  });
};

const toAgreement = (type) => {
  uni.navigateTo({
    url: `/pages/member/agreement?type=${type}`,
  });
};

const loadVipConfig = async () => {
  if (loadingConfig.value || configMenus.value.length) return;
  loadingConfig.value = true;
  try {
    const result = await getAppConfig();
    if (result) updateConfig(result);
  } catch (error) {
    console.log("load vip config error", error);
  } finally {
    loadingConfig.value = false;
  }
};

const clearRefreshTimer = () => {
  if (timer.value) {
    clearInterval(timer.value);
    timer.value = null;
  }
};

const refreshUserAfterPay = () => {
  clearRefreshTimer();
  let refreshTimes = 0;
  // 先记录支付前的最大到期时间，轮询到更大的值就认为会员状态已刷新。
  lastDate.value = getLatestVipExpiredTime();
  refreshing.value = true;
  timer.value = setInterval(async () => {
    refreshTimes += 1;
    try {
      const result = await getHomeData();
      const latestExpiredAt = getLatestVipExpiredTime(result.user);
      if (result.user && latestExpiredAt > lastDate.value) {
        lastDate.value = latestExpiredAt;
        updateUser(result.user);
        clearRefreshTimer();
        refreshing.value = false;
      } else if (refreshTimes >= maxRefreshTimes) {
        clearRefreshTimer();
        refreshing.value = false;
      }
    } catch (error) {
      console.log("refresh user after pay error", error);
      if (refreshTimes >= maxRefreshTimes) {
        clearRefreshTimer();
        refreshing.value = false;
      }
    }
  }, 1000);
};

const onPay = async () => {
  if (paying.value || refreshing.value) return;
  if (!user.value.id) {
    showModal.value = true;
    return;
  }
  if (!configMenus.value.length) {
    await loadVipConfig();
  }
  const vipId = selectedPackage.value && selectedPackage.value.id;
  if (!vipId) {
    uni.showToast({
      title: loadingConfig.value ? "套餐配置加载中" : "套餐暂不可购买",
      icon: "none",
    });
    return;
  }
  paying.value = true;
  let waitingPayment = false;
  try {
    const result = await createOrderAPI(vipId);
    const params = result?.pay?.order?.jsApi?.params;
    if (!params?.timeStamp || !params?.nonceStr || !params?.package || !params?.paySign) {
      uni.showToast({
        title: "支付参数生成失败",
        icon: "none",
      });
      refreshing.value = false;
      return;
    }
    waitingPayment = true;
    wx.requestPayment({
      timeStamp: params.timeStamp, // 微信支付时间戳
      nonceStr: params.nonceStr, // 微信支付随机串
      package: params.package, // 预支付交易会话标识
      paySign: params.paySign, // 微信支付签名
      signType: params.signType || "RSA",
      success() {
        uni.showToast({
          title: "支付成功",
          icon: "none",
        });
        refreshUserAfterPay();
      },
      fail(res) {
        console.log("pay error", res);
        if (res.errMsg && res.errMsg.indexOf("cancel") !== -1) return;
        uni.showToast({
          title: "支付失败，请稍后重试",
          icon: "none",
        });
      },
      complete() {
        paying.value = false;
      },
    });
  } catch (error) {
    console.log("create vip order error", error);
  } finally {
    if (!waitingPayment) paying.value = false;
  }
};

onShow(loadVipConfig);

onBeforeUnmount(() => {
  clearRefreshTimer();
});
</script>

<template>
  <Container title="" :bgType="10" :scroll="false" :showBottom="false">
    <view class="vip-page" :class="currentType.themeClass">
      <view class="type-tabs" :style="{ top: capsuleHeight + 'px' }">
        <view
          v-for="(item, index) in memberTypes"
          :key="item.key"
          class="type-tab"
          :class="{ 'type-tab--active': currentTypeIndex === index }"
          @click="switchType(index)"
        >
          <text>{{ item.tab }}</text>
          <view class="type-tab__indicator" />
        </view>
      </view>
      <swiper
        class="type-swiper"
        :current="currentTypeIndex"
        :duration="260"
        @change="onSwiperChange"
      >
        <swiper-item v-for="type in memberTypes" :key="type.key">
          <scroll-view scroll-y class="type-scroll" :show-scrollbar="false">
            <view class="vip-content">
              <view
                class="hero-card"
                :class="{ 'hero-card--active': isVipActive(type) }"
              >
                <image class="hero-card__bg" :src="getHeroCard(type)" mode="scaleToFill" />
                <!-- 生效态卡片使用 title2 底图，补充有效期和订单入口叠层。 -->
                <view v-if="isVipActive(type)" class="hero-card__content">
                  <text class="hero-card__date">
                    有效期至：{{ getActiveVipExpiredDate(type) }}
                  </text>
                  <!-- <text v-if="type.key === 'super'" class="hero-card__renew">
                    下期会员将于：{{ getActiveVipRenewDate(type) }}自动续费
                  </text> -->
                  <view class="hero-card__order" @click.stop="toOrderPage">
                    <image class="hero-card__order-icon" :src="type.orderIcon" mode="aspectFit" />
                    <text>订单管理</text>
                  </view>
                </view>
              </view>

              <view class="benefit-title">
                <view class="benefit-title__line" />
                <text>{{ type.benefitTitle }}</text>
                <view class="benefit-title__line" />
              </view>

              <view class="benefit-grid" :class="{ 'benefit-grid--normal': type.key === 'normal' }">
                <view
                  v-for="benefit in type.benefits"
                  :key="benefit.label"
                  class="benefit-item"
                >
                  <view class="benefit-icon">
                    <image class="benefit-icon__img" :src="benefit.icon" mode="aspectFit" />
                  </view>
                  <text class="benefit-item__label">{{ benefit.label }}</text>
                </view>
              </view>

              <view class="package-header">
                <text class="package-header__title">选择套餐</text>
                <view class="package-header__link" @click="toPackageDesc">
                  <text>套餐说明</text>
                  <image
                    class="package-header__icon"
                    src="../../static/enter.png"
                    mode="aspectFit"
                  />
                </view>
              </view>

              <scroll-view scroll-x class="package-scroll" :show-scrollbar="false">
                <view class="package-list">
                  <view
                    v-for="(pack, index) in getPackages(type)"
                    :key="`${type.key}-${pack.name}`"
                    class="package-card"
                    :class="{ 'package-card--active': selectedPackageIndex === index }"
                    @click="selectPackage(index)"
                  >
                    <view class="package-card__inner">
                      <text class="package-name">{{ pack.name }}</text>
                      <view class="package-price">
                        <text class="package-price__symbol">¥</text>
                        <text class="package-price__value">{{ pack.price }}</text>
                      </view>
                      <view class="package-origin">
                        <text>¥{{ pack.original }}</text>
                        <view class="package-origin__line" />
                      </view>
                    </view>
                  </view>
                </view>
              </scroll-view>

              <button
                hover-class="none"
                class="activate-btn"
                :class="type.buttonClass"
                :disabled="loadingConfig || paying || refreshing"
                @click="onPay"
              >
                <text v-if="loadingConfig">加载套餐中</text>
                <text v-else-if="paying">创建订单中</text>
                <text v-else-if="!refreshing">¥ {{ selectedPackage.price }} 一键激活</text>
                <text v-else>刷新会员状态中</text>
              </button>

              <view class="agreement">
                <text>支付即同意</text>
                《&nbsp;<text class="agreement__link" @click.stop="toAgreement('renew')">会员自动续费服务协议</text>》
                《&nbsp;<text class="agreement__link" @click.stop="toAgreement('deduct')">扣款授权服务协议</text>》
              </view>
            </view>
          </scroll-view>
        </swiper-item>
      </swiper>
      <Signin :show="showModal" :onClose="() => (showModal = false)" />
    </view>
  </Container>
</template>

<style scoped>
.vip-page {
  position: relative;
  width: 100%;
  height: 100%;
}
.type-tabs {
  position: fixed;
  left: 0;
  z-index: 998;
  width: 50%;
  height: 50px;
  margin-left: 50%;
  transform:translateX(-60%);
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: auto;
}

.type-tab {
  width: 132rpx;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  color: rgba(255, 255, 255, 0.45);
  font-size: 34rpx;
  font-weight: 700;
  font-style: italic;
}

.type-tab__indicator {
  width: 40rpx;
  height: 4rpx;
  border-radius: 4rpx;
  margin-top: 8rpx;
  background-color: transparent;
}

.type-tab--active {
  color: #ffffff;
}

.vip-page--normal .type-tab--active .type-tab__indicator {
  background-color: #ffffff;
}

.vip-page--super .type-tab--active {
  color: #fedab5;
}

.vip-page--super .type-tab--active .type-tab__indicator {
  background-color: #fedab5;
}

.type-swiper {
  position: relative;
  z-index: 1;
  width: 100%;
  height: 100%;
}

.type-scroll {
  width: 100%;
  height: 100%;
}

.vip-content {
  min-height: 100%;
  padding: 32rpx 24rpx 52rpx;
  box-sizing: border-box;
}

.hero-card {
  position: relative;
  width: 702rpx;
  height: 260rpx;
  overflow: hidden;
}

.hero-card__bg {
  position: absolute;
  left: 0;
  top: 0;
  width: 702rpx;
  height: 260rpx;
}

.hero-card__content {
  position: relative;
  z-index: 1;
  /* 对齐 title2 切图左侧预留文案区域。 */
  padding: 132rpx 0 0 44rpx;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  box-sizing: border-box;
}

.hero-card__date,
.hero-card__renew {
  color: #8d6d55;
  font-size: 24rpx;
  line-height: 34rpx;
}

.vip-page--normal .hero-card__date,
.vip-page--normal .hero-card__renew {
  color: #555555;
}

.hero-card__order {
  display: flex;
  align-items: center;
  margin-top: 10rpx;
  color: #6d5644;
  font-size: 24rpx;
  line-height: 34rpx;
  text-decoration: underline;
}

.vip-page--normal .hero-card__order {
  color: #555555;
}

.hero-card__order-icon {
  width: 28rpx;
  height: 32rpx;
  margin-right: 8rpx;
  flex-shrink: 0;
}

.benefit-title {
  display: flex;
  align-items: center;
  justify-content: center;
  margin-top: 38rpx;
  color: #ffffff;
  font-size: 24rpx;
  line-height: 34rpx;
}

.benefit-title__line {
  width: 14rpx;
  height: 2rpx;
  background-color: #ffffff;
  margin: 0 10rpx;
}

.benefit-grid {
  display: flex;
  flex-wrap: wrap;
  width: 622rpx;
  margin: 38rpx auto 0;
}

.benefit-grid--normal {
  width: 672rpx;
}

.benefit-item {
  width: 144rpx;
  height: 122rpx;
  margin-right: 94rpx;
  margin-bottom: 30rpx;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.benefit-item:nth-child(3n) {
  margin-right: 0;
}

.benefit-grid--normal .benefit-item {
  margin-right: 120rpx;
}

.benefit-grid--normal .benefit-item:nth-child(3n) {
  margin-right: 0;
}

.benefit-icon {
  width: 80rpx;
  height: 80rpx;
  display: flex;
  align-items: center;
  justify-content: center;
}

.benefit-icon__img {
  width: 80rpx;
  height: 80rpx;
  display: block;
}

.benefit-item__label {
  margin-top: 8rpx;
  color: #ffffff;
  opacity: 0.7;
  font-size: 24rpx;
  line-height: 34rpx;
  text-align: center;
  white-space: pre-line;
}

.package-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: 56rpx;
  padding-right: 8rpx;
}

.benefit-grid--normal + .package-header {
  margin-top: 146rpx;
}

.package-header__title {
  color: #ffffff;
  font-size: 28rpx;
  line-height: 40rpx;
  font-weight: 500;
}

.vip-page--super .package-header__title {
  color: #e7ba80;
}

.package-header__link {
  display: flex;
  align-items: center;
  color: #999999;
  font-size: 22rpx;
  line-height: 32rpx;
}

.package-header__icon {
  width: 24rpx;
  height: 28rpx;
}

.package-scroll {
  width: 100%;
  margin-top: 40rpx;
  white-space: nowrap;
}

.package-list {
  display: flex;
  width: 984rpx;
  padding: 6rpx 84rpx 6rpx 6rpx;
  box-sizing: border-box;
}

.package-card {
  position: relative;
  width: 264rpx;
  height: 224rpx;
  border-radius: 16rpx;
  border: 2rpx solid #999999;
  margin-right: 32rpx;
  padding: 0;
  overflow: hidden;
  box-sizing: border-box;
  color: #999999;
}

.package-card__inner {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  border-radius: inherit;
}

.package-card--active {
  border-width: 6rpx;
  border-color: #fed847;
}

.vip-page--super .package-card--active {
  border: none;
  padding: 6rpx;
  background: linear-gradient(180deg, #fef3e6 0%, #f0c191 100%);
}

.vip-page--super .package-card--active .package-card__inner {
  border-radius: 10rpx;
  background-color: #050b19;
}

.package-name {
  font-size: 24rpx;
  line-height: 34rpx;
}

.package-price {
  display: flex;
  align-items: baseline;
  margin-top: 12rpx;
  color: #ffffff;
}

.package-card--active .package-price {
  color: #fed847;
}

.vip-page--super .package-card--active .package-price {
  color: #ffe8cd;
}

.package-price__symbol {
  font-size: 30rpx;
  line-height: 36rpx;
  font-weight: 700;
}

.package-price__value {
  font-size: 56rpx;
  line-height: 66rpx;
  font-weight: 700;
}

.package-origin {
  position: relative;
  margin-top: 2rpx;
  color: #999999;
  font-size: 24rpx;
  line-height: 34rpx;
}

.package-origin__line {
  position: absolute;
  left: -4rpx;
  right: -4rpx;
  top: 16rpx;
  height: 2rpx;
  background-color: #999999;
}

.activate-btn {
  width: 686rpx;
  height: 88rpx;
  border-radius: 44rpx;
  margin: 34rpx auto 0;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #000000;
  font-size: 30rpx;
  line-height: 42rpx;
  font-weight: 500;
}

.activate-btn::after {
  border: none;
}

.activate-btn--normal {
  background-color: #fed847;
}

.activate-btn--super {
  background: linear-gradient( 181deg, #FDFDFC 0%, #FDF8F2 0%, #FFC992 100%, #FFB96C 100%);
}

.agreement {
  display: flex;
  justify-content: center;
  align-items: center;
  margin-top: 24rpx;
  color: #999999;
  font-size: 20rpx;
  line-height: 28rpx;
}

.agreement__link {
  margin-left: -6rpx;
  text-decoration: underline;
}
</style>
