<template>
  <view class="page" :style="{ '--status-bar': statusBarHeight + 'px' }">
    <CustomNavBar title="订单管理" show-back />

    <!-- Summary stats bar -->
    <view class="stats-bar">
      <view class="stat-item">
        <text class="stat-num">{{ totalCount || '--' }}</text>
        <text class="stat-label">全部订单</text>
      </view>
      <view class="stat-divider" />
      <view class="stat-item">
        <text class="stat-num paid">{{ paidCount || '--' }}</text>
        <text class="stat-label">已支付</text>
      </view>
      <view class="stat-divider" />
      <view class="stat-item">
        <text class="stat-num pending">{{ pendingCount || '--' }}</text>
        <text class="stat-label">待支付</text>
      </view>
    </view>

    <!-- Status filter tabs -->
    <view class="filter-wrap">
      <scroll-view scroll-x class="filter-scroll" :show-scrollbar="false">
        <view class="filter-row">
          <view
            v-for="f in filters"
            :key="f.value"
            class="filter-pill"
            :class="{ active: activeFilter === f.value }"
            @tap="selectFilter(f.value)"
          >
            <text class="filter-pill-text">{{ f.label }}</text>
            <view v-if="f.count != null" class="filter-pill-dot" />
          </view>
        </view>
      </scroll-view>
    </view>

    <!-- Pull-to-refresh -->
    <scroll-view
      scroll-y
      class="list-scroll"
      :refresher-enabled="true"
      :refresher-triggered="refreshing"
      :lower-threshold="120"
      @refresherrefresh="onRefresh"
      @scrolltolower="loadMore"
    >
      <!-- Loading skeleton -->
      <view v-if="loading && !orders.length" class="order-list">
        <view v-for="i in 5" :key="i" class="skeleton-card" />
      </view>

      <!-- Empty -->
      <view v-else-if="!loading && !orders.length" class="empty-state">
        <view class="empty-illustration">
          <text class="empty-icon">📭</text>
        </view>
        <text class="empty-title">暂无订单</text>
        <text class="empty-sub">当前筛选条件下没有找到订单</text>
      </view>

      <!-- Order cards -->
      <view v-else class="order-list">
        <view
          v-for="(order, idx) in orders"
          :key="order.id"
          class="order-card"
          :class="{ 'order-card--paid': order.status === OrderStatus.PAID, 'order-card--pending': order.status === OrderStatus.PENDING }"
          :style="{ animationDelay: `${idx * 40}ms` }"
        >
          <!-- Card accent bar -->
          <view class="card-accent" :class="statusAccentClass(order.status)" />

          <!-- Card header -->
          <view class="card-header">
            <view class="card-title-row">
              <text class="card-plan">{{ order.cardType?.name ?? '未知套餐' }}</text>
              <view class="badge" :class="statusBadgeClass(order.status)">
                <text class="badge-text">{{ statusLabel(order.status) }}</text>
              </view>
            </view>
            <text class="card-order-no">#{{ order.orderNo }}</text>
          </view>

          <!-- Card divider -->
          <view class="card-divider" />

          <!-- Card body -->
          <view class="card-body">
            <view class="info-row">
              <view class="info-left">
                <text class="info-label">用户</text>
                <text class="info-value">{{ order.user?.nickname ?? '未知用户' }}</text>
              </view>
              <view class="info-right">
                <text class="info-label">手机</text>
                <text class="info-value mono">{{ order.user?.phone ?? '未绑定' }}</text>
              </view>
            </view>

            <view class="info-row">
              <view class="info-left">
                <text class="info-label">金额</text>
                <text class="info-value price">¥{{ formatPrice(order.amount) }}</text>
              </view>
              <view class="info-right">
                <text class="info-label">下单时间</text>
                <text class="info-value">{{ formatDateTime(order.createdAt) }}</text>
              </view>
            </view>

            <!-- Paid time if available -->
            <view v-if="order.paidAt && order.status === OrderStatus.PAID" class="info-row">
              <text class="info-label">支付时间</text>
              <text class="info-value">{{ formatDateTime(order.paidAt) }}</text>
            </view>
          </view>
        </view>
      </view>

      <!-- Load more / no more -->
      <view v-if="hasMore" class="load-more">
        <text class="load-more-text">{{ loading ? '加载中...' : '加载更多' }}</text>
      </view>
      <view v-else-if="orders.length > 0" class="no-more">
        <text class="no-more-text">— 已加载全部 {{ orders.length }} 条订单 —</text>
      </view>

      <view style="height: 60rpx" />
    </scroll-view>
  </view>
</template>

<script setup lang="ts">
import { ref, computed, onMounted } from 'vue'
import CustomNavBar from '../../components/CustomNavBar.vue'
import { useAdminStore } from '../../stores/admin'
import { formatPrice, formatDateTime } from '../../utils/format'
import { OrderStatus } from '@mp-pilates/shared'
import type { OrderWithDetails } from '@mp-pilates/shared'

const adminStore = useAdminStore()

// 动态计算顶部模块高度
const statusBarHeight = ref(0)

onMounted(() => {
  const windowInfo = uni.getWindowInfo()
  statusBarHeight.value = windowInfo.statusBarHeight ?? 20
})

const filters = [
  { label: '全部', value: '', count: null },
  { label: '已支付', value: OrderStatus.PAID, count: null },
  { label: '待支付', value: OrderStatus.PENDING, count: null },
  { label: '已退款', value: OrderStatus.REFUNDED, count: null },
]

const activeFilter = ref('')
const orders = ref<OrderWithDetails[]>([])
const loading = ref(false)
const refreshing = ref(false)
const page = ref(1)
const hasMore = ref(false)
const totalCount = ref<number | null>(null)
const paidCount = ref<number | null>(null)
const pendingCount = ref<number | null>(null)

// 每个 tab 单独缓存数据
const orderCache: Record<string, { items: OrderWithDetails[]; total: number; page: number; hasMore: boolean }> = {}

function getCacheKey(filter: string): string {
  return filter || 'all'
}

function getCachedData(filter: string) {
  return orderCache[getCacheKey(filter)]
}

function setCachedData(filter: string, data: { items: OrderWithDetails[]; total: number; page: number; hasMore: boolean }) {
  orderCache[getCacheKey(filter)] = data
}

const LIMIT = 20

function statusLabel(s: string) {
  const map: Record<string, string> = {
    [OrderStatus.PAID]: '已支付',
    [OrderStatus.PENDING]: '待支付',
    [OrderStatus.REFUNDED]: '已退款',
  }
  return map[s] ?? s
}

function statusBadgeClass(s: string) {
  if (s === OrderStatus.PAID) return 'badge--paid'
  if (s === OrderStatus.PENDING) return 'badge--pending'
  if (s === OrderStatus.REFUNDED) return 'badge--refunded'
  return 'badge--default'
}

function statusAccentClass(s: string) {
  if (s === OrderStatus.PAID) return 'accent--paid'
  if (s === OrderStatus.PENDING) return 'accent--pending'
  if (s === OrderStatus.REFUNDED) return 'accent--refunded'
  return ''
}

async function loadOrders(reset = false) {
  const filter = activeFilter.value

  // 如果有缓存且是重置（切换tab），直接用缓存数据
  if (reset) {
    const cached = getCachedData(filter)
    if (cached) {
      orders.value = [...cached.items]
      hasMore.value = cached.hasMore
      page.value = cached.page
      return
    }
  }

  // 初始加载或下拉刷新，需要请求接口
  if (loading.value) return
  if (reset) page.value = 1

  loading.value = true
  try {
    const params: { page: number; limit: number; status?: string } = {
      page: page.value,
      limit: LIMIT,
    }
    if (filter) params.status = filter
    const result = await adminStore.fetchAdminOrders(params)

    const newItems = reset ? [...result.items] : [...orders.value, ...result.items]
    const newHasMore = newItems.length < result.total

    // 缓存数据
    setCachedData(filter, {
      items: newItems,
      total: result.total,
      page: page.value,
      hasMore: newHasMore,
    })

    orders.value = newItems
    hasMore.value = newHasMore
  } catch {
    uni.showToast({ title: '加载失败', icon: 'none' })
  } finally {
    loading.value = false
    refreshing.value = false
  }
}

// 初始加载所有分类的数据
async function loadAllFiltersData() {
  loading.value = true
  try {
    // 并行请求所有分类（第一页数据）
    const [allResult, paidResult, pendingResult, refundedResult] = await Promise.all([
      adminStore.fetchAdminOrders({ page: 1, limit: LIMIT }),
      adminStore.fetchAdminOrders({ page: 1, limit: LIMIT, status: OrderStatus.PAID }),
      adminStore.fetchAdminOrders({ page: 1, limit: LIMIT, status: OrderStatus.PENDING }),
      adminStore.fetchAdminOrders({ page: 1, limit: LIMIT, status: OrderStatus.REFUNDED }),
    ])

    // 缓存全部
    setCachedData('', {
      items: [...allResult.items],
      total: allResult.total,
      page: 1,
      hasMore: allResult.items.length < allResult.total,
    })
    totalCount.value = allResult.total

    // 缓存已支付
    setCachedData(OrderStatus.PAID, {
      items: [...paidResult.items],
      total: paidResult.total,
      page: 1,
      hasMore: paidResult.items.length < paidResult.total,
    })
    paidCount.value = paidResult.total

    // 缓存待支付
    setCachedData(OrderStatus.PENDING, {
      items: [...pendingResult.items],
      total: pendingResult.total,
      page: 1,
      hasMore: pendingResult.items.length < pendingResult.total,
    })
    pendingCount.value = pendingResult.total

    // 缓存已退款
    setCachedData(OrderStatus.REFUNDED, {
      items: [...refundedResult.items],
      total: refundedResult.total,
      page: 1,
      hasMore: refundedResult.items.length < refundedResult.total,
    })

    // 设置当前 tab 的数据
    orders.value = [...allResult.items]
    hasMore.value = allResult.items.length < allResult.total
  } catch {
    uni.showToast({ title: '加载失败', icon: 'none' })
  } finally {
    loading.value = false
    refreshing.value = false
  }
}

function selectFilter(value: string) {
  activeFilter.value = value
  // 切换 tab 直接从缓存读取
  const cached = getCachedData(value)
  if (cached) {
    orders.value = [...cached.items]
    hasMore.value = cached.hasMore
    page.value = cached.page
  }
}

async function onRefresh() {
  refreshing.value = true
  // 下拉刷新重新请求所有分类的数据
  await loadAllFiltersData()
}

function loadMore() {
  if (!hasMore.value || loading.value) return
  page.value++
  loadOrders(false)
}

onMounted(() => {
  loadAllFiltersData()
})
</script>

<style lang="scss" scoped>
/* ── Page shell ──────────────────────────────── */
.page {
  height: 100vh;
  display: flex;
  flex-direction: column;
  background: #FAF8F5;
  font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', sans-serif;
}

/* ── Stats bar ──────────────────────────────── */
.stats-bar {
  position: fixed;
  top: calc(var(--status-bar) + 44px);
  left: 0;
  right: 0;
  display: flex;
  align-items: center;
  height: 96rpx;
  background: #FFFFFF;
  padding: 0;
  border-bottom: 1rpx solid rgba(180, 160, 130, 0.2);
  box-shadow: 0 2rpx 12rpx rgba(180, 160, 130, 0.08);
  z-index: 100;
}

.stat-item {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8rpx;
}

.stat-num {
  font-size: 42rpx;
  font-weight: 700;
  color: #4A4035;
  letter-spacing: -1rpx;
  line-height: 1;
  font-family: 'DIN Alternate', 'Helvetica Neue', Arial, sans-serif;
}

.stat-num.paid { color: #7A9E7E; }
.stat-num.pending { color: $warning-color; }

.stat-label {
  font-size: 22rpx;
  color: #A09080;
  letter-spacing: 1rpx;
}

.stat-divider {
  width: 1rpx;
  height: 48rpx;
  background: rgba(180, 160, 130, 0.25);
}

/* ── Filter pills ───────────────────────────── */
.filter-wrap {
  position: fixed;
  top: calc(var(--status-bar) + 92px);
  left: 0;
  right: 0;
  background: #FAF8F5;
  border-bottom: 1rpx solid rgba(180, 160, 130, 0.15);
  z-index: 99;
}

.filter-scroll { overflow: hidden; }

.filter-row {
  display: flex;
  align-items: center;
  padding: 20rpx 28rpx;
  gap: 16rpx;
  white-space: nowrap;
}

.filter-pill {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 8rpx;
  height: 64rpx;
  padding: 0 32rpx;
  border-radius: 32rpx;
  background: rgba(180, 160, 130, 0.1);
  border: 1.5rpx solid rgba(180, 160, 130, 0.2);
  flex-shrink: 0;
  transition: all 0.22s ease;
}

.filter-pill.active {
  background: #4A4035;
  border-color: #4A4035;
}

.filter-pill-text {
  font-size: 26rpx;
  color: #7A6A5A;
  font-weight: 500;
  transition: color 0.22s ease;
}

.filter-pill.active .filter-pill-text {
  color: #E8D8C0;
  font-weight: 600;
}

.filter-pill-dot {
  width: 6rpx;
  height: 6rpx;
  border-radius: 50%;
  background: $accent-color;
}

/* ── List ───────────────────────────────────── */
.list-scroll {
  position: fixed;
  top: calc(var(--status-bar) + 144px);
  left: 0;
  right: 0;
  bottom: 0;
  overflow: hidden;
}

.order-list {
  padding: 20rpx 24rpx 0;
  display: flex;
  flex-direction: column;
  gap: 20rpx;
}

/* ── Skeleton ───────────────────────────────── */
.skeleton-card {
  height: 220rpx;
  border-radius: 20rpx;
  background: linear-gradient(90deg, #F0EBE3 25%, #E8E0D5 50%, #F0EBE3 75%);
  background-size: 400% 100%;
  animation: shimmer 1.6s ease infinite;
}

/* ── Empty ──────────────────────────────────── */
.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 120rpx 48rpx;
  gap: 12rpx;
}

.empty-illustration {
  width: 120rpx;
  height: 120rpx;
  border-radius: 60rpx;
  background: rgba(180, 160, 130, 0.15);
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 12rpx;
}

.empty-icon { font-size: 56rpx; }

.empty-title {
  font-size: 32rpx;
  font-weight: 600;
  color: #4A4035;
  letter-spacing: 0.5rpx;
}

.empty-sub {
  font-size: 26rpx;
  color: rgba(74, 64, 53, 0.4);
  text-align: center;
}

/* ── Order card ─────────────────────────────── */
.order-card {
  position: relative;
  background: #FFFFFF;
  border-radius: 20rpx;
  overflow: hidden;
  box-shadow: 0 4rpx 20rpx rgba(180, 160, 130, 0.12);
  animation: cardIn 0.4s ease both;
}

@keyframes cardIn {
  from { opacity: 0; transform: translateY(12rpx); }
  to { opacity: 1; transform: translateY(0); }
}

.card-accent {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 6rpx;
}

.accent--paid { background: #8FCB9B; }
.accent--pending { background: #F2C94C; }
.accent--refunded { background: rgba(43, 43, 43, 0.2); }

.card-header {
  padding: 24rpx 24rpx 20rpx 30rpx;
}

.card-title-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.card-plan {
  font-size: 30rpx;
  font-weight: 700;
  color: #4A4035;
  letter-spacing: 0.5rpx;
}

.card-order-no {
  font-size: 22rpx;
  color: rgba(74, 64, 53, 0.35);
  margin-top: 6rpx;
  display: block;
  font-family: 'SF Mono', 'Menlo', monospace;
}

.card-divider {
  height: 1rpx;
  background: rgba(180, 160, 130, 0.15);
  margin: 0 24rpx;
}

.card-body {
  padding: 20rpx 24rpx 20rpx 30rpx;
  display: flex;
  flex-direction: column;
  gap: 12rpx;
}

.info-row {
  display: flex;
  align-items: center;
}

.info-left,
.info-right {
  flex: 1;
  display: flex;
  align-items: center;
  gap: 12rpx;
}

.info-right {
  justify-content: flex-end;
}

.info-label {
  font-size: 24rpx;
  color: rgba(74, 64, 53, 0.4);
  flex-shrink: 0;
  min-width: 80rpx;
}

.info-value {
  font-size: 26rpx;
  color: #4A4035;
  font-weight: 500;
}

.info-value.mono {
  font-family: 'SF Mono', 'Menlo', monospace;
  font-size: 24rpx;
}

.info-value.price {
  font-size: 30rpx;
  font-weight: 700;
  color: $accent-color;
  font-family: 'DIN Alternate', 'Helvetica Neue', Arial, sans-serif;
}

/* ── Status badges ─────────────────────────── */
.badge {
  border-radius: 8rpx;
  padding: 4rpx 14rpx;
}

.badge--paid { background: rgba(122, 158, 126, 0.15); }
.badge--paid .badge-text { font-size: 22rpx; color: #5A7E5E; font-weight: 600; }

.badge--pending { background: rgba(196, 149, 106, 0.2); }
.badge--pending .badge-text { font-size: 22rpx; color: #A07540; font-weight: 600; }

.badge--refunded { background: rgba(180, 160, 130, 0.15); }
.badge--refunded .badge-text { font-size: 22rpx; color: #8A7A6A; }

.badge--default .badge-text { font-size: 22rpx; color: #888; }

/* ── Load more ─────────────────────────────── */
.load-more {
  text-align: center;
  padding: 40rpx 0 20rpx;
}

.load-more-text {
  font-size: 26rpx;
  color: $accent-color;
  font-weight: 500;
}

.no-more {
  text-align: center;
  padding: 32rpx 0 20rpx;
}

.no-more-text {
  font-size: 24rpx;
  color: rgba(74, 64, 53, 0.3);
  letter-spacing: 0.5rpx;
}
</style>
