import { useEffect, useState } from 'react';
import Taro from '@tarojs/taro';
import { Button, Input, Text, View } from '@tarojs/components';
import { logout } from '@/services/auth';
import { checkActivationCode, loadEntitlements, loadOrders, loadSvipPlans, redeemActivationCode, type OrderItem, type SvipPlan } from '@/services/commerce';
import {
  loadLearningStats,
  loadLearningTrend,
  loadPracticeHistory,
  type LearningStats,
  type LearningTrendItem,
  type PracticeHistoryItem,
} from '@/services/learning';
import {
  checkIn,
  claimActivityTask,
  loadBadges,
  loadExamCountdowns,
  loadActivityTasks,
  loadExchangeItems,
  loadNotifications,
  loadProfile,
  loadScoreEvents,
  redeemExchangeItem,
  updateProfile,
  updateNotificationStatus,
  type PointActivityTask,
  type PointExchangeItem,
  type StudentProfile,
  type UserNotificationItem,
} from '@/services/profile';
import '../student.css';

function percent(value?: number | null) {
  return `${Math.round((value || 0) * 100)}%`;
}

function shortDate(value?: string | null) {
  if (!value) return '';
  return value.slice(5, 10);
}

function dateText(value?: string | null) {
  if (!value) return '暂无记录';
  return value.slice(0, 10);
}

function practiceTitle(item: PracticeHistoryItem) {
  return item.blueprintName || item.collectionName || item.contentNodeName || item.entryName || modeLabel(item.mode);
}

function modeLabel(mode?: string | null) {
  const normalized = String(mode || '');
  if (normalized === 'mock_exam') return '全真模拟';
  if (normalized === 'random') return '随机练习';
  if (normalized === 'wrong_review') return '错题复习';
  if (normalized === 'favorites') return '收藏练习';
  return '顺序练习';
}

function maxTrendAnswers(items: LearningTrendItem[]) {
  return Math.max(1, ...items.map(item => item.answeredCount || 0));
}

function trendBucket(value: number, maxValue: number) {
  if (value <= 0) return 'h-bucket-0';
  const ratio = maxValue ? value / maxValue : 0;
  const bucket = Math.max(1, Math.min(12, Math.ceil(ratio * 12)));
  return `h-bucket-${bucket}`;
}

function progressBucket(value: number) {
  const ratio = Math.max(0, Math.min(1, value || 0));
  const bucket = Math.max(0, Math.min(10, Math.round(ratio * 10)));
  return `w-bucket-${bucket}`;
}

function sessionStatusLabel(status?: string | null) {
  if (status === 'active') return '进行中';
  if (status === 'expired') return '已过期';
  return '已完成';
}

function sessionStatusClass(status?: string | null) {
  if (status === 'active') return 'warning';
  if (status === 'expired') return 'danger';
  return '';
}

type ProfileNotificationStatus = NonNullable<UserNotificationItem['status']>;
type AvatarPreset = NonNullable<StudentProfile['avatarPreset']>;

function taskTypeLabel(type?: string | null) {
  if (type === 'daily_check_in') return '每日签到';
  if (type === 'feedback_submit') return '提交反馈';
  if (type === 'feedback_resolved') return '反馈采纳';
  if (type === 'practice_complete') return '完成练习';
  if (type === 'vocabulary_review') return '背单词';
  if (type === 'mock_exam_submit') return '提交模考';
  return '手动领取';
}

function periodLabel(type?: string | null) {
  if (type === 'daily') return '每日';
  if (type === 'weekly') return '每周';
  if (type === 'monthly') return '每月';
  if (type === 'unlimited') return '不限次数';
  return '一次性';
}

function exchangeTypeLabel(type?: string | null) {
  if (type === 'coupon') return '优惠券';
  if (type === 'asset') return '资料';
  if (type === 'custom') return '自定义';
  return '人工发放';
}

function notificationTypeLabel(type?: string | null) {
  if (type === 'feedback_status_updated') return '反馈处理';
  if (type === 'feedback_reward_granted') return '反馈奖励';
  if (type === 'badge_granted') return '勋章发放';
  if (type === 'point_exchange_completed') return '兑换完成';
  if (type === 'point_exchange_pending_fulfillment') return '待履约兑换';
  return '系统通知';
}

function notificationStatusLabel(status?: string | null) {
  if (status === 'unread') return '未读';
  if (status === 'read') return '已读';
  if (status === 'dismissed') return '已忽略';
  if (status === 'archived') return '已归档';
  return '通知';
}

function notificationStatusClass(status?: string | null, severity?: string | null) {
  if (severity === 'error') return 'danger';
  if (status === 'unread' || severity === 'warning') return 'warning';
  return '';
}

function avatarPresetLabel(preset?: string | null) {
  return preset === 'female' ? '女生默认' : '男生默认';
}

export default function StudentProfilePage() {
  const [profile, setProfile] = useState<StudentProfile | null>(null);
  const [plans, setPlans] = useState<SvipPlan[]>([]);
  const [orders, setOrders] = useState<OrderItem[]>([]);
  const [badges, setBadges] = useState<Record<string, unknown>[]>([]);
  const [countdowns, setCountdowns] = useState<Record<string, unknown>[]>([]);
  const [learningStats, setLearningStats] = useState<LearningStats | null>(null);
  const [learningTrend, setLearningTrend] = useState<LearningTrendItem[]>([]);
  const [practiceHistory, setPracticeHistory] = useState<PracticeHistoryItem[]>([]);
  const [activityTasks, setActivityTasks] = useState<PointActivityTask[]>([]);
  const [exchangeItems, setExchangeItems] = useState<PointExchangeItem[]>([]);
  const [scoreEvents, setScoreEvents] = useState<Record<string, unknown>[]>([]);
  const [notifications, setNotifications] = useState<UserNotificationItem[]>([]);
  const [notificationSummary, setNotificationSummary] = useState<Record<string, number>>({});
  const [notificationFilter, setNotificationFilter] = useState<'' | ProfileNotificationStatus>('unread');
  const [notificationBusy, setNotificationBusy] = useState('');
  const [pointsBusy, setPointsBusy] = useState('');
  const [profileBusy, setProfileBusy] = useState('');
  const [activationCode, setActivationCode] = useState('');
  const [message, setMessage] = useState('');
  const [error, setError] = useState('');

  function reload(nextNotificationFilter = notificationFilter) {
    Promise.all([
      loadProfile().catch(() => ({ item: null })),
      loadSvipPlans().catch(() => ({ items: [] })),
      loadOrders().catch(() => ({ items: [] })),
      loadBadges().catch(() => ({ items: [] })),
      loadExamCountdowns().catch(() => ({ items: [] })),
      loadLearningStats(30).catch(() => ({ item: undefined })),
      loadLearningTrend(14).catch(() => ({ items: [] })),
      loadPracticeHistory({ limit: 6 }).catch(() => ({ items: [] })),
      loadActivityTasks({ limit: 8 }).catch(() => ({ items: [] })),
      loadExchangeItems(8).catch(() => ({ items: [] })),
      loadScoreEvents(8).catch(() => ({ items: [] })),
      loadNotifications({ status: nextNotificationFilter || undefined, limit: 8 }).catch(() => ({ items: [], summary: {} })),
      loadEntitlements().catch(() => ({ summary: {} })),
    ]).then(([
      profilePayload,
      planPayload,
      orderPayload,
      badgePayload,
      countdownPayload,
      statsPayload,
      trendPayload,
      historyPayload,
      activityTaskPayload,
      exchangeItemPayload,
      scoreEventPayload,
      notificationPayload,
    ]) => {
      setProfile(profilePayload.item || null);
      setPlans(planPayload.items || []);
      setOrders(orderPayload.items || []);
      setBadges(badgePayload.items || []);
      setCountdowns(countdownPayload.items || []);
      setLearningStats(statsPayload.item || null);
      setLearningTrend(trendPayload.items || []);
      setPracticeHistory(historyPayload.items || []);
      setActivityTasks(activityTaskPayload.items || []);
      setExchangeItems(exchangeItemPayload.items || []);
      setScoreEvents(scoreEventPayload.items || []);
      setNotifications(notificationPayload.items || []);
      setNotificationSummary(notificationPayload.summary || {});
    }).catch(nextError => setError(nextError instanceof Error ? nextError.message : '个人中心加载失败'));
  }

  useEffect(() => {
    reload();
  }, []);

  async function handleCheckIn() {
    try {
      const payload = await checkIn();
      setMessage(`签到成功，当前积分 ${String(payload.item?.score ?? '')}`);
      reload();
    } catch (nextError) {
      setError(nextError instanceof Error ? nextError.message : '签到失败');
    }
  }

  async function handleRedeem() {
    try {
      await checkActivationCode(activationCode);
      await redeemActivationCode(activationCode);
      setMessage('激活码兑换成功');
      setActivationCode('');
      reload();
    } catch (nextError) {
      setError(nextError instanceof Error ? nextError.message : '激活码兑换失败');
    }
  }

  async function handleLogout() {
    await logout();
    Taro.redirectTo({ url: '/pages/student/login/index' });
  }

  async function changeAvatarPreset(nextPreset: AvatarPreset) {
    const currentPreset = profile?.avatarPreset || profile?.avatar?.preset || 'male';
    if (profileBusy || currentPreset === nextPreset) return;
    setProfileBusy(`avatar:${nextPreset}`);
    setError('');
    try {
      await updateProfile({ avatarPreset: nextPreset });
      setProfile(prev => prev ? {
        ...prev,
        avatarPreset: nextPreset,
        avatar: {
          ...prev.avatar,
          preset: nextPreset,
          displayUrl: `/assets/avatars/default-${nextPreset}.svg`,
        },
      } : prev);
      setMessage('头像已更新');
      reload();
    } catch (nextError) {
      setError(nextError instanceof Error ? nextError.message : '头像更新失败');
    } finally {
      setProfileBusy('');
    }
  }

  async function reloadNotifications(nextFilter = notificationFilter) {
    setNotificationBusy('reload');
    try {
      const payload = await loadNotifications({ status: nextFilter || undefined, limit: 12 });
      setNotifications(payload.items || []);
      setNotificationSummary(payload.summary || {});
    } catch (nextError) {
      setError(nextError instanceof Error ? nextError.message : '消息加载失败');
    } finally {
      setNotificationBusy('');
    }
  }

  async function changeNotificationFilter(nextFilter: '' | ProfileNotificationStatus) {
    setNotificationFilter(nextFilter);
    await reloadNotifications(nextFilter);
  }

  async function markNotification(item: UserNotificationItem, status: 'read' | 'dismissed' | 'archived') {
    setNotificationBusy(`${item.id}:${status}`);
    try {
      await updateNotificationStatus({ notificationIds: [item.id], status });
      setMessage(status === 'read' ? '消息已标记为已读' : status === 'archived' ? '消息已归档' : '消息已忽略');
      await reloadNotifications(notificationFilter);
    } catch (nextError) {
      setError(nextError instanceof Error ? nextError.message : '消息状态更新失败');
    } finally {
      setNotificationBusy('');
    }
  }

  async function claimTask(item: PointActivityTask) {
    setPointsBusy(`task:${item.id}`);
    setError('');
    try {
      const payload = await claimActivityTask({
        taskId: item.id,
        idempotencyKey: `task-${item.id}-${Date.now()}`,
        metadata: { source: 'taro-profile' },
      });
      setMessage(`已领取 ${String(item.rewardPoints || 0)} 积分，当前积分 ${String(payload.item?.score ?? '')}`);
      reload();
    } catch (nextError) {
      setError(nextError instanceof Error ? nextError.message : '任务领取失败');
    } finally {
      setPointsBusy('');
    }
  }

  async function redeemItem(item: PointExchangeItem) {
    setPointsBusy(`exchange:${item.id}`);
    setError('');
    try {
      const payload = await redeemExchangeItem({
        itemId: item.id,
        idempotencyKey: `exchange-${item.id}-${Date.now()}`,
        metadata: { source: 'taro-profile' },
      });
      setMessage(`兑换已提交，当前积分 ${String(payload.item?.score ?? '')}`);
      reload();
    } catch (nextError) {
      setError(nextError instanceof Error ? nextError.message : '积分兑换失败');
    } finally {
      setPointsBusy('');
    }
  }

  const maxAnswers = maxTrendAnswers(learningTrend);
  const answerStats = learningStats?.answers;
  const reportStats = learningStats?.reports;
  const wrongBook = learningStats?.wrongBook;
  const favoriteStats = learningStats?.favorites;
  const questionTypes = learningStats?.questionTypes || [];
  const bestPlan = plans[0];
  const avatarPreset = profile?.avatarPreset || profile?.avatar?.preset || 'male';

  return (
    <View className='student-page'>
      <View className='student-topbar'>
        <View className='student-title-block'>
          <Text className='student-kicker'>Profile</Text>
          <Text className='student-title'>{profile?.name || profile?.phone || '个人中心'}</Text>
          <Text className='student-subtitle'>{profile?.membership?.isSvip ? 'SVIP 生效中' : '普通用户'} · 积分 {profile?.score ?? 0}</Text>
        </View>
        <Button className='secondary-button' onClick={handleLogout}>退出</Button>
      </View>

      <View className='profile-card'>
        <View className={`profile-avatar ${avatarPreset}`}>
          <Text className='profile-avatar-mark'>{avatarPreset === 'female' ? '女' : '男'}</Text>
        </View>
        <View className='profile-card-main'>
          <Text className='row-main'>{profile?.name || profile?.phone || '题库学生'}</Text>
          <Text className='row-meta'>{avatarPresetLabel(avatarPreset)} · 当前使用</Text>
          <View className='avatar-choice-grid'>
            {(['male', 'female'] as AvatarPreset[]).map(preset => (
              <View
                key={preset}
                className={`avatar-choice ${avatarPreset === preset ? 'active' : ''} ${profileBusy === `avatar:${preset}` ? 'busy' : ''}`}
                onClick={() => void changeAvatarPreset(preset)}
              >
                <View className={`avatar-choice-icon ${preset}`}>
                  <Text className='avatar-choice-mark'>{preset === 'female' ? '女' : '男'}</Text>
                </View>
                <View className='avatar-choice-copy'>
                  <Text className='avatar-choice-title'>{avatarPresetLabel(preset)}</Text>
                  <Text className='avatar-choice-meta'>{profileBusy === `avatar:${preset}` ? '保存中' : avatarPreset === preset ? '当前使用' : '点击切换'}</Text>
                </View>
              </View>
            ))}
          </View>
        </View>
      </View>

      <View className='grid-two'>
        <View className='metric'><Text className='metric-value'>{String(answerStats?.totalAnswered ?? (profile?.stats?.answers as Record<string, unknown> | undefined)?.totalAnswered ?? 0)}</Text><Text className='metric-label'>累计答题</Text></View>
        <View className='metric'><Text className='metric-value'>{String((profile?.stats?.vocabulary as Record<string, unknown> | undefined)?.masteredWords ?? 0)}</Text><Text className='metric-label'>掌握单词</Text></View>
      </View>

      <View className='section-block'>
        <Text className='section-heading'>学习报告</Text>
        <View className='report-panel learning-report-panel'>
          <View className='grid-two'>
            <View className='metric compact-metric'>
              <Text className='metric-value'>{percent(answerStats?.accuracy)}</Text>
              <Text className='metric-label'>累计正确率</Text>
            </View>
            <View className='metric compact-metric'>
              <Text className='metric-value'>{String(answerStats?.todayAnswered ?? 0)}</Text>
              <Text className='metric-label'>今日答题</Text>
            </View>
            <View className='metric compact-metric'>
              <Text className='metric-value'>{String(wrongBook?.unresolvedWrong ?? 0)}</Text>
              <Text className='metric-label'>待解决错题</Text>
            </View>
            <View className='metric compact-metric'>
              <Text className='metric-value'>{String(reportStats?.bestScore ?? 0)}</Text>
              <Text className='metric-label'>模考/练习最高分</Text>
            </View>
          </View>
          <Text className='row-meta report-summary-line'>
            近 {String(learningStats?.windowDays || 30)} 天题型统计 · 最近答题 {dateText(answerStats?.latestAnsweredAt)} · 已完成报告 {String(reportStats?.reportCount || 0)} 份
          </Text>
        </View>
      </View>

      <View className='section-block'>
        <Text className='section-heading'>14 天趋势</Text>
        {learningTrend.length ? (
          <View className='trend-chart'>
            {learningTrend.map(item => {
              return (
                <View className='trend-column' key={item.date}>
                  <Text className='trend-value'>{String(item.answeredCount || 0)}</Text>
                  <View className='trend-bar-track'>
                    <View className={`trend-bar-fill ${trendBucket(item.answeredCount || 0, maxAnswers)}`} />
                  </View>
                  <Text className='trend-label'>{shortDate(item.date)}</Text>
                </View>
              );
            })}
          </View>
        ) : <View className='empty-state'>暂无趋势数据，完成练习后会自动生成。</View>}
      </View>

      <View className='section-block'>
        <Text className='section-heading'>题型表现</Text>
        {questionTypes.length ? (
          <View className='list-stack'>
            {questionTypes.slice(0, 6).map(item => (
              <View className='list-row' key={item.questionType}>
                <View className='split-row'>
                  <Text className='row-main'>{item.typeLabel || item.questionType}</Text>
                  <Text className='status-badge'>{percent(item.accuracy)}</Text>
                </View>
                <Text className='row-meta'>已答 {String(item.answeredCount)} · 正确 {String(item.correctCount)} · 错误 {String(item.wrongCount)}</Text>
                <View className='progress-track'>
                  <View className={`progress-fill ${progressBucket(item.accuracy)}`} />
                </View>
              </View>
            ))}
          </View>
        ) : <View className='empty-state'>暂无题型统计，开始刷题后这里会显示强弱项。</View>}
      </View>

      <View className='section-block'>
        <Text className='section-heading'>最近练习</Text>
        {practiceHistory.length ? (
          <View className='list-stack'>
            {practiceHistory.map(item => (
              <View className='list-row' key={item.id}>
                <View className='split-row'>
                  <Text className='row-main'>{practiceTitle(item)}</Text>
                  <Text className={`status-badge ${sessionStatusClass(item.status)}`}>{sessionStatusLabel(item.status)}</Text>
                </View>
                <Text className='row-meta'>
                  {modeLabel(item.mode)} · 已答 {String(item.answeredCount || 0)} / {String(item.questionCount || 0)} · 正确率 {percent(item.accuracy)}
                </Text>
                <Text className='row-meta'>开始 {dateText(item.startedAt)}{item.submittedAt ? ` · 交卷 ${dateText(item.submittedAt)}` : ''}</Text>
                <View className='toolbar compact-toolbar'>
                  {item.status === 'active' ? (
                    <Button className='primary-button' onClick={() => Taro.navigateTo({ url: `/pages/student/practice/index?practiceSessionId=${item.id}` })}>继续</Button>
                  ) : null}
                  {item.reportId ? (
                    <Button className='secondary-button' onClick={() => Taro.navigateTo({ url: `/pages/student/reports/index?practiceSessionId=${item.id}` })}>报告</Button>
                  ) : null}
                </View>
              </View>
            ))}
          </View>
        ) : <View className='empty-state'>还没有练习历史，可以先从题库入口开始。</View>}
      </View>

      <View className='section-block'>
        <Text className='section-heading'>目标与考试</Text>
        <View className='list-stack'>
          <View className='list-row'>
            <Text className='row-main'>{profile?.target?.regionName || '未选择地区'}{profile?.target?.schoolName ? ` · ${profile.target.schoolName}` : ''}</Text>
            <Text className='row-meta'>{profile?.target?.majorName || '暂无目标专业'}</Text>
          </View>
          {countdowns.slice(0, 3).map(item => (
            <View className='list-row' key={String(item.id || item.examName)}>
              <Text className='row-main'>{String(item.examName || '考试')}</Text>
              <Text className='row-meta'>剩余 {String(item.daysLeft ?? '-')} 天</Text>
            </View>
          ))}
        </View>
        <View className='toolbar wrap'>
          <Button className='secondary-button' onClick={() => Taro.navigateTo({ url: '/pages/student/region/index' })}>切换地区</Button>
          <Button className='secondary-button' onClick={() => Taro.navigateTo({ url: '/pages/student/review/index?type=wrong' })}>错题本</Button>
          <Button className='secondary-button' onClick={() => Taro.navigateTo({ url: '/pages/student/review/index?type=favorite' })}>收藏夹</Button>
          <Button className='secondary-button' onClick={() => Taro.navigateTo({ url: '/pages/student/reports/index' })}>练习报告</Button>
        </View>
      </View>

      <View className='section-block'>
        <Text className='section-heading'>消息中心</Text>
        <View className='grid-two'>
          <View className='metric compact-metric'><Text className='metric-value'>{String(notificationSummary.unread || 0)}</Text><Text className='metric-label'>未读消息</Text></View>
          <View className='metric compact-metric'><Text className='metric-value'>{String((notificationSummary.read || 0) + (notificationSummary.archived || 0))}</Text><Text className='metric-label'>已处理消息</Text></View>
        </View>
        <View className='toolbar wrap compact-toolbar notification-toolbar'>
          {([
            ['', '全部'],
            ['unread', '未读'],
            ['read', '已读'],
            ['archived', '归档'],
          ] as Array<['' | ProfileNotificationStatus, string]>).map(([value, label]) => (
            <Button
              key={value || 'all'}
              className={`secondary-button ${notificationFilter === value ? 'active' : ''}`}
              loading={notificationBusy === 'reload' && notificationFilter === value}
              onClick={() => void changeNotificationFilter(value)}
            >
              {label}
            </Button>
          ))}
          <Button className='secondary-button' onClick={() => Taro.navigateTo({ url: '/pages/student/notifications/index' })}>消息中心</Button>
        </View>
        {notifications.length ? (
          <View className='list-stack'>
            {notifications.map(item => (
              <View className={`list-row notification-row ${item.status === 'unread' ? 'active' : ''}`} key={item.id}>
                <View className='split-row'>
                  <Text className='row-main'>{item.title || notificationTypeLabel(item.notificationType)}</Text>
                  <Text className={`status-badge ${notificationStatusClass(item.status, item.severity)}`}>{notificationStatusLabel(item.status)}</Text>
                </View>
                <Text className='row-meta'>{notificationTypeLabel(item.notificationType)} · {dateText(item.createdAt)}</Text>
                <Text className='row-meta notification-message'>{item.message || '暂无消息内容'}</Text>
                <View className='toolbar compact-toolbar'>
                  {item.status !== 'read' ? (
                    <Button className='secondary-button' loading={notificationBusy === `${item.id}:read`} onClick={() => void markNotification(item, 'read')}>已读</Button>
                  ) : null}
                  {item.status !== 'archived' ? (
                    <Button className='secondary-button' loading={notificationBusy === `${item.id}:archived`} onClick={() => void markNotification(item, 'archived')}>归档</Button>
                  ) : null}
                  {item.actionLabel ? <Text className='row-meta notification-action-text'>{item.actionLabel}</Text> : null}
                </View>
              </View>
            ))}
          </View>
        ) : <View className='empty-state'>暂无消息。反馈处理、勋章发放和积分兑换结果会出现在这里。</View>}
      </View>

      <View className='section-block'>
        <Text className='section-heading'>积分任务</Text>
        <View className='grid-two'>
          <View className='metric compact-metric'><Text className='metric-value'>{String(profile?.score ?? 0)}</Text><Text className='metric-label'>当前积分</Text></View>
          <View className='metric compact-metric'><Text className='metric-value'>{String(activityTasks.filter(item => (item.remainingClaims ?? 0) > 0).length)}</Text><Text className='metric-label'>可领取任务</Text></View>
        </View>
        {activityTasks.length ? (
          <View className='list-stack points-list'>
            {activityTasks.map(item => {
              const canClaim = item.taskType === 'manual' && (item.remainingClaims ?? 0) > 0;
              return (
                <View className='list-row' key={item.id}>
                  <View className='split-row'>
                    <Text className='row-main'>{item.title || taskTypeLabel(item.taskType)}</Text>
                    <Text className={`status-badge ${canClaim ? '' : 'warning'}`}>{canClaim ? '可领取' : item.claimedInCurrentPeriod ? '已领取' : '需完成'}</Text>
                  </View>
                  <Text className='row-meta'>{taskTypeLabel(item.taskType)} · {periodLabel(item.periodType)} · 奖励 {String(item.rewardPoints || 0)} 积分</Text>
                  {item.description ? <Text className='row-meta notification-message'>{item.description}</Text> : null}
                  <View className='toolbar compact-toolbar'>
                    {canClaim ? (
                      <Button className='primary-button' loading={pointsBusy === `task:${item.id}`} onClick={() => void claimTask(item)}>领取积分</Button>
                    ) : (
                      <Text className='row-meta notification-action-text'>{item.taskType === 'manual' ? '本周期已达领取上限' : '完成对应学习动作后由后端校验'}</Text>
                    )}
                  </View>
                </View>
              );
            })}
          </View>
        ) : <View className='empty-state'>暂无积分任务。运营后台配置后会在这里展示。</View>}
      </View>

      <View className='section-block'>
        <Text className='section-heading'>积分兑换</Text>
        {exchangeItems.length ? (
          <View className='list-stack'>
            {exchangeItems.map(item => {
              const stockLeft = item.stockRemaining;
              const outOfStock = stockLeft !== null && stockLeft !== undefined && stockLeft <= 0;
              const notEnoughScore = Number(profile?.score || 0) < Number(item.costPoints || 0);
              return (
                <View className='list-row' key={item.id}>
                  <View className='split-row'>
                    <Text className='row-main'>{item.title || item.code || '兑换商品'}</Text>
                    <Text className={`status-badge ${outOfStock || notEnoughScore ? 'warning' : ''}`}>{String(item.costPoints || 0)} 积分</Text>
                  </View>
                  <Text className='row-meta'>{exchangeTypeLabel(item.itemType)} · 库存 {stockLeft === null || stockLeft === undefined ? '不限' : String(stockLeft)} · 每人 {String(item.perUserLimit || 1)} 次</Text>
                  {item.description ? <Text className='row-meta notification-message'>{item.description}</Text> : null}
                  <View className='toolbar compact-toolbar'>
                    <Button
                      className={outOfStock || notEnoughScore ? 'secondary-button' : 'primary-button'}
                      disabled={outOfStock || notEnoughScore}
                      loading={pointsBusy === `exchange:${item.id}`}
                      onClick={() => void redeemItem(item)}
                    >
                      {outOfStock ? '库存不足' : notEnoughScore ? '积分不足' : '立即兑换'}
                    </Button>
                  </View>
                </View>
              );
            })}
          </View>
        ) : <View className='empty-state'>暂无可兑换商品。优惠券、资料或人工奖品会在配置后显示。</View>}
      </View>

      <View className='section-block'>
        <Text className='section-heading'>积分明细</Text>
        {scoreEvents.length ? (
          <View className='list-stack'>
            {scoreEvents.map((item, index) => (
              <View className='list-row' key={String(item.id || index)}>
                <View className='split-row'>
                  <Text className='row-main'>{String(item.eventType || item.type || '积分变动')}</Text>
                  <Text className={`status-badge ${Number(item.points || 0) < 0 ? 'warning' : ''}`}>{Number(item.points || 0) > 0 ? '+' : ''}{String(item.points || 0)}</Text>
                </View>
                <Text className='row-meta'>余额 {String(item.balanceAfter ?? '-')} · {dateText(String(item.createdAt || ''))}</Text>
              </View>
            ))}
          </View>
        ) : <View className='empty-state'>暂无积分明细。</View>}
      </View>

      <View className='section-block'>
        <Text className='section-heading'>会员套餐</Text>
        <View className='list-stack'>
          {plans.slice(0, 4).map(item => (
            <View className='list-row' key={item.id} onClick={() => Taro.navigateTo({ url: `/pages/student/checkout/index?planId=${encodeURIComponent(item.id)}${profile?.target?.regionId ? `&regionId=${encodeURIComponent(profile.target.regionId)}` : ''}` })}>
              <Text className='row-main'>{item.name} · ¥{String(item.price ?? 0)}</Text>
              <Text className='row-meta'>{item.days === -1 ? '永久' : `${item.days || 0} 天`} {item.badge ? ` · ${item.badge}` : ''}</Text>
            </View>
          ))}
        </View>
        <View className='toolbar wrap'>
          <Button className='primary-button' onClick={() => Taro.navigateTo({ url: `/pages/student/checkout/index${bestPlan?.id ? `?planId=${encodeURIComponent(bestPlan.id)}` : profile?.target?.regionId ? `?regionId=${encodeURIComponent(profile.target.regionId)}` : ''}` })}>开通会员</Button>
        </View>
      </View>

      <View className='section-block'>
        <Text className='section-heading'>激活码</Text>
        <View className='toolbar'>
          <Input className='input' placeholder='输入激活码' value={activationCode} onInput={event => setActivationCode(String(event.detail.value || ''))} />
          <Button className='primary-button' onClick={handleRedeem}>兑换</Button>
        </View>
      </View>

      <View className='section-block'>
        <Text className='section-heading'>订单</Text>
        <View className='list-stack'>
          {orders.slice(0, 5).map(item => (
            <View className='list-row' key={item.id} onClick={() => Taro.navigateTo({ url: `/pages/student/order-detail/index?orderNo=${encodeURIComponent(item.orderNo)}` })}>
              <Text className='row-main'>{item.productName || item.orderNo}</Text>
              <Text className='row-meta'>{item.status} · ¥{((item.amountCents || 0) / 100).toFixed(2)}</Text>
            </View>
          ))}
        </View>
      </View>

      <View className='section-block'>
        <Text className='section-heading'>成长数据</Text>
        <View className='toolbar'>
          <Button className='primary-button' onClick={handleCheckIn}>签到</Button>
          <Button className='secondary-button' onClick={() => Taro.navigateTo({ url: '/pages/student/catalog/index' })}>刷题</Button>
        </View>
        <View className='grid-two'>
          <View className='metric'><Text className='metric-value'>{String(badges.length)}</Text><Text className='metric-label'>勋章</Text></View>
          <View className='metric'><Text className='metric-value'>{String(wrongBook?.unresolvedWrong ?? 0)}</Text><Text className='metric-label'>待解决错题</Text></View>
          <View className='metric'><Text className='metric-value'>{String(favoriteStats?.favoriteQuestions ?? 0)}</Text><Text className='metric-label'>收藏题目</Text></View>
          <View className='metric'><Text className='metric-value'>{percent(reportStats?.avgAccuracy)}</Text><Text className='metric-label'>报告平均正确率</Text></View>
        </View>
      </View>

      {message ? <Text className='success-text'>{message}</Text> : null}
      {error ? <Text className='error-text'>{error}</Text> : null}
    </View>
  );
}
