<template>
  <view class="bookings-page" :style="{ paddingTop: navBarHeight }">
    <CustomNavBar title="我的预约" show-back />
    <!-- Tab bar -->
    <view class="tab-bar">
      <view
        v-for="tab in tabs"
        :key="tab.key"
        class="tab-item"
        :class="{ active: activeTab === tab.key }"
        @tap="selectTab(tab.key)"
      >
        <text class="tab-label">{{ tab.label }}</text>
        <view v-if="tab.key === 'upcoming' && upcomingCount > 0" class="tab-badge">
          <text class="tab-badge-text">{{ upcomingCount }}</text>
        </view>
      </view>
    </view>

    <!-- Upcoming tab content -->
    <scroll-view
      v-show="activeTab === 'upcoming'"
      class="scroll"
      scroll-y
      refresher-enabled
      :refresher-triggered="refreshingUpcoming"
      @refresherrefresh="onRefreshUpcoming"
    >
      <!-- Loading -->
      <view v-if="bookingStore.loadingBookings && !refreshingUpcoming" class="loading-wrap">
        <view v-for="i in 3" :key="i" class="skeleton-card">
          <view class="skeleton-stripe" />
          <view class="skeleton-body">
            <view class="skeleton-line skeleton-line--long" />
            <view class="skeleton-line skeleton-line--short" />
            <view class="skeleton-line skeleton-line--medium" />
          </view>
        </view>
      </view>

      <!-- Empty -->
      <view v-else-if="upcomingBookings.length === 0" class="empty-wrap">
        <view class="empty-illustration">
          <text class="empty-icon">&#x1F9D8;</text>
        </view>
        <text class="empty-title">暂无即将上课的预约</text>
        <text class="empty-sub">开始预约你的普拉提课程吧</text>
        <view class="empty-btn" @tap="goBooking">
          <text class="empty-btn-text">立即预约</text>
        </view>
      </view>

      <!-- Booking list -->
      <view v-else class="list">
        <view
          v-for="booking in upcomingBookings"
          :key="booking.id"
          class="booking-card"
        >
          <view class="booking-stripe stripe--confirmed" />
          <view class="booking-content">
            <view class="booking-header">
              <view class="booking-datetime">
                <text class="booking-date">{{ formatDateDisplay(booking.timeSlot.date) }}</text>
                <text class="booking-time">
                  {{ booking.timeSlot.startTime.slice(0, 5) }} - {{ booking.timeSlot.endTime.slice(0, 5) }}
                </text>
              </view>
              <view class="status-badge badge--confirmed">
                <text class="status-text">已预约</text>
              </view>
            </view>
            <view class="booking-footer">
              <view class="booking-meta">
                <text class="meta-label">使用卡种</text>
                <text class="meta-value">{{ booking.membership.cardType.name }}</text>
              </view>
              <view class="cancel-btn" @tap="handleCancel(booking)">
                <text class="cancel-text">取消预约</text>
              </view>
            </view>
          </view>
        </view>
      </view>

      <view class="scroll-bottom-spacer" />
    </scroll-view>

    <!-- History tab content -->
    <scroll-view
      v-show="activeTab === 'history'"
      class="scroll"
      scroll-y
      refresher-enabled
      :refresher-triggered="refreshingHistory"
      @refresherrefresh="onRefreshHistory"
    >
      <!-- Loading -->
      <view v-if="bookingStore.loadingBookings && !refreshingHistory" class="loading-wrap">
        <view v-for="i in 3" :key="i" class="skeleton-card">
          <view class="skeleton-stripe" />
          <view class="skeleton-body">
            <view class="skeleton-line skeleton-line--long" />
            <view class="skeleton-line skeleton-line--short" />
          </view>
        </view>
      </view>

      <!-- Empty -->
      <view v-else-if="historyBookings.length === 0" class="empty-wrap">
        <view class="empty-illustration">
          <text class="empty-icon">&#x1F4CB;</text>
        </view>
        <text class="empty-title">暂无历史记录</text>
        <text class="empty-sub">已完成或取消的课程将显示在这里</text>
      </view>

      <!-- Booking list -->
      <view v-else class="list">
        <view
          v-for="booking in historyBookings"
          :key="booking.id"
          class="booking-card"
        >
          <view class="booking-stripe" :class="stripeClass(booking.status)" />
          <view class="booking-content">
            <view class="booking-header">
              <view class="booking-datetime">
                <text class="booking-date">{{ formatDateDisplay(booking.timeSlot.date) }}</text>
                <text class="booking-time">
                  {{ booking.timeSlot.startTime.slice(0, 5) }} - {{ booking.timeSlot.endTime.slice(0, 5) }}
                </text>
              </view>
              <view class="status-badge" :class="statusBadgeClass(booking.status)">
                <text class="status-text">{{ statusLabel(booking.status) }}</text>
              </view>
            </view>
            <view class="booking-meta-row">
              <text class="meta-label">使用卡种</text>
              <text class="meta-value">{{ booking.membership.cardType.name }}</text>
            </view>
          </view>
        </view>
      </view>

      <view class="scroll-bottom-spacer" />
    </scroll-view>
  </view>
</template>

<script setup lang="ts">
import { ref, computed, onMounted } from 'vue'
import type { BookingWithDetails } from '@mp-pilates/shared'
import { BookingStatus } from '@mp-pilates/shared'
import { useBookingStore } from '../../stores/booking'
import { formatDate, getWeekdayLabel } from '../../utils/format'
import CustomNavBar from '../../components/CustomNavBar.vue'

const bookingStore = useBookingStore()

// ─── Nav bar height ──────────────────────────────────────
const navBarHeight = ref('64px')

// ─── Tab state ────────────────────────────────────────────
type TabKey = 'upcoming' | 'history'

const tabs = [
  { key: 'upcoming' as TabKey, label: '即将上课' },
  { key: 'history' as TabKey, label: '历史记录' },
]

const activeTab = ref<TabKey>('upcoming')
const refreshingUpcoming = ref(false)
const refreshingHistory = ref(false)

// ─── Safe array accessor ─────────────────────────────────
function safeBookings(): readonly BookingWithDetails[] {
  const raw = bookingStore.myBookings
  return Array.isArray(raw) ? raw : []
}

/** Normalize date to YYYY-MM-DD — handles both "2026-04-06" and "2026-04-06T00:00:00.000Z" */
function toDateStr(date: string): string {
  return date.slice(0, 10)
}

// ─── Filtered bookings ────────────────────────────────────
const today = computed(() => formatDate(new Date()))

const upcomingBookings = computed<BookingWithDetails[]>(() => {
  return safeBookings()
    .filter(
      (b) => b.status === BookingStatus.CONFIRMED && toDateStr(b.timeSlot.date) >= today.value,
    )
    .sort((a, b) => {
      const dateA = toDateStr(a.timeSlot.date)
      const dateB = toDateStr(b.timeSlot.date)
      if (dateA !== dateB) {
        return dateA.localeCompare(dateB)
      }
      return a.timeSlot.startTime.localeCompare(b.timeSlot.startTime)
    })
})

const historyBookings = computed<BookingWithDetails[]>(() => {
  return safeBookings()
    .filter(
      (b) =>
        b.status !== BookingStatus.CONFIRMED ||
        toDateStr(b.timeSlot.date) < today.value,
    )
    .sort((a, b) => {
      const dateA = toDateStr(a.timeSlot.date)
      const dateB = toDateStr(b.timeSlot.date)
      if (dateB !== dateA) {
        return dateB.localeCompare(dateA)
      }
      return b.timeSlot.startTime.localeCompare(a.timeSlot.startTime)
    })
})

const upcomingCount = computed(() => upcomingBookings.value.length)

// ─── Helpers ──────────────────────────────────────────────
const STATUS_LABELS: Record<BookingStatus, string> = {
  [BookingStatus.CONFIRMED]: '已预约',
  [BookingStatus.CANCELLED]: '已取消',
  [BookingStatus.COMPLETED]: '已完成',
  [BookingStatus.NO_SHOW]: '未出席',
}

const STATUS_BADGE_CLASSES: Record<BookingStatus, string> = {
  [BookingStatus.CONFIRMED]: 'badge--confirmed',
  [BookingStatus.CANCELLED]: 'badge--cancelled',
  [BookingStatus.COMPLETED]: 'badge--completed',
  [BookingStatus.NO_SHOW]: 'badge--noshow',
}

const STATUS_STRIPE_CLASSES: Record<BookingStatus, string> = {
  [BookingStatus.CONFIRMED]: 'stripe--confirmed',
  [BookingStatus.CANCELLED]: 'stripe--cancelled',
  [BookingStatus.COMPLETED]: 'stripe--completed',
  [BookingStatus.NO_SHOW]: 'stripe--noshow',
}

function statusLabel(status: BookingStatus): string {
  return STATUS_LABELS[status] ?? status
}

function statusBadgeClass(status: BookingStatus): string {
  return STATUS_BADGE_CLASSES[status] ?? ''
}

function stripeClass(status: BookingStatus): string {
  return STATUS_STRIPE_CLASSES[status] ?? ''
}

function formatDateDisplay(dateStr: string): string {
  const normalized = toDateStr(dateStr)
  const todayStr = formatDate(new Date())
  const tomorrowDate = new Date()
  tomorrowDate.setDate(tomorrowDate.getDate() + 1)
  const tomorrowStr = formatDate(tomorrowDate)

  // Parse from normalized YYYY-MM-DD to avoid timezone shifts
  const [y, m, d] = normalized.split('-').map(Number)
  const localDate = new Date(y, m - 1, d)
  const weekday = getWeekdayLabel(localDate)

  if (normalized === todayStr) {
    return `今天 ${m}月${d}日`
  }
  if (normalized === tomorrowStr) {
    return `明天 ${m}月${d}日`
  }
  return `${m}月${d}日 ${weekday}`
}

// ─── Actions ──────────────────────────────────────────────
function selectTab(key: TabKey) {
  activeTab.value = key
}

async function onRefreshUpcoming() {
  refreshingUpcoming.value = true
  await bookingStore.fetchMyBookings()
  refreshingUpcoming.value = false
}

async function onRefreshHistory() {
  refreshingHistory.value = true
  await bookingStore.fetchMyBookings()
  refreshingHistory.value = false
}

function goBooking() {
  uni.switchTab({ url: '/pages/booking/index' })
}

async function handleCancel(booking: BookingWithDetails) {
  const dateLabel = formatDateDisplay(booking.timeSlot.date)
  const timeLabel = booking.timeSlot.startTime.slice(0, 5)

  uni.showModal({
    title: '取消预约',
    content: `确定要取消 ${dateLabel} ${timeLabel} 的课程吗？`,
    confirmText: '确定取消',
    confirmColor: '#ef4444',
    cancelText: '再想想',
    success: async (res) => {
      if (!res.confirm) return
      uni.showLoading({ title: '取消中...' })
      try {
        await bookingStore.cancelBooking(booking.id)
        uni.hideLoading()
        uni.showToast({ title: '已取消预约', icon: 'success' })
        await bookingStore.fetchMyBookings()
      } catch (err: unknown) {
        uni.hideLoading()
        const msg = err instanceof Error ? err.message : '取消失败，请重试'
        uni.showToast({ title: msg, icon: 'none' })
      }
    },
  })
}

// ─── Lifecycle ────────────────────────────────────────────
onMounted(() => {
  const windowInfo = uni.getWindowInfo()
  const statusBarH = windowInfo.statusBarHeight ?? 20
  navBarHeight.value = `${statusBarH + Math.round(88 * windowInfo.windowWidth / 750)}px`
  bookingStore.fetchMyBookings()
})
</script>

<style lang="scss" scoped>
.bookings-page {
  min-height: 100vh;
  background: #f5f3f0;
  display: flex;
  flex-direction: column;
}

/* ── Tab bar ─────────────────────────────────────────── */
.tab-bar {
  display: flex;
  flex-direction: row;
  background: #fff;
  border-bottom: 1rpx solid #f0ece8;
  flex-shrink: 0;
}

.tab-item {
  flex: 1;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  gap: 8rpx;
  padding: 28rpx 0;
  position: relative;
  transition: opacity 0.2s;

  &:active {
    opacity: 0.7;
  }

  &.active {
    .tab-label {
      color: $primary-dark;
      font-weight: 600;
    }

    &::after {
      content: '';
      position: absolute;
      bottom: 0;
      left: 50%;
      transform: translateX(-50%);
      width: 48rpx;
      height: 4rpx;
      background: $primary-dark;
      border-radius: 2rpx;
    }
  }
}

.tab-label {
  font-size: 28rpx;
  color: #999;
  font-weight: 400;
}

.tab-badge {
  min-width: 32rpx;
  height: 32rpx;
  border-radius: 16rpx;
  background: #ef4444;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 8rpx;
}

.tab-badge-text {
  font-size: 20rpx;
  color: #fff;
  font-weight: 600;
}

/* ── Scroll ──────────────────────────────────────────── */
.scroll {
  flex: 1;
  height: calc(100vh - 88rpx);
}

/* ── Loading skeleton ────────────────────────────────── */
.loading-wrap {
  padding: 24rpx;
  display: flex;
  flex-direction: column;
  gap: 16rpx;
}

.skeleton-card {
  border-radius: 16rpx;
  background: #fff;
  overflow: hidden;
  display: flex;
  flex-direction: row;
}

.skeleton-stripe {
  width: 8rpx;
  flex-shrink: 0;
  background: #eee;
}

.skeleton-body {
  flex: 1;
  padding: 28rpx 24rpx;
  display: flex;
  flex-direction: column;
  gap: 16rpx;
}

.skeleton-line {
  height: 28rpx;
  border-radius: 8rpx;
  background: linear-gradient(90deg, #f0f0f0 25%, #e8e8e8 50%, #f0f0f0 75%);
  background-size: 400% 100%;
  animation: shimmer 1.4s infinite;

  &--long { width: 70%; }
  &--short { width: 40%; }
  &--medium { width: 55%; }
}

/* ── Empty ───────────────────────────────────────────── */
.empty-wrap {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 120rpx 40rpx;
  gap: 16rpx;
}

.empty-illustration {
  width: 160rpx;
  height: 160rpx;
  border-radius: 80rpx;
  background: #faf6f1;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 16rpx;
}

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

.empty-title {
  font-size: 32rpx;
  font-weight: 600;
  color: #333;
}

.empty-sub {
  font-size: 26rpx;
  color: #999;
}

.empty-btn {
  margin-top: 24rpx;
  padding: 22rpx 64rpx;
  border-radius: 44rpx;
  background: linear-gradient(135deg, $primary-color, $primary-dark);
  box-shadow: 0 4rpx 16rpx rgba(201, 168, 124, 0.3);

  &:active {
    opacity: 0.85;
    transform: scale(0.98);
  }
}

.empty-btn-text {
  font-size: 30rpx;
  color: #fff;
  font-weight: 600;
  letter-spacing: 2rpx;
}

/* ── List ────────────────────────────────────────────── */
.list {
  padding: 24rpx 24rpx 0;
  display: flex;
  flex-direction: column;
  gap: 20rpx;
}

/* ── Booking card ────────────────────────────────────── */
.booking-card {
  background: #fff;
  border-radius: 20rpx;
  overflow: hidden;
  box-shadow: 0 2rpx 16rpx rgba(0, 0, 0, 0.05);
  display: flex;
  flex-direction: row;
}

/* Colored left stripe */
.booking-stripe {
  width: 8rpx;
  flex-shrink: 0;

  &.stripe--confirmed { background: $primary-dark; }
  &.stripe--completed { background: #66bb6a; }
  &.stripe--cancelled { background: #e0e0e0; }
  &.stripe--noshow    { background: #ef5350; }
}

.booking-content {
  flex: 1;
  padding: 28rpx 24rpx 24rpx 20rpx;
  display: flex;
  flex-direction: column;
  gap: 16rpx;
}

.booking-header {
  display: flex;
  flex-direction: row;
  align-items: flex-start;
  justify-content: space-between;
}

.booking-datetime {
  display: flex;
  flex-direction: column;
  gap: 6rpx;
}

.booking-date {
  font-size: 30rpx;
  font-weight: 600;
  color: #1a1a1a;
}

.booking-time {
  font-size: 26rpx;
  color: #888;
  letter-spacing: 1rpx;
}

/* Status badge */
.status-badge {
  padding: 8rpx 18rpx;
  border-radius: 20rpx;
  flex-shrink: 0;

  &.badge--confirmed { background: rgba(201, 168, 124, 0.12); }
  &.badge--completed { background: rgba(102, 187, 106, 0.12); }
  &.badge--cancelled { background: rgba(0, 0, 0, 0.04); }
  &.badge--noshow    { background: rgba(239, 83, 80, 0.1); }
}

.status-text {
  font-size: 22rpx;
  font-weight: 600;

  .badge--confirmed & { color: $primary-dark; }
  .badge--completed & { color: #66bb6a; }
  .badge--cancelled & { color: #bbb; }
  .badge--noshow    & { color: #ef5350; }
}

/* Footer row with meta + cancel */
.booking-footer {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  padding-top: 8rpx;
  border-top: 1rpx solid #f5f5f5;
}

/* Meta info */
.booking-meta,
.booking-meta-row {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 8rpx;
}

.booking-meta-row {
  padding-top: 8rpx;
  border-top: 1rpx solid #f5f5f5;
}

.meta-label {
  font-size: 22rpx;
  color: #bbb;
}

.meta-value {
  font-size: 24rpx;
  color: #666;
  font-weight: 500;
}

/* Cancel button */
.cancel-btn {
  padding: 12rpx 28rpx;
  border-radius: 24rpx;
  border: 1rpx solid rgba(239, 68, 68, 0.2);
  background: rgba(254, 240, 240, 0.8);
  transition: opacity 0.2s;

  &:active {
    opacity: 0.65;
  }
}

.cancel-text {
  font-size: 24rpx;
  color: #ef4444;
  font-weight: 500;
}

/* ── Spacer ──────────────────────────────────────────── */
.scroll-bottom-spacer {
  height: 48rpx;
}
</style>
