<script setup lang="ts">
import { ref, computed, onMounted, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { useRouter, useRoute, type LocationQueryRaw } from 'vue-router'
import { get, post, put } from '@/utils/request'
import { useAuthStore } from '@/stores/auth'
import { useCopyTradingStore } from '@/stores/copyTrading'
import { storeToRefs } from 'pinia'
import { useToast } from '@/composables/useToast'
import TransferModal from '@/components/common/TransferModal.vue'

const { t, locale } = useI18n()
const router = useRouter()
const route = useRoute()
const auth = useAuthStore()
const copyTradingStore = useCopyTradingStore()
const { isTrader } = storeToRefs(copyTradingStore)
const toast = useToast()

// ── Tab / Sort ─────────────────────────────────────────────────────────────
type Tab     = 'normal' | 'lossless' | 'favorite'
type SortKey = 'comprehensive' | 'winRate' | 'profit'

const activeTab = ref<Tab>('normal')
const sortKey   = ref<SortKey>('comprehensive')

/** 与路由 ?tab= 同步（页脚「无损跟单」等深链） */
function applyTabFromRoute() {
  const raw = route.query.tab
  const v = Array.isArray(raw) ? raw[0] : raw
  if (v === 'lossless') {
    activeTab.value = 'lossless'
  } else if (v === 'favorite') {
    activeTab.value = 'favorite'
  } else {
    activeTab.value = 'normal'
  }
}

function setCopyTab(tab: Tab) {
  activeTab.value = tab
  const nextQuery: LocationQueryRaw = { ...route.query }
  if (tab === 'lossless') {
    nextQuery.tab = 'lossless'
  } else if (tab === 'favorite') {
    nextQuery.tab = 'favorite'
  } else {
    delete nextQuery.tab
  }
  void router.replace({ path: route.path, query: nextQuery })
}

const SORT_TYPE: Record<SortKey, number> = {
  comprehensive: 10,
  winRate:       30,
  profit:        20,
}

const sorts = computed(() => [
  { key: 'comprehensive' as SortKey, label: t('copyTrade.comprehensive') },
  { key: 'winRate' as SortKey, label: t('copyTrade.winRate14d') },
  { key: 'profit' as SortKey, label: t('copyTrade.profit14d') },
])

// ── Trader data ────────────────────────────────────────────────────────────
interface Trader {
  id: string | number
  name: string
  avatar: string | null
  avatarError: boolean
  lossless: boolean
  level: number          // 交易员等级 (1=初级, 2=L2, ...)
  profit14d: number      // 近14天收益率
  winRate: number        // 近14天胜率
  profitUsdt: string     // 收益(USDT)
  profitShare: string    // 分润比例
  yield14: number[]      // 14天走势数据
  followers: number
  maxFollowers: number
  days: number
  trades: number
  isFavorited?: boolean
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
function mapTrader(r: any): Trader {
  const profit14d = parseFloat(r.dayYield14 ?? r.dayYield30 ?? r.profit30d ?? '0') || 0
  const winRate   = parseFloat(r.winRate14 ?? r.winRate ?? r.winningRate ?? '0') || 0
  const followers = parseInt(r.followCustomer ?? r.followCount ?? r.followers ?? '0', 10) || 0
  const maxFollowers = parseInt(r.maxFollow ?? r.maxFollowCount ?? '0', 10) || 0
  const days      = parseInt(r.tradingDays ?? r.registerDays ?? r.days ?? '0', 10) || 0
  const trades    = parseInt(r.orderDeal14 ?? r.tradeCount ?? r.trades ?? '0', 10) || 0

  const profitV = parseFloat(r.profitAmount ?? r.totalProfit ?? '0') || 0
  const profitUsdt = profitV === 0 ? '--'
    : (profitV >= 0 ? '+' : '') + profitV.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })

  const shareV = parseFloat(r.dividendPercent ?? r.profitShare ?? r.shareRatio ?? '0') || 0
  const profitShare = shareV > 0 ? shareV.toFixed(0) + '%' : '--'

  // yield14List: [{dayYield14: number, dateTime: ...}, ...]
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  const yield14 = Array.isArray(r.yield14List)
    ? r.yield14List.map((y: any) => parseFloat(y.dayYield14 ?? y.yield ?? '0') || 0)
    : []

  return {
    id: r.id ?? r.traderId ?? r.memberId ?? Math.random(),
    name: r.nickname ?? r.nickName ?? r.name ?? r.realName ?? t('copyTrade.defaultTraderName'),
    avatar: r.avatar ?? r.headImg ?? r.logo ?? null,
    avatarError: false,
    lossless:  !!(r.specialTrader ?? r.protectFlag ?? r.lossless),
    level: parseInt(r.traderLevelId ?? r.level ?? '0', 10) || 0,
    profit14d,
    winRate,
    profitUsdt,
    profitShare,
    yield14,
    followers,
    maxFollowers,
    days,
    trades,
    isFavorited: !!(r.isFavorite ?? r.isFavorited ?? r.favorite ?? false),
  }
}

function levelLabel(level: number): string {
  if (!level) {
    return ''
  }
  if (level === 1) {
    return t('copyTrade.levelJunior')
  }
  return `L${level}`
}

function sparklinePoints(yields: number[]): string {
  if (yields.length < 2) return ''
  const min = Math.min(...yields)
  const max = Math.max(...yields)
  const range = max - min || 1
  const w = 100 / (yields.length - 1)
  return yields.map((v, i) => {
    const x = +(i * w).toFixed(2)
    const y = +(36 - ((v - min) / range) * 32 + 2).toFixed(2)
    return `${x},${y}`
  }).join(' ')
}

function sparklineFill(yields: number[]): string {
  if (yields.length < 2) return ''
  const pts = sparklinePoints(yields)
  const parts = pts.split(' ')
  const lastX = parts[parts.length - 1].split(',')[0]
  const firstX = parts[0].split(',')[0]
  return `${pts} ${lastX},40 ${firstX},40`
}

const traders   = ref<Trader[]>([])
const loading   = ref(false)
const loadError = ref('')
const pageSize  = 30

// ── Wallet & my-stats (requires login) ────────────────────────────────────
interface FollowWallet {
  cumulativePnl:    number
  availableBalance: number
  unrealizedPnl:    number
}
interface TraderStats {
  nickName:        string
  avatar:          string | null
  followerCount:   number
  tradingDays:     number
  profitAmount:    number
  level:           number
}
const followWallet     = ref<FollowWallet | null>(null)
const myStats          = ref<{ followCount: number } | null>(null)
const followedCount     = ref(0)
const traderStats      = ref<TraderStats | null>(null)
const traderAvatarError = ref(false)

// ── Computed list ──────────────────────────────────────────────────────────
// 服务端已按 traderType 过滤（登录用 trader-list，未登录用 top-trader-list），直接展示
const filteredTraders = computed(() => traders.value)

const isFavoriteTab = computed(() => activeTab.value === 'favorite')

const emptyListHint = computed(() => {
  if (isFavoriteTab.value) {
    return t('copyTrade.emptyFavoriteHint')
  }
  if (activeTab.value === 'lossless') {
    return t('copyTrade.emptyTraderListLossless')
  }
  return t('copyTrade.emptyTraderListDefault')
})

// ── API calls ──────────────────────────────────────────────────────────────

async function fetchTopTraders() {
  loading.value   = true
  loadError.value = ''
  try {
    const traderType = activeTab.value === 'lossless' ? 1 : 0
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const res: any = await get('/follow/customer/top-trader-list', { traderType })
    const list = Array.isArray(res) ? res : (res?.records ?? res?.list ?? res?.data ?? [])
    const rows = Array.isArray(list) ? list : []
    traders.value = rows.map(mapTrader)
    if (auth.isLoggedIn) {
      await fetchFavorites()
    }
  } catch {
    loadError.value = t('copyTrade.loadTraderListFailed')
    traders.value = []
  } finally {
    loading.value = false
  }
}

async function fetchFavorites() {
  if (!auth.isLoggedIn || traders.value.length === 0) return
  try {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const res: any = await post('/follow/favorite/list', { currentPage: 1, pageSize: 200 })
    const list = Array.isArray(res) ? res : (res?.records ?? res?.list ?? res?.data ?? [])
    if (!Array.isArray(list) || list.length === 0) return
    const favIds = new Set(list.map((r: any) => String(r.id ?? r.traderId ?? r.trader_id ?? '')))
    traders.value.forEach(t => { t.isFavorited = favIds.has(String(t.id)) })
  } catch { /* silent */ }
}

async function fetchFavoriteList() {
  loading.value   = true
  loadError.value = ''
  try {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const res: any = await post('/follow/favorite/list', { currentPage: 1, pageSize: 200 })
    const list = Array.isArray(res) ? res : (res?.records ?? res?.list ?? res?.data ?? [])
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    traders.value = (Array.isArray(list) ? list : []).map((r: any) => ({ ...mapTrader(r), isFavorited: true }))
  } catch {
    loadError.value = t('copyTrade.loadFavoritesFailed')
  } finally {
    loading.value = false
  }
}

async function fetchTraderList() {
  loading.value   = true
  loadError.value = ''
  try {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const res: any = await post('/follow/customer/trader-list', {
      pageNum: 1,
      pageSize,
      orderBy:    SORT_TYPE[sortKey.value],
      traderType: activeTab.value === 'lossless' ? 1 : 0,
    })
    const list = Array.isArray(res) ? res : (res?.records ?? res?.list ?? res?.data ?? [])
    traders.value = list.map(mapTrader)
    await fetchFavorites()
  } catch {
    await fetchTopTraders()
  } finally {
    loading.value = false
  }
}

async function fetchWallet() {
  try {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const res: any = await get('/swap/follow-wallet/get')
    followWallet.value = {
      cumulativePnl:    parseFloat(res?.totalRevenue ?? res?.totalProfit ?? '0') || 0,
      availableBalance: parseFloat(res?.availableBalance ?? '0') || 0,
      unrealizedPnl:    parseFloat(res?.currentRevenue ?? res?.unrealizedPnl ?? '0') || 0,
    }
  } catch { /* silent — not critical */ }
}

async function fetchMyStats() {
  try {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const item: any = await copyTradingStore.fetchFollowerInfo()
    if (!item) return

    if (copyTradingStore.isTrader) {
      traderAvatarError.value = false
      traderStats.value = {
        nickName:     item.nickname ?? item.nickName ?? '',
        avatar:       item.avatar ?? null,
        followerCount: 0,
        tradingDays:  0,
        profitAmount: 0,
        level:        parseInt(item.traderLevelId ?? '0', 10) || 0,
      }
      try {
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        const info: any = await put(`/follow/customer/trader-info/${item.id}`)
        const d = Array.isArray(info) ? info[0] : info
        if (d && traderStats.value) {
          traderStats.value.followerCount = parseInt(d.following ?? '0', 10) || 0
          traderStats.value.tradingDays   = parseInt(d.tradingDays ?? '0', 10) || 0
          traderStats.value.profitAmount  = parseFloat(d.profitAmount ?? '0') || 0
        }
      } catch { /* silent */ }
    } else {
      myStats.value = {
        followCount: parseInt(item.followCount ?? item.defaultFollowCustomer ?? '0', 10) || 0,
      }
    }
  } catch { /* silent */ }
}

async function fetchFollowedCount() {
  try {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const res: any = await post('/follow/follow/following', { currentPage: 1, pageSize: 1 })
    const total = parseInt(res?.total ?? '0', 10)
    if (total > 0) {
      followedCount.value = total
    } else {
      const list = Array.isArray(res) ? res : (res?.records ?? res?.list ?? res?.data ?? [])
      followedCount.value = list.length
    }
  } catch { /* silent */ }
}

function fetchListByTab() {
  if (!auth.isLoggedIn) { fetchTopTraders(); return }
  if (activeTab.value === 'favorite') fetchFavoriteList()
  else fetchTraderList()
}

onMounted(async () => {
  applyTabFromRoute()
  if (auth.isLoggedIn) {
    const listFetch = activeTab.value === 'favorite' ? fetchFavoriteList() : fetchTraderList()
    await Promise.all([listFetch, fetchWallet(), fetchMyStats(), fetchFollowedCount()])
  } else {
    copyTradingStore.reset()
    await fetchTopTraders()
  }
})

watch(
  () => route.query.tab,
  () => {
    applyTabFromRoute()
  },
)

// Re-fetch when sort or tab changes
watch([sortKey, activeTab], () => {
  fetchListByTab()
})

// ── Favorite actions ───────────────────────────────────────────────────────
async function toggleFavorite(trader: Trader, e: Event) {
  e.stopPropagation()
  if (!auth.isLoggedIn) { router.push('/login'); return }
  const wasFavorited = trader.isFavorited
  // 乐观更新：先改 UI，失败再还原
  const target = traders.value.find(item => item.id === trader.id)
  if (target) target.isFavorited = !wasFavorited
  try {
    if (wasFavorited) {
      await put(`/follow/favorite/unfavorite/${trader.id}`)
      // 收藏 tab 下取消收藏，直接移出列表
      if (activeTab.value === 'favorite') {
        traders.value = traders.value.filter(item => item.id !== trader.id)
      }
    } else {
      await put(`/follow/favorite/${trader.id}`)
      toast.success(t('copyTrade.favoritedToast'))
    }
  } catch (err) {
    // 还原
    if (target) target.isFavorited = wasFavorited
    toast.error((err as Error).message || t('common.operationFailed'))
  }
}

// ── Transfer modal ─────────────────────────────────────────────────────────
const showTransfer = ref(false)

// ── Helpers ────────────────────────────────────────────────────────────────
function initials(name: string) {
  return name.charAt(0).toUpperCase()
}

function fmtFollowers(n: number) {
  return n >= 1000 ? (n / 1000).toFixed(1) + 'K' : String(n)
}

function fmtMoney(n: number) {
  if (n == null || isNaN(n)) {
    return '0.00'
  }
  const abs = Math.abs(n)
  const isZh = locale.value === 'zh-CN' || locale.value === 'zh-TW'
  if (isZh) {
    if (abs >= 1e8) {
      return (n / 1e8).toFixed(2) + t('copyTrade.unitYi')
    }
    if (abs >= 1e4) {
      return (n / 1e4).toFixed(2) + t('copyTrade.unitWan')
    }
  } else {
    if (abs >= 1e6) {
      return (n / 1e6).toFixed(2) + 'M'
    }
    if (abs >= 1e3) {
      return (n / 1e3).toFixed(2) + 'K'
    }
  }
  return n.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })
}
</script>

<template>
  <main class="ct-main">
    <!-- ── My account quick-nav (logged in only) ─────────── -->
    <div v-if="auth.isLoggedIn" class="ct-my-nav">
      <div class="page-container my-nav-inner">
        <span class="my-nav-label">{{ isTrader ? t('copyTrade.traderIdentity') : t('copyTrade.myFollowing') }}</span>
        <button v-if="!isTrader" class="my-nav-btn" @click="router.push('/copy-trade/my-following')">{{ t('copyTrade.myFollowingAccount') }}</button>
        <button class="my-nav-btn" @click="router.push('/copy-trade/my-lead')">
          {{ isTrader ? t('copyTrade.leadManage') : t('copyTrade.applyLead') }}
        </button>
      </div>
    </div>

    <!-- ── Banner ──────────────────────────────────────────── -->
    <section class="ct-banner">
      <div class="page-container banner-inner">
        <div class="banner-text">
          <h1 class="banner-title">{{ t('copyTrade.pageTitle') }}</h1>
          <p class="banner-desc">{{ t('copyTrade.heroDesc') }}</p>
        </div>

        <!-- 右侧：仅登录后展示 -->
        <div v-if="auth.isLoggedIn" class="banner-img-wrap">
          <div class="banner-orb" />

          <!-- 带单员：展示带单概况 -->
          <div v-if="isTrader && traderStats" class="banner-wallet dark-card">
            <div class="wallet-title-row">
              <div class="wallet-title">{{ t('copyTrade.traderOverview') }}</div>
            </div>
            <div class="trader-profile-row">
              <img
                v-if="traderStats.avatar && !traderAvatarError"
                :src="traderStats.avatar"
                alt=""
                class="trader-mini-avatar-img"
                referrerpolicy="no-referrer"
                @error="traderAvatarError = true"
              />
              <div v-else class="trader-mini-avatar">{{ traderStats.nickName.charAt(0).toUpperCase() }}</div>
              <div class="trader-mini-name">{{ traderStats.nickName }}</div>
            </div>
            <div class="wallet-row">
              <div class="wallet-item">
                <div class="wallet-label">{{ t('copyTrade.copyFollowersCount') }}</div>
                <div class="wallet-val num text-up">{{ traderStats.followerCount }}</div>
              </div>
              <div class="wallet-item">
                <div class="wallet-label">{{ t('copyTrade.cumulativeTradingDays') }}</div>
                <div class="wallet-val num">{{ traderStats.tradingDays }}</div>
              </div>
              <div class="wallet-item">
                <div class="wallet-label">{{ t('copyTrade.cumulativeLeadProfit') }}</div>
                <div class="wallet-val num" :class="traderStats.profitAmount >= 0 ? 'text-up' : 'text-down'">
                  {{ traderStats.profitAmount >= 0 ? '+' : '' }}{{ fmtMoney(traderStats.profitAmount) }}
                </div>
              </div>
            </div>
            <button class="wallet-lead-btn" @click="router.push('/copy-trade/my-lead')">{{ t('copyTrade.goLeadManage') }}</button>
          </div>

          <!-- 跟单者：展示跟单钱包 -->
          <div v-else-if="!isTrader && followWallet" class="banner-wallet dark-card">
            <div class="wallet-title-row">
              <div class="wallet-title">{{ t('copyTrade.copyWalletTitle') }}</div>
              <button class="wallet-transfer-btn" @click="showTransfer = true">{{ t('assets.transfer') }}</button>
            </div>
            <div class="wallet-row">
              <div class="wallet-item">
                <div class="wallet-label">{{ t('copyTrade.cumulativePnlUsdt') }}</div>
                <div class="wallet-val num" :class="followWallet.cumulativePnl >= 0 ? 'text-up' : 'text-down'">
                  {{ fmtMoney(followWallet.cumulativePnl) }}
                </div>
              </div>
              <div class="wallet-item">
                <div class="wallet-label">{{ t('copyTrade.availableUsdt') }}</div>
                <div class="wallet-val num">{{ fmtMoney(followWallet.availableBalance) }}</div>
              </div>
              <div class="wallet-item">
                <div class="wallet-label">{{ t('copyTrade.unrealizedPnlUsdtShort') }}</div>
                <div class="wallet-val num" :class="followWallet.unrealizedPnl >= 0 ? 'text-up' : 'text-down'">
                  {{ fmtMoney(followWallet.unrealizedPnl) }}
                </div>
              </div>
            </div>
            <div class="wallet-following">{{ t('copyTrade.followingTradersSummary', { n: followedCount }) }}</div>
          </div>
        </div>
      </div>
    </section>

    <!-- ── Tabs ────────────────────────────────────────────── -->
    <div class="ct-tabs-wrap">
      <div class="page-container">
        <div class="ct-tabs">
          <button class="ct-tab" :class="{ active: activeTab === 'normal' }" @click="setCopyTab('normal')">
            {{ t('copyTrade.normal') }}
          </button>
          <button class="ct-tab" :class="{ active: activeTab === 'lossless' }" @click="setCopyTab('lossless')">
            {{ t('copyTrade.lossless') }}
            <span class="tab-badge">{{ t('copyTrade.newBadge') }}</span>
          </button>
          <button v-if="auth.isLoggedIn" class="ct-tab" :class="{ active: activeTab === 'favorite' }" @click="setCopyTab('favorite')">
            {{ t('copyTrade.favorite') }}
          </button>
        </div>
      </div>
    </div>

    <!-- 无损跟单说明条 -->
    <div v-if="activeTab === 'lossless'" class="lossless-banner">
      <div class="page-container lossless-inner">
        <span class="ll-icon">🛡</span>
        <div>
          <strong>{{ t('copyTrade.losslessShieldTitle') }}</strong>{{ t('copyTrade.losslessShieldDesc') }}
        </div>
        <a href="#lossless-info" class="ll-link">{{ t('copyTrade.learnHowItWorks') }}</a>
      </div>
    </div>

    <!-- ── 筛选栏（收藏 tab 不展示排序）──────────────────── -->
    <div class="filter-bar">
      <div class="page-container filter-inner">
        <div class="sort-tabs">
          <template v-if="!isFavoriteTab">
            <button
              v-for="s in sorts"
              :key="s.key"
              class="sort-tab"
              :class="{ active: sortKey === s.key }"
              @click="sortKey = s.key"
            >{{ s.label }}</button>
          </template>
          <span v-else class="filter-tab-label">{{ t('copyTrade.myStarredTraders') }}</span>
        </div>
        <div class="filter-right">
          <span v-if="!loading" class="filter-count">{{ t('copyTrade.traderTotalCount', { count: filteredTraders.length }) }}</span>
          <span v-else class="filter-count">{{ t('copyTrade.filterLoadingShort') }}</span>
        </div>
      </div>
    </div>

    <!-- ── 交易员列表 ──────────────────────────────────────── -->
    <div class="page-container trader-grid-wrap">
      <!-- Loading skeleton -->
      <div v-if="loading" class="trader-grid">
        <div v-for="i in 6" :key="i" class="trader-card trader-card--skeleton">
          <div class="sk sk-avatar" />
          <div class="sk sk-line" style="width:60%" />
          <div class="sk sk-line" style="width:40%" />
          <div class="sk sk-block" />
        </div>
      </div>

      <!-- Error state -->
      <div v-else-if="loadError" class="empty-state">
        <div class="empty-icon">⚠️</div>
        <div class="empty-text">{{ loadError }}</div>
        <button class="empty-retry" @click="fetchListByTab()">{{ t('common.retry') }}</button>
      </div>

      <!-- Empty state -->
      <div v-else-if="filteredTraders.length === 0" class="empty-state">
        <div class="empty-icon">{{ isFavoriteTab ? '⭐' : '📭' }}</div>
        <div class="empty-text">{{ emptyListHint }}</div>
        <button v-if="isFavoriteTab" class="empty-retry" @click="setCopyTab('normal')">{{ t('copyTrade.browseTraders') }}</button>
      </div>

      <!-- Trader cards -->
      <div v-else class="trader-grid">
        <div
          v-for="tr in filteredTraders" :key="tr.id"
          class="trader-card"
          @click="router.push(`/copy-trade/trader/${tr.id}`)"
        >
          <!-- 头部 -->
          <div class="tc-header">
            <div class="tc-avatar-wrap">
              <img
                v-if="tr.avatar && !tr.avatarError"
                :src="tr.avatar"
                :alt="tr.name"
                class="tc-avatar-img"
                referrerpolicy="no-referrer"
                @error="tr.avatarError = true"
              />
              <div v-else class="tc-avatar" :class="{ 'tc-avatar--lossless': tr.lossless }">
                {{ initials(tr.name) }}
              </div>
              <span v-if="tr.lossless" class="tc-lossless-dot">{{ t('copyTrade.badgeLossless') }}</span>
              <span v-else-if="tr.level" class="tc-level-dot">{{ levelLabel(tr.level) }}</span>
            </div>
            <div class="tc-info">
              <div class="tc-name-row">
                <span class="tc-name">{{ tr.name }}</span>
                <span v-if="tr.lossless" class="tc-lossless-badge">{{ t('copyTrade.badgeLossless') }}</span>
              </div>
              <div class="tc-meta">
                {{ t('copyTrade.metaDaysTrades', { days: tr.days, trades: tr.trades }) }}
                <span v-if="tr.maxFollowers > 0" class="tc-follow-count">{{ fmtFollowers(tr.followers) }}/{{ fmtFollowers(tr.maxFollowers) }}</span>
              </div>
            </div>
            <div class="tc-header-right">
              <button
                v-if="auth.isLoggedIn"
                class="tc-fav-btn"
                :class="{ active: tr.isFavorited }"
                @click="toggleFavorite(tr, $event)"
              >
                <svg width="14" height="14" viewBox="0 0 24 24" :fill="tr.isFavorited ? 'currentColor' : 'none'" stroke="currentColor" stroke-width="2">
                  <path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/>
                </svg>
              </button>
              <button
                v-if="auth.isLoggedIn && !isTrader"
                class="tc-follow-btn"
                @click.stop="router.push(`/copy-trade/trader/${tr.id}`)"
              >{{ t('copyTrade.followAction') }}</button>
            </div>
          </div>

          <!-- 3列数据 -->
          <div class="tc-metrics">
            <div class="tc-metric">
              <div class="tc-metric-label">{{ t('copyTrade.profit14d') }}</div>
              <div class="tc-metric-val" :class="tr.profit14d >= 0 ? 'text-up' : 'text-down'">
                {{ tr.profit14d >= 0 ? '+' : '' }}{{ tr.profit14d.toFixed(2) }}%
              </div>
            </div>
            <div class="tc-metric">
              <div class="tc-metric-label">{{ t('copyTrade.profitUsdtBracket') }}</div>
              <div class="tc-metric-val" :class="tr.profitUsdt.startsWith('+') ? 'text-up' : tr.profitUsdt === '--' ? '' : 'text-down'">
                {{ tr.profitUsdt }}
              </div>
            </div>
            <div class="tc-metric">
              <div class="tc-metric-label">{{ t('copyTrade.profitShareRate') }}</div>
              <div class="tc-metric-val">{{ tr.profitShare }}</div>
            </div>
          </div>

          <div class="tc-trend">
            <div class="tc-trend-label">{{ t('copyTrade.trend14Days') }}</div>
            <svg v-if="tr.yield14.length >= 2" viewBox="0 0 100 40" preserveAspectRatio="none" class="tc-sparkline"
              :class="tr.profit14d >= 0 ? 'spark-up' : 'spark-down'">
              <defs>
                <linearGradient :id="`sg-${tr.id}`" x1="0" y1="0" x2="0" y2="1">
                  <stop offset="0%" :stop-color="tr.profit14d >= 0 ? '#0ecb81' : '#ff4d4f'" stop-opacity="0.25"/>
                  <stop offset="100%" :stop-color="tr.profit14d >= 0 ? '#0ecb81' : '#ff4d4f'" stop-opacity="0"/>
                </linearGradient>
              </defs>
              <polygon :points="sparklineFill(tr.yield14)" :fill="`url(#sg-${tr.id})`" />
              <polyline :points="sparklinePoints(tr.yield14)" fill="none" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>
            </svg>
            <div v-else class="tc-trend-empty">--</div>
          </div>

          <div class="tc-winrate-row">
            <span class="tc-winrate-label">{{ t('copyTrade.winRate14d') }}</span>
            <span class="tc-winrate-val">{{ tr.winRate.toFixed(1) }}%</span>
          </div>
        </div>
      </div>
    </div>

    <!-- ── 无损跟单机制说明 ──────────────────────────────── -->
    <div v-if="activeTab === 'lossless'" id="lossless-info" class="lossless-info-section">
      <div class="page-container">
        <h2 class="ll-info-title">{{ t('copyTrade.losslessInfoHeading') }}</h2>
        <div class="ll-info-grid">
          <div class="ll-info-card">
            <div class="ll-info-icon">📋</div>
            <h3>{{ t('copyTrade.llInfoCard1Title') }}</h3>
            <p>{{ t('copyTrade.llInfoCard1Body') }}</p>
          </div>
          <div class="ll-info-card">
            <div class="ll-info-icon">✅</div>
            <h3>{{ t('copyTrade.llInfoCard2Title') }}</h3>
            <p>{{ t('copyTrade.llInfoCard2Body') }}</p>
          </div>
          <div class="ll-info-card">
            <div class="ll-info-icon">🛡</div>
            <h3>{{ t('copyTrade.llInfoCard3Title') }}</h3>
            <p>{{ t('copyTrade.llInfoCard3Body') }}</p>
          </div>
          <div class="ll-info-card">
            <div class="ll-info-icon">⚠️</div>
            <h3>{{ t('copyTrade.llInfoCard4Title') }}</h3>
            <p>{{ t('copyTrade.llInfoCard4Body') }}</p>
          </div>
        </div>
      </div>
    </div>

  </main>

  <!-- ── Transfer Modal ── -->
  <Teleport to="body">
    <TransferModal
      v-if="showTransfer"
      default-from="SPOT"
      default-to="FOLLOW"
      @close="showTransfer = false"
      @success="fetchWallet"
    />
  </Teleport>
</template>

<style scoped>
.ct-main { padding-top: var(--header-height); background: var(--color-bg-primary); min-height: 100vh; }

/* ── My-nav quick links ── */
.ct-my-nav {
  background: rgba(240,185,11,0.05);
  border-bottom: 1px solid rgba(240,185,11,0.15);
  padding: 8px 0;
}
.my-nav-inner { display: flex; align-items: center; gap: 10px; }
.my-nav-label { font-size: 12px; color: var(--color-text-muted); flex: 1; }
.my-nav-btn {
  padding: 5px 14px; font-size: 12px; border-radius: 6px;
  background: transparent; border: 1px solid rgba(240,185,11,0.3);
  color: var(--color-primary); cursor: pointer; transition: all 0.2s;
}
.my-nav-btn:hover { background: rgba(240,185,11,0.08); }

/* ── Banner ── */
.ct-banner {
  background: linear-gradient(135deg, #0f0f0f 0%, #1a1400 50%, #0f0f0f 100%);
  border-bottom: 1px solid var(--color-border);
  padding: 64px 0 56px;
}
.banner-inner {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 48px;
  align-items: center;
}
.banner-title {
  font-size: 40px; font-weight: 700;
  color: var(--color-text-primary); margin-bottom: 12px;
}
.banner-desc {
  font-size: 16px; color: var(--color-text-secondary);
  margin-bottom: 32px; line-height: 1.6;
}
.banner-stats { display: flex; align-items: center; gap: 24px; }
.bstat-val { font-size: 22px; font-weight: 700; color: var(--color-primary); font-family: var(--font-family-num); }
.bstat-lbl { font-size: 12px; color: var(--color-text-muted); margin-top: 4px; }
.bstat-divider { width: 1px; height: 36px; background: var(--color-border); }

.banner-img-wrap { position: relative; display: flex; justify-content: center; }
.banner-orb {
  position: absolute;
  width: 280px; height: 280px; border-radius: 50%;
  background: radial-gradient(circle, rgba(240,185,11,0.12) 0%, transparent 70%);
  top: 50%; left: 50%; transform: translate(-50%, -50%);
}

/* 跟单钱包卡片（已登录） */
.banner-wallet {
  position: relative;
  width: 100%; max-width: 380px;
  padding: 24px;
}
.wallet-title { font-size: 13px; color: var(--color-text-muted); margin-bottom: 8px; }
.wallet-title-row { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; }
.wallet-transfer-btn {
  padding: 5px 14px; font-size: 12px; border-radius: 6px;
  background: transparent; border: 1px solid rgba(240,185,11,0.3);
  color: var(--color-primary); cursor: pointer; transition: all 0.2s;
}
.wallet-transfer-btn:hover { background: rgba(240,185,11,0.08); }
.trader-badge {
  font-size: 11px; font-weight: 600;
  background: rgba(240,185,11,0.12); color: var(--color-primary);
  border: 1px solid rgba(240,185,11,0.3); border-radius: 4px; padding: 2px 8px;
}
.trader-profile-row { display: flex; align-items: center; gap: 10px; margin-bottom: 16px; }
.trader-mini-avatar {
  width: 36px; height: 36px; border-radius: 50%; flex-shrink: 0;
  background: var(--color-primary); color: #000;
  font-size: 14px; font-weight: 700;
  display: flex; align-items: center; justify-content: center;
}
.trader-mini-avatar-img { width: 36px; height: 36px; border-radius: 50%; object-fit: cover; flex-shrink: 0; }
.trader-mini-name { font-size: 15px; font-weight: 600; color: var(--color-text-primary); }
.wallet-lead-btn {
  width: 100%; margin-top: 14px;
  padding: 9px; background: var(--color-primary); color: #000;
  font-size: 13px; font-weight: 600; border-radius: 8px; border: none;
  cursor: pointer; transition: opacity 0.2s; text-align: center;
}
.wallet-lead-btn:hover { opacity: 0.85; }
.wallet-row { display: flex; gap: 0; border-top: 1px solid var(--color-border); padding-top: 16px; margin-bottom: 14px; }
.wallet-item { flex: 1; text-align: center; }
.wallet-item:not(:last-child) { border-right: 1px solid var(--color-border); }
.wallet-label { font-size: 11px; color: var(--color-text-muted); margin-bottom: 4px; }
.wallet-val { font-size: 14px; font-weight: 600; }
.wallet-following { font-size: 12px; color: var(--color-text-muted); text-align: center; }

/* 演示卡片（未登录） */
.banner-card-demo {
  position: relative;
  width: 100%; max-width: 340px;
  background: rgba(255,255,255,0.04);
  border: 1px solid rgba(255,255,255,0.1);
  border-radius: 16px; padding: 20px;
  backdrop-filter: blur(8px);
}
.demo-row { display: flex; align-items: center; gap: 12px; }
.demo-avatar {
  width: 40px; height: 40px; border-radius: 50%;
  background: var(--color-primary); color: #000;
  font-size: 14px; font-weight: 700;
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}
.demo-avatar.lossless { background: #0ecb81; }
.demo-name { font-size: 14px; font-weight: 600; color: var(--color-text-primary); }
.demo-tag { font-size: 12px; color: var(--color-text-muted); margin-top: 2px; }
.demo-btn {
  margin-left: auto; padding: 6px 14px;
  background: var(--color-primary); color: #000;
  font-size: 12px; font-weight: 600;
  border-radius: 8px; border: none; cursor: pointer;
  flex-shrink: 0; transition: opacity 0.2s;
}
.demo-btn:hover { opacity: 0.85; }
.demo-divider { height: 1px; background: rgba(255,255,255,0.06); margin: 16px 0; }
.lossless-badge {
  font-size: 10px; font-weight: 600;
  background: rgba(14,203,129,0.15); color: #0ecb81;
  border: 1px solid rgba(14,203,129,0.3);
  border-radius: 4px; padding: 1px 5px;
  margin-left: 4px; vertical-align: middle;
}

/* ── Tabs ── */
.ct-tabs-wrap {
  background: var(--color-bg-secondary);
  border-bottom: 1px solid var(--color-border);
  position: sticky; top: var(--header-height); z-index: 10;
}
.ct-tabs { display: flex; }
.ct-tab {
  padding: 14px 28px; font-size: 15px; font-weight: 500;
  color: var(--color-text-muted); background: transparent;
  border: none; cursor: pointer;
  border-bottom: 2px solid transparent;
  transition: color 0.2s, border-color 0.2s;
  display: flex; align-items: center; gap: 6px;
}
.ct-tab:hover { color: var(--color-text-primary); }
.ct-tab.active { color: var(--color-primary); border-bottom-color: var(--color-primary); }
.tab-badge {
  font-size: 10px; font-weight: 700;
  background: var(--color-primary); color: #000;
  padding: 1px 5px; border-radius: 4px;
}

/* ── 无损跟单 banner ── */
.lossless-banner {
  background: rgba(14,203,129,0.06);
  border-bottom: 1px solid rgba(14,203,129,0.15);
  padding: 10px 0;
}
.lossless-inner {
  display: flex; align-items: center; gap: 10px;
  font-size: 13px; color: var(--color-text-secondary);
}
.ll-icon { font-size: 16px; flex-shrink: 0; }
.ll-link { margin-left: auto; color: #0ecb81; font-size: 12px; white-space: nowrap; }
.ll-link:hover { text-decoration: underline; }

/* ── Filter bar ── */
.filter-bar { padding: 16px 0; border-bottom: 1px solid var(--color-border); }
.filter-inner { display: flex; align-items: center; justify-content: space-between; }
.sort-tabs { display: flex; gap: 4px; }
.sort-tab {
  padding: 6px 16px; font-size: 13px;
  color: var(--color-text-muted); background: transparent;
  border: 1px solid transparent; border-radius: 20px; cursor: pointer;
  transition: all 0.2s;
}
.sort-tab:hover { color: var(--color-text-primary); background: rgba(255,255,255,0.04); }
.sort-tab.active { color: var(--color-primary); border-color: var(--color-primary); background: rgba(240,185,11,0.06); }
.filter-count { font-size: 13px; color: var(--color-text-muted); }
.filter-tab-label { font-size: 14px; font-weight: 500; color: var(--color-text-primary); }

/* ── Trader grid ── */
.trader-grid-wrap { padding: 24px 0 48px; }
.trader-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
}

/* Skeleton */
.trader-card--skeleton { pointer-events: none; }
.sk {
  background: rgba(255,255,255,0.06);
  border-radius: 6px;
  animation: sk-pulse 1.4s ease infinite;
}
.sk-avatar { width: 44px; height: 44px; border-radius: 50%; margin-bottom: 12px; }
.sk-line { height: 14px; margin-bottom: 8px; }
.sk-block { height: 60px; margin-top: 16px; }
@keyframes sk-pulse {
  0%, 100% { opacity: 1; }
  50%       { opacity: 0.4; }
}

/* Empty / Error */
.empty-state {
  grid-column: 1 / -1;
  text-align: center; padding: 60px 20px;
}
.empty-icon { font-size: 36px; margin-bottom: 12px; }
.empty-text { color: var(--color-text-muted); font-size: 14px; margin-bottom: 16px; }
.empty-retry {
  padding: 8px 24px; border: 1px solid var(--color-border);
  border-radius: 8px; cursor: pointer;
  color: var(--color-text-secondary); background: transparent;
  font-size: 13px; transition: border-color 0.2s;
}
.empty-retry:hover { border-color: var(--color-primary); color: var(--color-primary); }

/* Trader card */
.trader-card {
  background: var(--color-bg-card);
  border: 1px solid var(--color-border);
  border-radius: 12px; padding: 20px;
  cursor: pointer;
  transition: border-color 0.2s, transform 0.2s, box-shadow 0.2s;
}
.trader-card:hover {
  border-color: rgba(240,185,11,0.3);
  transform: translateY(-2px);
  box-shadow: 0 8px 24px rgba(0,0,0,0.3);
}
/* ── 交易员卡片（App 风格） ── */
.tc-header { display: flex; align-items: flex-start; gap: 10px; margin-bottom: 14px; }
.tc-avatar-wrap { position: relative; flex-shrink: 0; }
.tc-avatar-img { width: 44px; height: 44px; border-radius: 50%; object-fit: cover; }
.tc-avatar {
  width: 44px; height: 44px; border-radius: 50%;
  background: var(--color-primary); color: #000;
  font-size: 16px; font-weight: 700;
  display: flex; align-items: center; justify-content: center;
}
.tc-avatar--lossless { background: #0ecb81; }
.tc-lossless-dot {
  position: absolute; bottom: -2px; left: 50%; transform: translateX(-50%);
  font-size: 9px; font-weight: 700;
  background: #0ecb81; color: #000;
  border-radius: 4px; padding: 0 4px; white-space: nowrap;
}
.tc-level-dot {
  position: absolute; bottom: -2px; left: 50%; transform: translateX(-50%);
  font-size: 9px; font-weight: 700;
  background: #1677ff; color: #fff;
  border-radius: 4px; padding: 0 5px; white-space: nowrap;
}

.tc-info { flex: 1; min-width: 0; }
.tc-name-row { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; }
.tc-name { font-size: 14px; font-weight: 600; color: var(--color-text-primary); }
.tc-lossless-badge {
  font-size: 10px; font-weight: 600;
  background: rgba(14,203,129,0.15); color: #0ecb81;
  border: 1px solid rgba(14,203,129,0.3);
  border-radius: 4px; padding: 1px 5px;
}
.tc-meta { font-size: 12px; color: var(--color-text-muted); margin-top: 3px; display: flex; gap: 8px; align-items: center; }
.tc-follow-count { color: var(--color-text-muted); }

.tc-header-right { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
.tc-fav-btn {
  background: none; border: none; cursor: pointer;
  color: var(--color-text-muted); padding: 4px;
  transition: color 0.2s; line-height: 1;
}
.tc-fav-btn:hover, .tc-fav-btn.active { color: #f0b90b; }
.tc-follow-btn {
  padding: 6px 16px; background: var(--color-primary);
  color: #000; font-size: 13px; font-weight: 600;
  border-radius: 8px; border: none; cursor: pointer;
  white-space: nowrap; transition: opacity 0.2s;
}
.tc-follow-btn:hover { opacity: 0.85; }

/* 3列指标行 */
.tc-metrics { display: flex; gap: 0; margin-bottom: 12px; }
.tc-metric { flex: 1; }
.tc-metric:not(:last-child) { padding-right: 8px; border-right: 1px solid var(--color-border); margin-right: 8px; }
.tc-metric-label { font-size: 11px; color: var(--color-text-muted); margin-bottom: 4px; white-space: nowrap; }
.tc-metric-val {
  font-size: 15px; font-weight: 700;
  font-family: var(--font-family-num);
  color: var(--color-text-primary);
}
.tc-metric-val.text-up   { color: var(--color-up, #0ecb81); }
.tc-metric-val.text-down { color: var(--color-down, #ff4d4f); }

/* 走势图 */
.tc-trend { margin-bottom: 10px; }
.tc-trend-label { font-size: 11px; color: var(--color-text-muted); margin-bottom: 4px; }
.tc-sparkline {
  width: 100%; height: 48px; display: block;
  border-radius: 4px;
  overflow: visible;
}
.spark-up   polyline { stroke: #0ecb81; }
.spark-down polyline { stroke: #ff4d4f; }
.tc-trend-empty { font-size: 13px; color: var(--color-text-muted); height: 48px; display: flex; align-items: center; }

/* 胜率行 */
.tc-winrate-row { display: flex; align-items: baseline; gap: 6px; }
.tc-winrate-label { font-size: 12px; color: var(--color-text-muted); }
.tc-winrate-val { font-size: 15px; font-weight: 700; font-family: var(--font-family-num); color: var(--color-text-primary); }

/* ── 无损跟单机制说明 ── */
.lossless-info-section {
  background: var(--color-bg-secondary);
  border-top: 1px solid var(--color-border);
  padding: 48px 0 64px;
}
.ll-info-title {
  font-size: 24px; font-weight: 700;
  color: var(--color-text-primary);
  text-align: center; margin-bottom: 32px;
}
.ll-info-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; }
.ll-info-card {
  background: var(--color-bg-card);
  border: 1px solid var(--color-border);
  border-radius: 12px; padding: 24px 20px;
}
.ll-info-icon { font-size: 28px; margin-bottom: 12px; }
.ll-info-card h3 { font-size: 15px; font-weight: 600; color: var(--color-text-primary); margin-bottom: 8px; }
.ll-info-card p { font-size: 13px; color: var(--color-text-secondary); line-height: 1.6; }

/* ── 响应式 ── */
@media (max-width: 1024px) {
  .trader-grid { grid-template-columns: repeat(2, 1fr); }
  .ll-info-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 768px) {
  .banner-inner { grid-template-columns: 1fr; gap: 24px; }
  .banner-img-wrap { display: none; }
  .banner-title { font-size: 28px; }
  .trader-grid { grid-template-columns: 1fr; }
  .ll-info-grid { grid-template-columns: 1fr 1fr; }
  .sort-tabs { flex-wrap: wrap; }
  .ct-tab { padding: 12px 16px; font-size: 14px; }
}
@media (max-width: 480px) {
  .ll-info-grid { grid-template-columns: 1fr; }
  .banner-stats { gap: 16px; }
}

</style>
