import 'dart:io';
import 'dart:typed_data';
import 'dart:ui' as ui;

import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:gal/gal.dart';
import 'package:go_router/go_router.dart';
import 'package:path_provider/path_provider.dart';
import 'package:qr_flutter/qr_flutter.dart';
import 'package:share_plus/share_plus.dart';

import '../../../core/utils/avatar_urls.dart';
import '../../../core/l10n/app_localizations.dart';
import '../../../core/network/dio_client.dart';
import '../../../core/theme/app_colors.dart';
import '../../../core/utils/dialog_utils.dart';
import '../../../core/utils/top_toast.dart';
import '../../../data/repositories/copy_trading_repository.dart';
import '../../../data/models/copy_trading/trader.dart';
import '../../../data/services/auth_service.dart';
import '../../../providers/app_provider.dart';
import '../../../providers/auth_provider.dart';
import '../../../providers/copy_trading_provider.dart';
import '../../../providers/my_copy_trading_provider.dart';
import '../../widgets/common/app_shimmer.dart';

// ── Provider ──────────────────────────────────────────────────────────────────

final _traderDetailProvider =
    FutureProvider.autoDispose.family<Map<String, dynamic>?, String>(
  (ref, traderId) =>
      ref.read(copyTradingRepositoryProvider).getTraderInfo(traderId),
);

// ── Screen ────────────────────────────────────────────────────────────────────

class TraderDetailScreen extends ConsumerStatefulWidget {
  const TraderDetailScreen({super.key, required this.traderId});
  final String traderId;

  @override
  ConsumerState<TraderDetailScreen> createState() => _TraderDetailScreenState();
}

class _TraderDetailScreenState extends ConsumerState<TraderDetailScreen>
    with SingleTickerProviderStateMixin {
  // ── Tab: 历史带单=0 / 当前带单=1
  late TabController _tabController;
  final _scrollCtrl = ScrollController();

  // ── Favorite / Follow state
  bool _isFavorite = false;
  bool _isFollowing = false;
  bool _favoriteLoading = false;
  bool _followLoading = false;
  bool _initialized = false;

  // ── 带单合约
  bool _symbolExpanded = true;
  List<String> _traderSymbols = [];

  // ── 当前带单
  List<Map<String, dynamic>> _currentOrders = [];
  bool _loadingCurrent = false;
  bool _currentLoaded = false;
  int _currentPage = 1;
  bool _currentHasMore = true;
  bool _currentLoadingMore = false;

  // ── 历史带单
  List<Map<String, dynamic>> _historyOrders = [];
  bool _loadingHistory = false;
  bool _historyLoaded = false;
  int _historyPage = 1;
  bool _historyHasMore = true;
  bool _historyLoadingMore = false;

  static const _pageSize = 10;

  static const _avatarColors = [
    Color(0xFFf7931a),
    Color(0xFF627eea),
    Color(0xFF9945ff),
    Color(0xFFf3ba2f),
    Color(0xFF2775ca),
    Color(0xFF00aae4),
  ];

  @override
  void initState() {
    super.initState();
    // 默认显示「当前带单」(index 0)
    _tabController = TabController(length: 2, vsync: this, initialIndex: 0);
    _tabController.addListener(() {
      if (!mounted) return;
      if (!_tabController.indexIsChanging) {
        // 切换到历史带单 tab 时重新拉取
        if (_tabController.index == 1) _loadHistory();
        setState(() {}); // 仅更新 tab 标题计数
      }
    });
    // 进入页面同时预加载两个 tab 的数据
    _loadCurrent();
    _loadHistory();
    _loadTraderSymbols();
  }

  @override
  void dispose() {
    _tabController.dispose();
    _scrollCtrl.dispose();
    super.dispose();
  }

  Future<void> _loadTraderSymbols() async {
    try {
      final list = await ref
          .read(copyTradingRepositoryProvider)
          .getTraderSymbols(widget.traderId);
      if (mounted) {
        setState(() {
          _traderSymbols = list
              .map((s) =>
                  s['symbolName']?.toString() ?? s['symbol']?.toString() ?? '')
              .where((n) => n.isNotEmpty)
              .toList()
            ..sort();
        });
      }
    } catch (_) {}
  }

  Color _avatarBg(String name) => _avatarColors[
      name.isEmpty ? 0 : name.codeUnitAt(0) % _avatarColors.length];

  String _fmt(dynamic raw, {int decimals = 2}) {
    if (raw == null) return '--';
    final d = double.tryParse(raw.toString());
    if (d == null) return '--';
    return d.toStringAsFixed(decimals);
  }

  String _fmtPercent(dynamic raw) {
    if (raw == null) return '--';
    final d = double.tryParse(raw.toString());
    if (d == null) return '--';
    return '${d >= 0 ? '+' : ''}${d.toStringAsFixed(2)}%';
  }

  Color _pnlColor(dynamic raw) {
    final d = double.tryParse(raw?.toString() ?? '');
    if (d == null) return AppColors.darkTextSecondary;
    return d >= 0 ? AppColors.rise : AppColors.fall;
  }

  // ── Data loading ──────────────────────────────────────────────────────────

  Future<void> _loadCurrent() async {
    if (_loadingCurrent) return;
    if (!mounted) return;
    setState(() {
      _loadingCurrent = true;
      _currentPage = 1;
      _currentHasMore = true;
    });
    try {
      final orders =
          await ref.read(copyTradingRepositoryProvider).getTraderOrders(
                traderId: widget.traderId,
                type: 'current',
                page: 1,
                pageSize: _pageSize,
              );
      if (mounted)
        setState(() {
          _currentOrders = orders;
          _currentLoaded = true;
          _currentHasMore = orders.length >= _pageSize;
        });
    } catch (_) {
      if (mounted) setState(() => _currentLoaded = true);
    } finally {
      if (mounted) setState(() => _loadingCurrent = false);
    }
  }

  Future<void> _loadMoreCurrent() async {
    if (!_currentHasMore || _currentLoadingMore || _loadingCurrent) return;
    final nextPage = _currentPage + 1;
    setState(() => _currentLoadingMore = true);
    try {
      final orders =
          await ref.read(copyTradingRepositoryProvider).getTraderOrders(
                traderId: widget.traderId,
                type: 'current',
                page: nextPage,
                pageSize: _pageSize,
              );
      if (mounted)
        setState(() {
          _currentOrders = [..._currentOrders, ...orders];
          _currentPage = nextPage;
          _currentHasMore = orders.length >= _pageSize;
          _currentLoadingMore = false;
        });
    } catch (_) {
      if (mounted) setState(() => _currentLoadingMore = false);
    }
  }

  Future<void> _loadHistory() async {
    if (_loadingHistory) return;
    setState(() {
      _loadingHistory = true;
      _historyPage = 1;
      _historyHasMore = true;
    });
    try {
      final orders =
          await ref.read(copyTradingRepositoryProvider).getTraderOrders(
                traderId: widget.traderId,
                type: 'history',
                page: 1,
                pageSize: _pageSize,
              );
      if (mounted)
        setState(() {
          _historyOrders = orders;
          _historyLoaded = true;
          _historyHasMore = orders.length >= _pageSize;
        });
    } catch (_) {
      if (mounted) setState(() => _historyLoaded = true);
    } finally {
      if (mounted) setState(() => _loadingHistory = false);
    }
  }

  Future<void> _loadMoreHistory() async {
    if (!_historyHasMore || _historyLoadingMore || _loadingHistory) return;
    final nextPage = _historyPage + 1;
    setState(() => _historyLoadingMore = true);
    try {
      final orders =
          await ref.read(copyTradingRepositoryProvider).getTraderOrders(
                traderId: widget.traderId,
                type: 'history',
                page: nextPage,
                pageSize: _pageSize,
              );
      if (mounted)
        setState(() {
          _historyOrders = [..._historyOrders, ...orders];
          _historyPage = nextPage;
          _historyHasMore = orders.length >= _pageSize;
          _historyLoadingMore = false;
        });
    } catch (_) {
      if (mounted) setState(() => _historyLoadingMore = false);
    }
  }

  // ── Build ─────────────────────────────────────────────────────────────────

  @override
  Widget build(BuildContext context) {
    ref.watch(localeProvider);
    final cs = Theme.of(context).colorScheme;
    final isDark = Theme.of(context).brightness == Brightness.dark;
    final async = ref.watch(_traderDetailProvider(widget.traderId));

    ref.listen(_traderDetailProvider(widget.traderId), (_, next) {
      next.whenData((trader) {
        if (trader == null || _initialized) return;
        setState(() {
          _isFavorite = Trader.parseFavoriteFlag(
            trader['isFavorite'] ?? trader['isFavorited'] ?? trader['favorite'],
          );
          _isFollowing = trader['isFollow']?.toString() == '1' ||
              trader['follow']?.toString() == '1';
          _initialized = true;
        });
      });
    });

    final isTrader = ref.watch(copyTradingProvider.select((s) => s.isTrader));
    final trader = async.valueOrNull;

    return Scaffold(
      backgroundColor: isDark ? AppColors.darkBg : AppColors.lightBgSecondary,
      appBar: AppBar(
        backgroundColor: isDark ? AppColors.darkBg : AppColors.lightBg,
        title: Text(AppLocalizations.of(context)!.traderDetail,
            style: const TextStyle(fontSize: 17, fontWeight: FontWeight.w600)),
        actions: [
          // 带单员不显示关注按钮
          if (!isTrader)
            async.whenOrNull(
                  data: (td) => td == null
                      ? const SizedBox()
                      : GestureDetector(
                          onTap: () => _toggleFavorite(td),
                          child: Padding(
                            padding: const EdgeInsets.all(14),
                            child: Icon(
                              _isFavorite
                                  ? Icons.favorite
                                  : Icons.favorite_border,
                              color: _isFavorite
                                  ? Colors.red
                                  : cs.onSurface.withAlpha(153),
                              size: 24,
                            ),
                          ),
                        ),
                ) ??
                const SizedBox(),
        ],
      ),
      body: Column(
        children: [
          Expanded(
            child: _buildContent(context, cs, isDark, async, trader, isTrader),
          ),
          // 带单员不显示跟单/取消按钮
          if (!isTrader && trader != null)
            _BottomButton(
              isFollowing: _isFollowing,
              isFull: _isFull(trader),
              loading: _followLoading,
              onTap: () => _onFollowTap(context, trader),
            ),
        ],
      ),
    );
  }

  bool _isFull(Map<String, dynamic> trader) {
    final following = int.tryParse(trader['following']?.toString() ?? '') ?? 0;
    final maxFollow = int.tryParse(trader['maxFollow']?.toString() ?? '') ?? 0;
    return !_isFollowing && maxFollow > 0 && following >= maxFollow;
  }

  Widget _buildContent(
    BuildContext context,
    ColorScheme cs,
    bool isDark,
    AsyncValue<Map<String, dynamic>?> async,
    Map<String, dynamic>? trader,
    bool isTrader,
  ) {
    if (async.hasError && trader == null) {
      return Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            Text(AppLocalizations.of(context)!.loadFailed,
                style: TextStyle(color: cs.onSurface.withAlpha(153))),
            const SizedBox(height: 12),
            ElevatedButton(
              onPressed: () =>
                  ref.invalidate(_traderDetailProvider(widget.traderId)),
              style: ElevatedButton.styleFrom(
                  backgroundColor: AppColors.brand,
                  foregroundColor: Colors.black),
              child: Text(AppLocalizations.of(context)!.retry),
            ),
          ],
        ),
      );
    }

    if (async.isLoading && trader == null) {
      return const _TraderDetailSkeleton();
    }

    final l10n = AppLocalizations.of(context)!;
    final tabBar = TabBar(
      controller: _tabController,
      labelColor: cs.onSurface,
      unselectedLabelColor: cs.onSurface.withAlpha(153),
      indicatorColor: AppColors.brand,
      indicatorWeight: 2.5,
      dividerColor: Colors.transparent,
      labelStyle: const TextStyle(fontSize: 14, fontWeight: FontWeight.w600),
      unselectedLabelStyle: const TextStyle(fontSize: 14),
      tabs: [
        Tab(
            text:
                '${l10n.currentCopyOrders}(${_currentOrders.length})'),
        Tab(text: l10n.historyCopyOrders),
      ],
    );

    // NestedScrollView: 外层滚动（header）与内层滚动（各 tab 列表）完全独立，
    // 切换 tab 不会影响外层滚动位置，彻底解决回顶问题。
    return NestedScrollView(
      controller: _scrollCtrl,
      headerSliverBuilder: (ctx, innerBoxIsScrolled) => [
        SliverToBoxAdapter(child: _buildProfile(trader, cs, isDark)),
        SliverToBoxAdapter(child: _buildAccountInfo(trader, cs, isDark)),
        SliverToBoxAdapter(child: _buildCoreData(trader, cs, isDark)),
        SliverToBoxAdapter(child: _buildSymbolSection(cs, isDark, l10n)),
        SliverOverlapAbsorber(
          handle: NestedScrollView.sliverOverlapAbsorberHandleFor(ctx),
          sliver: SliverPersistentHeader(
            pinned: true,
            delegate: _StickyTabBarDelegate(
              tabBar: tabBar,
              bgColor: isDark ? AppColors.darkBg : AppColors.lightBg,
              dividerColor: cs.outlineVariant.withAlpha(80),
            ),
          ),
        ),
      ],
      body: TabBarView(
        controller: _tabController,
        physics: const NeverScrollableScrollPhysics(),
        children: [
          _OrderPage(
            orders: _currentOrders,
            loading: _loadingCurrent,
            loaded: _currentLoaded,
            hasMore: _currentHasMore,
            loadingMore: _currentLoadingMore,
            isHistory: false,
            cs: cs,
            onRefresh: () async {
              ref.invalidate(_traderDetailProvider(widget.traderId));
              await _loadCurrent();
            },
            onLoadMore: _loadMoreCurrent,
          ),
          _OrderPage(
            orders: _historyOrders,
            loading: _loadingHistory,
            loaded: _historyLoaded,
            hasMore: _historyHasMore,
            loadingMore: _historyLoadingMore,
            isHistory: true,
            cs: cs,
            onRefresh: () async {
              ref.invalidate(_traderDetailProvider(widget.traderId));
              await _loadHistory();
            },
            onLoadMore: _loadMoreHistory,
          ),
        ],
      ),
    );
  }

  // ── Profile ───────────────────────────────────────────────────────────────

  Widget _buildProfile(
      Map<String, dynamic>? trader, ColorScheme cs, bool isDark) {
    final nickname = trader?['nickname']?.toString() ?? '';
    final description = trader?['description']?.toString() ?? '';
    final tags = (trader?['tags'] as List?)
            ?.map((e) => e.toString())
            .where((t) => t.isNotEmpty)
            .toList() ??
        [];
    final following = trader?['following']?.toString() ?? '--';
    final maxFollow = trader?['maxFollow']?.toString() ?? '--';
    final registerDays = trader?['registerDays']?.toString() ?? '--';
    final levelName = trader?['levelName']?.toString() ?? '';
    final avatarUrl = trader != null
        ? resolvedAvatarUrlFromRecord(Map<String, dynamic>.from(trader))
        : null;
    final letter = nickname.isNotEmpty ? nickname[0].toUpperCase() : '?';

    return Container(
      color: isDark ? AppColors.darkBgSecondary : AppColors.lightBg,
      padding: const EdgeInsets.fromLTRB(16, 16, 16, 16),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Row(
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              _Avatar(
                  letter: letter,
                  avatarUrl: avatarUrl,
                  bg: _avatarBg(nickname)),
              const SizedBox(width: 14),
              Expanded(
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    // 昵称 + 等级 badge
                    Row(
                      children: [
                        Flexible(
                          child: Text(nickname,
                              style: TextStyle(
                                  color: cs.onSurface,
                                  fontSize: 18,
                                  fontWeight: FontWeight.w700)),
                        ),
                        if (levelName.isNotEmpty) ...[
                          const SizedBox(width: 8),
                          Container(
                            padding: const EdgeInsets.symmetric(
                                horizontal: 8, vertical: 2),
                            decoration: BoxDecoration(
                              color: AppColors.brand,
                              borderRadius: BorderRadius.circular(4),
                            ),
                            child: Text(levelName,
                                style: const TextStyle(
                                    color: Colors.black,
                                    fontSize: 11,
                                    fontWeight: FontWeight.w700)),
                          ),
                        ],
                      ],
                    ),
                    const SizedBox(height: 8),
                    // 入驻天数 + 当前跟随
                    Row(
                      children: [
                        Icon(Icons.calendar_today_outlined,
                            size: 13, color: cs.onSurface.withAlpha(120)),
                        const SizedBox(width: 3),
                        Text(
                            AppLocalizations.of(context)!
                                .settledDaysLabelFmt(registerDays),
                            style: TextStyle(
                                color: cs.onSurface.withAlpha(153),
                                fontSize: 12)),
                        const SizedBox(width: 16),
                        Icon(Icons.group_outlined,
                            size: 13, color: cs.onSurface.withAlpha(120)),
                        const SizedBox(width: 3),
                        Text(
                            AppLocalizations.of(context)!
                                .currentFollowingLabelFmt(following, maxFollow),
                            style: TextStyle(
                                color: cs.onSurface.withAlpha(153),
                                fontSize: 12)),
                      ],
                    ),
                  ],
                ),
              ),
            ],
          ),
          if (description.isNotEmpty) ...[
            const SizedBox(height: 12),
            Text(description,
                style: TextStyle(
                    color: cs.onSurface.withAlpha(153), fontSize: 13)),
          ],
          if (tags.isNotEmpty) ...[
            const SizedBox(height: 10),
            Wrap(
              spacing: 6,
              runSpacing: 6,
              children: tags.map((t) => _TagChip(tag: t)).toList(),
            ),
          ],
        ],
      ),
    );
  }

  // ── 账户信息 ──────────────────────────────────────────────────────────────

  Widget _buildAccountInfo(
      Map<String, dynamic>? trader, ColorScheme cs, bool isDark) {
    final l10n = AppLocalizations.of(context)!;
    return _StatCard(
      isDark: isDark,
      title: l10n.accountInfoTitle,
      rows: [
        [
          _DetailStat(
            label: l10n.cumFollowProfitAmtUsdt,
            value: _fmt(trader?['profitAmount']),
            valueColor: AppColors.rise,
          ),
          _DetailStat(
            label: l10n.fundStrengthUsdt,
            value: trader?['moneyStrength']?.toString() ?? '--',
          ),
        ],
        [
          _DetailStat(
            label: l10n.cumFollowerCount,
            value: trader?['followCustomer']?.toString() ?? '--',
          ),
          _DetailStat(
            label: l10n.cumTradingDays,
            value: trader?['tradingDays']?.toString() ?? '--',
          ),
        ],
      ],
    );
  }

  // ── 核心数据 ──────────────────────────────────────────────────────────────

  Widget _buildCoreData(
      Map<String, dynamic>? trader, ColorScheme cs, bool isDark) {
    final dayYield30 = trader?['dayYield14'];
    final profit30d = trader?['teamProfit14'];
    final winRate = trader?['winRate14'] ?? trader?['winRate30'];
    final dividendPercent = trader?['dividendPercent'];
    String profit30dStr;
    Color? profit30dColor;
    if (profit30d != null) {
      final d = double.tryParse(profit30d.toString());
      profit30dStr =
          d == null ? '--' : '${d >= 0 ? '+' : ''}${d.toStringAsFixed(2)}';
      profit30dColor = _pnlColor(profit30d);
    } else {
      profit30dStr = '--';
      profit30dColor = null;
    }

    final l10n = AppLocalizations.of(context)!;
    return _StatCard(
      isDark: isDark,
      title: l10n.coreDataTitle,
      rows: [
        [
          _DetailStat(
            label: l10n.yield14d,
            value: _fmtPercent(dayYield30),
            valueColor: _pnlColor(dayYield30),
          ),
          _DetailStat(
            label: l10n.profit14dUsdt,
            value: profit30dStr,
            valueColor: profit30dColor,
          ),
        ],
        [
          _DetailStat(
            label: l10n.winRate14d,
            value: winRate == null ? '--' : '${_fmt(winRate, decimals: 1)}%',
          ),
          _DetailStat(
            label: l10n.profitShareRatio,
            value: dividendPercent == null
                ? '--'
                : '${_fmt(dividendPercent, decimals: 0)}%',
          ),
        ],
      ],
    );
  }

  // ── 带单合约 ──────────────────────────────────────────────────────────────

  Widget _buildSymbolSection(ColorScheme cs, bool isDark, AppLocalizations l10n) {
    final symbols = _traderSymbols;
    if (symbols.isEmpty) return const SizedBox.shrink();

    return Container(
      margin: const EdgeInsets.fromLTRB(12, 8, 12, 0),
      padding: const EdgeInsets.all(16),
      decoration: BoxDecoration(
        color: isDark ? AppColors.darkBgSecondary : AppColors.lightBg,
        borderRadius: BorderRadius.circular(12),
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          GestureDetector(
            onTap: () => setState(() => _symbolExpanded = !_symbolExpanded),
            behavior: HitTestBehavior.opaque,
            child: Row(
              children: [
                Text(l10n.tradingContracts,
                    style: TextStyle(
                        color: cs.onSurface,
                        fontSize: 14,
                        fontWeight: FontWeight.w700)),
                const Spacer(),
                Icon(
                  _symbolExpanded
                      ? Icons.keyboard_arrow_up
                      : Icons.keyboard_arrow_down,
                  color: cs.onSurface.withAlpha(153),
                  size: 20,
                ),
              ],
            ),
          ),
          if (_symbolExpanded) ...[
            const SizedBox(height: 10),
            Wrap(
              spacing: 8,
              runSpacing: 8,
              children: symbols.map((sym) {
                return Container(
                  padding:
                      const EdgeInsets.symmetric(horizontal: 14, vertical: 7),
                  decoration: BoxDecoration(
                    color: AppColors.brand.withValues(alpha: 0.12),
                    borderRadius: BorderRadius.circular(8),
                    border: Border.all(
                      color: AppColors.brand.withValues(alpha: 0.6),
                      width: 1.5,
                    ),
                  ),
                  child: Text(
                    sym,
                    style: const TextStyle(
                      color: AppColors.brand,
                      fontSize: 13,
                      fontWeight: FontWeight.w600,
                    ),
                  ),
                );
              }).toList(),
            ),
          ],
        ],
      ),
    );
  }

  // ── Actions ───────────────────────────────────────────────────────────────

  void _onFollowTap(BuildContext context, Map<String, dynamic> trader) {
    if (_isFollowing) {
      _toggleFollow(trader);
    } else {
      context.push<bool>('/follow-setting', extra: trader).then((result) {
        if (result == true && mounted) {
          setState(() => _isFollowing = true);
          ref.read(myCopyTradingProvider.notifier).silentRefresh();
          ref.read(copyTradingProvider.notifier).silentRefresh();
        }
      });
    }
  }

  Future<void> _toggleFavorite(Map<String, dynamic> trader) async {
    if (_favoriteLoading) return;
    if (!ref.read(isLoggedInProvider)) {
      context.push('/login');
      return;
    }
    setState(() => _favoriteLoading = true);
    final repo = ref.read(copyTradingRepositoryProvider);
    final id = trader['id']?.toString() ?? widget.traderId;
    try {
      final ok = _isFavorite
          ? await repo.unfavoriteTrader(id)
          : await repo.favoriteTrader(id);
      if (mounted) {
        setState(() {
          if (ok) _isFavorite = !_isFavorite;
          _favoriteLoading = false;
        });
        if (!ok)
          showTipDialog(context,
              content: AppLocalizations.of(context)!.operationFailedRetry);
      }
    } catch (e) {
      if (mounted) {
        setState(() => _favoriteLoading = false);
        showTipDialog(context, content: extractErrorMessage(e));
      }
    }
  }

  Future<void> _toggleFollow(Map<String, dynamic> trader) async {
    if (_followLoading) return;
    if (!ref.read(isLoggedInProvider)) {
      context.push('/login');
      return;
    }
    final id = trader['id']?.toString() ?? widget.traderId;
    if (_isFollowing) {
      final confirmed = await showConfirmDialog(context,
          content: AppLocalizations.of(context)!.unfollowTraderConfirm);
      if (!confirmed || !mounted) return;
    }
    setState(() => _followLoading = true);
    final repo = ref.read(copyTradingRepositoryProvider);
    try {
      bool ok;
      if (_isFollowing) {
        ok = await repo.unfollowTrader(id);
        if (ok && mounted) {
          setState(() => _isFollowing = false);
          ref.read(myCopyTradingProvider.notifier).silentRefresh();
          ref.read(copyTradingProvider.notifier).silentRefresh();
        }
      } else {
        ok = await repo.followTrader({'traderId': id});
        if (ok && mounted) setState(() => _isFollowing = true);
      }
      if (mounted) {
        setState(() => _followLoading = false);
        if (!ok)
          showTipDialog(context,
              content: AppLocalizations.of(context)!.operationFailedRetry);
      }
    } catch (e) {
      if (mounted) {
        setState(() => _followLoading = false);
        showTipDialog(context, content: extractErrorMessage(e));
      }
    }
  }
}

// ── 订单列表页（每个 tab 独立滚动，切换不影响外层位置）─────────────────────────────

class _OrderPage extends StatelessWidget {
  const _OrderPage({
    required this.orders,
    required this.loading,
    required this.loaded,
    required this.hasMore,
    required this.loadingMore,
    required this.isHistory,
    required this.cs,
    required this.onRefresh,
    required this.onLoadMore,
  });

  final List<Map<String, dynamic>> orders;
  final bool loading;
  final bool loaded;
  final bool hasMore;
  final bool loadingMore;
  final bool isHistory;
  final ColorScheme cs;
  final Future<void> Function() onRefresh;
  final VoidCallback onLoadMore;

  @override
  Widget build(BuildContext context) {
    return Builder(
      builder: (ctx) {
        return NotificationListener<ScrollNotification>(
          onNotification: (n) {
            if (n is ScrollEndNotification &&
                n.metrics.pixels >= n.metrics.maxScrollExtent - 300) {
              onLoadMore();
            }
            return false;
          },
          child: RefreshIndicator(
            color: AppColors.brand,
            onRefresh: onRefresh,
            child: CustomScrollView(
              slivers: [
                SliverOverlapInjector(
                  handle: NestedScrollView.sliverOverlapAbsorberHandleFor(ctx),
                ),
                if (loading && !loaded)
                  const SliverFillRemaining(
                    child: Center(
                      child: CircularProgressIndicator(color: AppColors.brand),
                    ),
                  )
                else if (loaded && orders.isEmpty)
                  SliverFillRemaining(
                    child: Center(
                      child: Text(AppLocalizations.of(context)!.noTradeRecords,
                          style: TextStyle(
                              color: cs.onSurface.withAlpha(153),
                              fontSize: 14)),
                    ),
                  )
                else
                  SliverPadding(
                    padding: const EdgeInsets.fromLTRB(12, 12, 12, 0),
                    sliver: SliverList(
                      delegate: SliverChildBuilderDelegate(
                        (_, i) {
                          if (i < orders.length) {
                            return isHistory
                                ? _HistoryOrderCard(order: orders[i])
                                : _CurrentOrderCard(order: orders[i]);
                          }
                          if (loadingMore) {
                            return const Padding(
                              padding: EdgeInsets.symmetric(vertical: 16),
                              child: Center(
                                child: CircularProgressIndicator(
                                    color: AppColors.brand, strokeWidth: 2),
                              ),
                            );
                          }
                          if (!hasMore && orders.isNotEmpty) {
                            return Padding(
                              padding: const EdgeInsets.symmetric(vertical: 16),
                              child: Center(
                                child: Text(
                                    AppLocalizations.of(context)!.noMore,
                                    style: TextStyle(
                                        color: cs.onSurface.withAlpha(100),
                                        fontSize: 12)),
                              ),
                            );
                          }
                          return const SizedBox(height: 20);
                        },
                        childCount: orders.length + 1,
                      ),
                    ),
                  ),
              ],
            ),
          ),
        );
      },
    );
  }
}

// ── Sticky TabBar delegate ────────────────────────────────────────────────────

class _StickyTabBarDelegate extends SliverPersistentHeaderDelegate {
  const _StickyTabBarDelegate({
    required this.tabBar,
    required this.bgColor,
    required this.dividerColor,
  });
  final TabBar tabBar;
  final Color bgColor;
  final Color dividerColor;

  @override
  double get minExtent => tabBar.preferredSize.height;
  @override
  double get maxExtent => tabBar.preferredSize.height;

  @override
  Widget build(
      BuildContext context, double shrinkOffset, bool overlapsContent) {
    return DecoratedBox(
      decoration: BoxDecoration(
        color: bgColor,
        border: Border(bottom: BorderSide(color: dividerColor, width: 0.5)),
      ),
      child: tabBar,
    );
  }

  @override
  bool shouldRebuild(covariant _StickyTabBarDelegate old) =>
      old.tabBar != tabBar || old.bgColor != bgColor;
}

// ── 统计卡片 ──────────────────────────────────────────────────────────────────

class _StatCard extends StatelessWidget {
  const _StatCard({
    required this.isDark,
    required this.title,
    required this.rows,
  });
  final bool isDark;
  final String title;
  final List<List<Widget>> rows;

  @override
  Widget build(BuildContext context) {
    final cs = Theme.of(context).colorScheme;
    return Container(
      margin: const EdgeInsets.fromLTRB(12, 8, 12, 0),
      padding: const EdgeInsets.all(16),
      decoration: BoxDecoration(
        color: isDark ? AppColors.darkBgSecondary : AppColors.lightBg,
        borderRadius: BorderRadius.circular(12),
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(title,
              style: TextStyle(
                  color: cs.onSurface,
                  fontSize: 14,
                  fontWeight: FontWeight.w700)),
          ...rows.expand((row) => [
                const SizedBox(height: 14),
                Row(children: row),
              ]),
        ],
      ),
    );
  }
}

// ── Avatar ────────────────────────────────────────────────────────────────────

class _Avatar extends StatelessWidget {
  const _Avatar({required this.letter, required this.bg, this.avatarUrl});
  final String letter;
  final Color bg;
  final String? avatarUrl;

  @override
  Widget build(BuildContext context) {
    if (avatarUrl != null && avatarUrl!.isNotEmpty) {
      return ClipOval(
        child: Image.network(avatarUrl!,
            width: 64,
            height: 64,
            fit: BoxFit.cover,
            errorBuilder: (_, __, ___) => _fallback()),
      );
    }
    return _fallback();
  }

  Widget _fallback() => Container(
        width: 64,
        height: 64,
        decoration: BoxDecoration(color: bg, shape: BoxShape.circle),
        child: Center(
          child: Text(letter,
              style: const TextStyle(
                  color: Colors.white,
                  fontSize: 24,
                  fontWeight: FontWeight.w700)),
        ),
      );
}

// ── 标签 chip ─────────────────────────────────────────────────────────────────

class _TagChip extends StatelessWidget {
  const _TagChip({required this.tag});
  final String tag;

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
      decoration: BoxDecoration(
        color: AppColors.tagBlueBg,
        borderRadius: BorderRadius.circular(20),
      ),
      child: Text(tag,
          style: const TextStyle(color: AppColors.tagBlue, fontSize: 12)),
    );
  }
}

// ── 统计项 ────────────────────────────────────────────────────────────────────

class _DetailStat extends StatelessWidget {
  const _DetailStat(
      {required this.label, required this.value, this.valueColor});
  final String label;
  final String value;
  final Color? valueColor;

  @override
  Widget build(BuildContext context) {
    final cs = Theme.of(context).colorScheme;
    return Expanded(
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(label,
              style:
                  TextStyle(color: cs.onSurface.withAlpha(153), fontSize: 12)),
          const SizedBox(height: 4),
          Text(
            value,
            style: TextStyle(
              color: valueColor ?? cs.onSurface,
              fontSize: 15,
              fontWeight: FontWeight.w600,
              fontFeatures: const [FontFeature.tabularFigures()],
            ),
          ),
        ],
      ),
    );
  }
}

// ── 数量格式化 ─────────────────────────────────────────────────────────────────

String _fmtQty(dynamic raw) {
  if (raw == null) return '--';
  final str = raw.toString().trim();
  if (str.isEmpty || double.tryParse(str) == null) return '--';
  final isNeg = str.startsWith('-');
  final absStr = isNeg ? str.substring(1) : str;
  final dotIdx = absStr.indexOf('.');
  String s;
  if (dotIdx < 0) {
    s = absStr;
  } else {
    final frac = absStr.substring(dotIdx + 1);
    s = '${absStr.substring(0, dotIdx)}.${frac.length >= 4 ? frac.substring(0, 4) : frac.padRight(4, '0')}';
  }
  if (s.contains('.')) {
    s = s.replaceAll(RegExp(r'0+$'), '').replaceAll(RegExp(r'\.$'), '');
  }
  final result = s.isEmpty ? '0' : s;
  return isNeg ? '-$result' : result;
}

// ── 当前带单卡片 ───────────────────────────────────────────────────────────────

class _CurrentOrderCard extends StatelessWidget {
  const _CurrentOrderCard({required this.order});
  final Map<String, dynamic> order;

  String _fmt(dynamic raw, {int decimals = 2}) {
    if (raw == null) return '--';
    final d = double.tryParse(raw.toString());
    if (d == null) return '--';
    return d.toStringAsFixed(decimals);
  }

  String _fmtPnl(dynamic raw, {int decimals = 2}) {
    if (raw == null) return '--';
    final d = double.tryParse(raw.toString());
    if (d == null) return '--';
    return '${d >= 0 ? '+' : ''}${d.toStringAsFixed(decimals)}';
  }

  Color _pnlColor(dynamic raw, ColorScheme cs) {
    final d = double.tryParse(raw?.toString() ?? '');
    if (d == null) return cs.onSurface;
    return d >= 0 ? AppColors.rise : AppColors.fall;
  }

  String _fmtTimestamp(dynamic ts) {
    if (ts == null) return '--';
    final ms = int.tryParse(ts.toString());
    if (ms == null) return ts.toString();
    final dt = DateTime.fromMillisecondsSinceEpoch(ms, isUtc: true)
        .add(const Duration(hours: 8));
    return '${dt.year}-${dt.month.toString().padLeft(2, '0')}-${dt.day.toString().padLeft(2, '0')} '
        '${dt.hour.toString().padLeft(2, '0')}:${dt.minute.toString().padLeft(2, '0')}:${dt.second.toString().padLeft(2, '0')}';
  }

  @override
  Widget build(BuildContext context) {
    final cs = Theme.of(context).colorScheme;
    final isDark = Theme.of(context).brightness == Brightness.dark;
    final l10n = AppLocalizations.of(context)!;
    final cardBg = isDark ? AppColors.darkBgSecondary : AppColors.lightBg;

    final symbol = order['symbol']?.toString() ?? '--';
    final direction = order['direction']?.toString() ?? '';
    final leverage = order['leverage']?.toString() ?? '--';
    final marginType = order['positionType']?.toString() ??
        order['marginType']?.toString() ??
        l10n.crossMargin;
    final openPrice = order['openPrice'] ?? order['avgOpenPrice'];
    final currentPrice = order['currentPrice'] ?? order['markPrice'];
    final margin = order['principalAmount'];
    final quantity = order['totalPosition'];
    final roi = order['profitRate'];
    final pnl = order['profit'];
    final openTimeStr = _fmtTimestamp(order['openTime']);
    final positionId =
        order['positionId']?.toString() ?? order['id']?.toString() ?? '';

    final isLong = direction == '0';
    final directionLabel =
        isLong ? l10n.openLongBullish : l10n.openShortBearish;
    final directionColor = isLong ? AppColors.rise : AppColors.fall;
    final baseCoin = symbol.contains('/')
        ? symbol.split('/')[0]
        : symbol.replaceAll('USDT', '');

    return Container(
      margin: const EdgeInsets.only(bottom: 10),
      padding: const EdgeInsets.all(14),
      decoration:
          BoxDecoration(color: cardBg, borderRadius: BorderRadius.circular(10)),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          // 标题行
          Row(
            children: [
              Expanded(
                child: Text('$symbol ${l10n.perpetual}',
                    style: TextStyle(
                        color: cs.onSurface,
                        fontSize: 14,
                        fontWeight: FontWeight.w700)),
              ),
              _Badge(
                  label: directionLabel,
                  bgColor: directionColor.withValues(alpha: 0.15),
                  textColor: directionColor),
              const SizedBox(width: 6),
              _Badge(
                  label: '${leverage}x',
                  bgColor: cs.onSurface.withAlpha(20),
                  textColor: cs.onSurface.withAlpha(180),
                  borderColor: cs.onSurface.withAlpha(60)),
              const SizedBox(width: 6),
              _Badge(
                  label: marginType,
                  bgColor: cs.onSurface.withAlpha(20),
                  textColor: cs.onSurface.withAlpha(153),
                  borderColor: cs.onSurface.withAlpha(60)),
            ],
          ),
          const SizedBox(height: 12),
          Row(
            children: [
              _OrderStat(label: l10n.openAvgPriceUsdt, value: _fmt(openPrice)),
              _OrderStat(
                  label: l10n.currentPriceUsdt, value: _fmt(currentPrice)),
              _OrderStat(label: l10n.currentMarginUsdt, value: _fmt(margin)),
            ],
          ),
          const SizedBox(height: 10),
          Row(
            children: [
              _OrderStat(
                  label: l10n.qtyWithCoin(baseCoin), value: _fmtQty(quantity)),
              _OrderStat(
                  label: l10n.returnRate,
                  value: roi == null ? '--' : '${_fmtPnl(roi)}%',
                  valueColor: _pnlColor(roi, cs)),
              _OrderStat(
                  label: l10n.profitUsdt,
                  value: _fmtPnl(pnl),
                  valueColor: _pnlColor(pnl, cs)),
            ],
          ),
          const SizedBox(height: 10),
          Divider(height: 1, thickness: 0.5, color: cs.outlineVariant),
          const SizedBox(height: 8),
          Row(
            children: [
              Text(l10n.openTimeWithValue(openTimeStr),
                  style: TextStyle(
                      color: cs.onSurface.withAlpha(120), fontSize: 11)),
              const Spacer(),
              if (positionId.isNotEmpty)
                Row(
                  children: [
                    Text('${l10n.positionIdPrefix}$positionId',
                        style: TextStyle(
                            color: cs.onSurface.withAlpha(120), fontSize: 11)),
                    const SizedBox(width: 4),
                    GestureDetector(
                      onTap: () {
                        Clipboard.setData(ClipboardData(text: positionId));
                        showTopToast(context,
                            message: l10n.copyPositionIdSuccess,
                            backgroundColor: AppColors.rise);
                      },
                      child: Icon(Icons.copy_outlined,
                          size: 13, color: cs.onSurface.withAlpha(100)),
                    ),
                  ],
                ),
            ],
          ),
        ],
      ),
    );
  }
}

// ── 历史带单卡片 ───────────────────────────────────────────────────────────────

class _HistoryOrderCard extends StatelessWidget {
  const _HistoryOrderCard({required this.order});
  final Map<String, dynamic> order;

  String _fmt(dynamic raw, {int decimals = 2}) {
    if (raw == null) return '--';
    final d = double.tryParse(raw.toString());
    if (d == null) return '--';
    return d.toStringAsFixed(decimals);
  }

  String _fmtPnl(dynamic raw, {int decimals = 2}) {
    if (raw == null) return '--';
    final d = double.tryParse(raw.toString());
    if (d == null) return '--';
    return '${d >= 0 ? '+' : ''}${d.toStringAsFixed(decimals)}';
  }

  Color _pnlColor(dynamic raw, ColorScheme cs) {
    final d = double.tryParse(raw?.toString() ?? '');
    if (d == null) return cs.onSurface;
    return d >= 0 ? AppColors.rise : AppColors.fall;
  }

  String _fmtTimestamp(dynamic ts) {
    if (ts == null) return '--';
    final ms = int.tryParse(ts.toString());
    if (ms == null) return ts.toString();
    final dt = DateTime.fromMillisecondsSinceEpoch(ms, isUtc: true)
        .add(const Duration(hours: 8));
    return '${dt.year}-${dt.month.toString().padLeft(2, '0')}-${dt.day.toString().padLeft(2, '0')} '
        '${dt.hour.toString().padLeft(2, '0')}:${dt.minute.toString().padLeft(2, '0')}:${dt.second.toString().padLeft(2, '0')}';
  }

  void _showShareSheet(BuildContext context) {
    showModalBottomSheet(
      context: context,
      useRootNavigator: true,
      isScrollControlled: true,
      backgroundColor: Colors.transparent,
      builder: (_) => _ShareOrderSheet(order: order, fmt: _fmt),
    );
  }

  @override
  Widget build(BuildContext context) {
    final cs = Theme.of(context).colorScheme;
    final isDark = Theme.of(context).brightness == Brightness.dark;
    final cardBg = isDark ? AppColors.darkBgSecondary : AppColors.lightBg;
    final l10n = AppLocalizations.of(context)!;

    final symbol = order['symbol']?.toString() ?? '--';
    final direction = order['direction']?.toString() ?? '';
    final leverage = order['leverage']?.toString() ?? '--';
    final marginType = order['positionType']?.toString() ??
        order['marginType']?.toString() ??
        l10n.crossMargin;
    final openPrice = order['openPrice'] ?? order['avgOpenPrice'];
    final closePrice = order['closePrice'] ?? order['avgClosePrice'];
    final quantity = order['totalPosition'];
    final pnl = order['profit'];
    final roi = order['profitRate'];
    final openTime = _fmtTimestamp(order['openTime']);
    final closeTime = _fmtTimestamp(order['closeTime']);

    final isLong = direction == '0';
    final directionLabel =
        isLong ? l10n.openLongBullish : l10n.openShortBearish;
    final directionColor = isLong ? AppColors.rise : AppColors.fall;
    final baseCoin = symbol.contains('/')
        ? symbol.split('/')[0]
        : symbol.replaceAll('USDT', '');

    return Container(
      margin: const EdgeInsets.only(bottom: 10),
      padding: const EdgeInsets.all(14),
      decoration:
          BoxDecoration(color: cardBg, borderRadius: BorderRadius.circular(10)),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          // 标题行
          Row(
            children: [
              Expanded(
                child: Text('$symbol ${l10n.perpetual}',
                    style: TextStyle(
                        color: cs.onSurface,
                        fontSize: 14,
                        fontWeight: FontWeight.w700)),
              ),
              GestureDetector(
                onTap: () => _showShareSheet(context),
                child: Icon(Icons.open_in_new,
                    size: 14, color: cs.onSurface.withAlpha(100)),
              ),
            ],
          ),
          const SizedBox(height: 8),
          // 徽章行
          Row(
            children: [
              _Badge(
                  label: directionLabel,
                  bgColor: directionColor.withValues(alpha: 0.15),
                  textColor: directionColor),
              const SizedBox(width: 6),
              _Badge(
                  label: '${leverage}x',
                  bgColor: cs.onSurface.withAlpha(20),
                  textColor: cs.onSurface.withAlpha(180),
                  borderColor: cs.onSurface.withAlpha(60)),
              const SizedBox(width: 6),
              _Badge(
                  label: marginType,
                  bgColor: cs.onSurface.withAlpha(20),
                  textColor: cs.onSurface.withAlpha(153),
                  borderColor: cs.onSurface.withAlpha(60)),
            ],
          ),
          const SizedBox(height: 12),
          // 数据行 1: 数量 + 收益 + 收益率
          Row(
            children: [
              _OrderStat(
                  label: l10n.qtyWithCoin(baseCoin), value: _fmtQty(quantity)),
              _OrderStat(
                  label: l10n.profitUsdt,
                  value: _fmtPnl(pnl),
                  valueColor: _pnlColor(pnl, cs)),
              _OrderStat(
                  label: l10n.returnRate,
                  value: roi == null ? '--' : '${_fmtPnl(roi)}%',
                  valueColor: _pnlColor(roi, cs)),
            ],
          ),
          const SizedBox(height: 10),
          // 数据行 2: 开仓均价 + 平仓均价
          Row(
            children: [
              _OrderStat(label: l10n.openAvgPriceUsdt, value: _fmt(openPrice)),
              _OrderStat(
                  label: l10n.closeAvgPriceUsdt, value: _fmt(closePrice)),
              const Expanded(child: SizedBox()),
            ],
          ),
          const SizedBox(height: 10),
          Divider(height: 1, thickness: 0.5, color: cs.outlineVariant),
          const SizedBox(height: 8),
          Row(
            children: [
              Text(openTime,
                  style: TextStyle(
                      color: cs.onSurface.withAlpha(120), fontSize: 11)),
              const Spacer(),
              Text(closeTime,
                  style: TextStyle(
                      color: cs.onSurface.withAlpha(120), fontSize: 11)),
            ],
          ),
        ],
      ),
    );
  }
}

// ── Badge ─────────────────────────────────────────────────────────────────────

class _Badge extends StatelessWidget {
  const _Badge({
    required this.label,
    required this.bgColor,
    required this.textColor,
    this.borderColor,
  });
  final String label;
  final Color bgColor;
  final Color textColor;
  final Color? borderColor;

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
      decoration: BoxDecoration(
        color: bgColor,
        borderRadius: BorderRadius.circular(4),
        border: borderColor != null
            ? Border.all(color: borderColor!, width: 0.8)
            : null,
      ),
      child: Text(label,
          style: TextStyle(
              color: textColor, fontSize: 11, fontWeight: FontWeight.w600)),
    );
  }
}

// ── OrderStat ─────────────────────────────────────────────────────────────────

class _OrderStat extends StatelessWidget {
  const _OrderStat({required this.label, required this.value, this.valueColor});
  final String label;
  final String value;
  final Color? valueColor;

  @override
  Widget build(BuildContext context) {
    final cs = Theme.of(context).colorScheme;
    return Expanded(
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(label,
              style:
                  TextStyle(color: cs.onSurface.withAlpha(153), fontSize: 11)),
          const SizedBox(height: 2),
          Text(value,
              style: TextStyle(
                color: valueColor ?? cs.onSurface,
                fontSize: 13,
                fontWeight: FontWeight.w600,
                fontFeatures: const [FontFeature.tabularFigures()],
              )),
        ],
      ),
    );
  }
}

// ── 底部按钮 ──────────────────────────────────────────────────────────────────

class _BottomButton extends StatelessWidget {
  const _BottomButton({
    required this.isFollowing,
    required this.loading,
    required this.onTap,
    this.isFull = false,
  });
  final bool isFollowing;
  final bool isFull;
  final bool loading;
  final VoidCallback onTap;

  @override
  Widget build(BuildContext context) {
    final cs = Theme.of(context).colorScheme;
    final isDark = Theme.of(context).brightness == Brightness.dark;
    return Container(
      padding: EdgeInsets.fromLTRB(
          16, 12, 16, 12 + MediaQuery.of(context).padding.bottom),
      decoration: BoxDecoration(
        color: isDark ? AppColors.darkBgSecondary : AppColors.lightBg,
        border: Border(
            top: BorderSide(
                color:
                    isDark ? AppColors.darkDivider : AppColors.lightDivider)),
      ),
      child: SizedBox(
        width: double.infinity,
        height: 48,
        child: loading
            ? OutlinedButton(
                onPressed: null,
                style: OutlinedButton.styleFrom(
                    side: BorderSide(color: cs.outline.withAlpha(50)),
                    shape: const StadiumBorder()),
                child: const SizedBox(
                    width: 20,
                    height: 20,
                    child: CircularProgressIndicator(strokeWidth: 2)),
              )
            : isFull
                ? ElevatedButton(
                    onPressed: null,
                    style: ElevatedButton.styleFrom(
                      backgroundColor: cs.outline.withAlpha(40),
                      foregroundColor: cs.onSurface.withAlpha(100),
                      elevation: 0,
                      shape: const StadiumBorder(),
                      disabledBackgroundColor: cs.outline.withAlpha(40),
                      disabledForegroundColor: cs.onSurface.withAlpha(100),
                    ),
                    child: Text(AppLocalizations.of(context)!.fullCapacity,
                        style: const TextStyle(
                            fontSize: 15, fontWeight: FontWeight.w600)),
                  )
                : isFollowing
                    ? ElevatedButton(
                        onPressed: onTap,
                        style: ElevatedButton.styleFrom(
                          backgroundColor: isDark
                              ? AppColors.darkBgTertiary
                              : AppColors.lightBgTertiary,
                          foregroundColor: cs.onSurface,
                          elevation: 0,
                          shape: const StadiumBorder(),
                        ),
                        child: Text(AppLocalizations.of(context)!.unfollow,
                            style: const TextStyle(
                                fontSize: 15, fontWeight: FontWeight.w600)),
                      )
                    : ElevatedButton(
                        onPressed: onTap,
                        style: ElevatedButton.styleFrom(
                          backgroundColor: AppColors.brand,
                          foregroundColor: Colors.black,
                          shape: const StadiumBorder(),
                          elevation: 0,
                        ),
                        child: Text(AppLocalizations.of(context)!.followTrader,
                            style: const TextStyle(
                                fontSize: 15, fontWeight: FontWeight.w600)),
                      ),
      ),
    );
  }
}

// ── 骨架屏 ────────────────────────────────────────────────────────────────────

class _TraderDetailSkeleton extends StatelessWidget {
  const _TraderDetailSkeleton();

  @override
  Widget build(BuildContext context) {
    final cs = Theme.of(context).colorScheme;
    final isDark = Theme.of(context).brightness == Brightness.dark;
    final cardBg = isDark ? AppColors.darkBgSecondary : AppColors.lightBg;

    return AppShimmer(
      child: SingleChildScrollView(
        physics: const NeverScrollableScrollPhysics(),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            // Profile card
            Container(
              color: cardBg,
              padding: const EdgeInsets.all(16),
              child: Row(
                crossAxisAlignment: CrossAxisAlignment.center,
                children: [
                  shimmerCircle(64),
                  const SizedBox(width: 14),
                  Expanded(
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        shimmerBox(140, 18),
                        const SizedBox(height: 10),
                        shimmerBox(200, 13),
                      ],
                    ),
                  ),
                ],
              ),
            ),
            const SizedBox(height: 8),
            // 账户信息 card
            Container(
              margin: const EdgeInsets.fromLTRB(12, 0, 12, 0),
              padding: const EdgeInsets.all(16),
              decoration: BoxDecoration(
                  color: cardBg, borderRadius: BorderRadius.circular(12)),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  shimmerBox(60, 14),
                  const SizedBox(height: 14),
                  Row(children: [
                    Expanded(
                        child: Column(
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: [
                          shimmerBox(120, 12),
                          const SizedBox(height: 6),
                          shimmerBox(80, 15),
                        ])),
                    Expanded(
                        child: Column(
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: [
                          shimmerBox(100, 12),
                          const SizedBox(height: 6),
                          shimmerBox(60, 15),
                        ])),
                  ]),
                  const SizedBox(height: 14),
                  Row(children: [
                    Expanded(
                        child: Column(
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: [
                          shimmerBox(80, 12),
                          const SizedBox(height: 6),
                          shimmerBox(50, 15),
                        ])),
                    Expanded(
                        child: Column(
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: [
                          shimmerBox(80, 12),
                          const SizedBox(height: 6),
                          shimmerBox(40, 15),
                        ])),
                  ]),
                ],
              ),
            ),
            const SizedBox(height: 8),
            // 核心数据 card
            Container(
              margin: const EdgeInsets.fromLTRB(12, 0, 12, 0),
              padding: const EdgeInsets.all(16),
              decoration: BoxDecoration(
                  color: cardBg, borderRadius: BorderRadius.circular(12)),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  shimmerBox(60, 14),
                  const SizedBox(height: 14),
                  Row(children: [
                    Expanded(
                        child: Column(
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: [
                          shimmerBox(80, 12),
                          const SizedBox(height: 6),
                          shimmerBox(70, 15),
                        ])),
                    Expanded(
                        child: Column(
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: [
                          shimmerBox(100, 12),
                          const SizedBox(height: 6),
                          shimmerBox(70, 15),
                        ])),
                  ]),
                ],
              ),
            ),
            const SizedBox(height: 16),
            // Tab bar skeleton
            Padding(
              padding: const EdgeInsets.symmetric(horizontal: 16),
              child: Row(children: [
                Expanded(child: shimmerFill(32, radius: 4)),
                const SizedBox(width: 16),
                Expanded(child: shimmerFill(32, radius: 4)),
              ]),
            ),
            const SizedBox(height: 16),
            // 订单卡片骨架
            ...List.generate(
              3,
              (_) => Container(
                margin: const EdgeInsets.fromLTRB(12, 0, 12, 10),
                padding: const EdgeInsets.all(14),
                decoration: BoxDecoration(
                    color: cs.onSurface.withAlpha(8),
                    borderRadius: BorderRadius.circular(10)),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Row(children: [
                      Expanded(child: shimmerBox(100, 14)),
                      shimmerBox(60, 20, radius: 4),
                    ]),
                    const SizedBox(height: 10),
                    Row(
                        children: List.generate(
                            3,
                            (i) => Expanded(
                                  child: Padding(
                                    padding:
                                        EdgeInsets.only(right: i < 2 ? 8.0 : 0),
                                    child: shimmerBox(double.infinity, 32,
                                        radius: 4),
                                  ),
                                ))),
                  ],
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

// ── 分享带单 BottomSheet ───────────────────────────────────

class _ShareOrderSheet extends ConsumerStatefulWidget {
  const _ShareOrderSheet({required this.order, required this.fmt});

  final Map<String, dynamic> order;
  final String Function(dynamic, {int decimals}) fmt;

  @override
  ConsumerState<_ShareOrderSheet> createState() => _ShareOrderSheetState();
}

class _ShareOrderSheetState extends ConsumerState<_ShareOrderSheet> {
  final _cardKey = GlobalKey();
  bool _sharing = false;
  bool _saving = false;
  String? _inviteCode;
  String? _inviteUrl;

  @override
  void initState() {
    super.initState();
    _loadInviteInfo();
  }

  Future<void> _loadInviteInfo() async {
    try {
      final dio = ref.read(dioClientProvider);
      final data = await AuthService(dio).getMyInfo();
      final prefix = data['promotionPrefix']?.toString() ?? '';
      final code = data['promotionCode']?.toString() ?? '';
      final url =
          (prefix.isNotEmpty || code.isNotEmpty) ? '$prefix$code' : null;
      if (mounted) {
        setState(() {
          _inviteCode = code.isNotEmpty ? code : null;
          _inviteUrl = url;
        });
      }
    } catch (_) {}
  }

  String _fmtTimestamp(dynamic ts) {
    if (ts == null) return '--';
    final ms = int.tryParse(ts.toString());
    if (ms == null) return ts.toString();
    final dt = DateTime.fromMillisecondsSinceEpoch(ms, isUtc: true)
        .add(const Duration(hours: 8));
    return '${dt.year}-${dt.month.toString().padLeft(2, '0')}-${dt.day.toString().padLeft(2, '0')} '
        '${dt.hour.toString().padLeft(2, '0')}:${dt.minute.toString().padLeft(2, '0')}:${dt.second.toString().padLeft(2, '0')}';
  }

  Future<Uint8List?> _renderCard() async {
    final boundary =
        _cardKey.currentContext?.findRenderObject() as RenderRepaintBoundary?;
    if (boundary == null) return null;
    final image = await boundary.toImage(pixelRatio: 3.0);
    final byteData = await image.toByteData(format: ui.ImageByteFormat.png);
    return byteData?.buffer.asUint8List();
  }

  Future<void> _doSave(BuildContext context) async {
    setState(() => _saving = true);
    try {
      final bytes = await _renderCard();
      if (bytes == null) return;
      await Gal.requestAccess();
      await Gal.putImageBytes(
        bytes,
        name: 'trade_share_${DateTime.now().millisecondsSinceEpoch}',
      );
      if (!context.mounted) return;
      showTopToast(context,
          message: AppLocalizations.of(context)!.saveSuccess,
          backgroundColor: AppColors.rise);
    } on GalException catch (e) {
      if (!context.mounted) return;
      final l10n = AppLocalizations.of(context)!;
      if (e.type == GalExceptionType.accessDenied) {
        showTopToast(context,
            message: l10n.photoPermissionDenied,
            backgroundColor: AppColors.fall);
      } else {
        showTopToast(context,
            message: l10n.saveFailed, backgroundColor: AppColors.fall);
      }
    } catch (e) {
      if (context.mounted) {
        showTopToast(context,
            message: AppLocalizations.of(context)!.saveFailed,
            backgroundColor: AppColors.fall);
      }
    } finally {
      if (mounted) setState(() => _saving = false);
    }
  }

  Future<void> _doShare(BuildContext context) async {
    setState(() => _sharing = true);
    try {
      final bytes = await _renderCard();
      if (bytes == null) return;
      final tmpDir = await getTemporaryDirectory();
      final file = File(
          '${tmpDir.path}/trade_share_${DateTime.now().millisecondsSinceEpoch}.png');
      await file.writeAsBytes(bytes);
      if (!context.mounted) return;
      Navigator.of(context).pop();
      await Share.shareXFiles(
        [XFile(file.path, mimeType: 'image/png')],
        subject: AppLocalizations.of(context)!.myTradingProfit,
      );
    } catch (e) {
      if (context.mounted) {
        showTopToast(context,
            message: AppLocalizations.of(context)!.shareFailed,
            backgroundColor: AppColors.fall);
      }
    } finally {
      if (mounted) setState(() => _sharing = false);
    }
  }

  @override
  Widget build(BuildContext context) {
    final cs = Theme.of(context).colorScheme;
    final isDark = Theme.of(context).brightness == Brightness.dark;
    final order = widget.order;
    final profit = double.tryParse(order['profit']?.toString() ?? '0') ?? 0.0;
    final pnlPositive = profit >= 0;
    final l10n = AppLocalizations.of(context)!;

    final symbol = order['symbol']?.toString() ?? '--';
    final isLong = (order['direction']?.toString() ?? '0') == '0';
    final leverage = order['leverage']?.toString() ?? '--';
    final profitRateRaw =
        double.tryParse(order['profitRate']?.toString() ?? '0') ?? 0.0;
    final profitRateStr =
        '${profitRateRaw >= 0 ? '+' : ''}${profitRateRaw.toStringAsFixed(2)}%';
    final openPrice = widget.fmt(order['openPrice']);
    final closePrice = widget.fmt(order['closePrice']);
    final openTime = _fmtTimestamp(order['openTime']);
    final closeTime = _fmtTimestamp(order['closeTime']);

    return Container(
      decoration: BoxDecoration(
        color: isDark ? AppColors.darkBgSecondary : AppColors.lightBgSecondary,
        borderRadius: const BorderRadius.vertical(top: Radius.circular(16)),
      ),
      padding: const EdgeInsets.fromLTRB(16, 16, 16, 32),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          // 拖拽指示条
          Container(
            width: 36,
            height: 4,
            decoration: BoxDecoration(
              color: cs.onSurface.withAlpha(60),
              borderRadius: BorderRadius.circular(2),
            ),
          ),
          const SizedBox(height: 16),

          // 分享卡片预览
          RepaintBoundary(
            key: _cardKey,
            child: _TradeShareCard(
              symbol: symbol,
              isLong: isLong,
              leverage: leverage,
              profitRateStr: profitRateStr,
              pnlPositive: pnlPositive,
              openPrice: openPrice,
              closePrice: closePrice,
              openTime: openTime,
              closeTime: closeTime,
              inviteCode: _inviteCode,
              inviteUrl: _inviteUrl,
            ),
          ),
          const SizedBox(height: 24),

          // 操作按钮行：取消 | 保存海报 | 分享
          Row(
            children: [
              Expanded(
                child: OutlinedButton(
                  onPressed: () => Navigator.of(context).pop(),
                  style: OutlinedButton.styleFrom(
                    padding: const EdgeInsets.symmetric(vertical: 12),
                    shape: RoundedRectangleBorder(
                        borderRadius: BorderRadius.circular(8)),
                  ),
                  child: Text(l10n.cancelLabel,
                      style: TextStyle(color: cs.onSurface, fontSize: 14)),
                ),
              ),
              const SizedBox(width: 8),
              Expanded(
                child: OutlinedButton(
                  onPressed: _saving ? null : () => _doSave(context),
                  style: OutlinedButton.styleFrom(
                    padding: const EdgeInsets.symmetric(vertical: 12),
                    shape: RoundedRectangleBorder(
                        borderRadius: BorderRadius.circular(8)),
                  ),
                  child: _saving
                      ? SizedBox(
                          width: 16,
                          height: 16,
                          child: CircularProgressIndicator(
                              strokeWidth: 2,
                              color: cs.onSurface.withAlpha(153)),
                        )
                      : Text(l10n.savePoster,
                          style: TextStyle(color: cs.onSurface, fontSize: 14)),
                ),
              ),
              const SizedBox(width: 8),
              Expanded(
                child: ElevatedButton(
                  onPressed: _sharing ? null : () => _doShare(context),
                  style: ElevatedButton.styleFrom(
                    backgroundColor:
                        pnlPositive ? AppColors.rise : AppColors.fall,
                    padding: const EdgeInsets.symmetric(vertical: 12),
                    shape: RoundedRectangleBorder(
                        borderRadius: BorderRadius.circular(8)),
                    elevation: 0,
                  ),
                  child: _sharing
                      ? const SizedBox(
                          width: 16,
                          height: 16,
                          child: CircularProgressIndicator(
                              strokeWidth: 2, color: Colors.white),
                        )
                      : Text(l10n.shareLabel,
                          style: const TextStyle(
                              color: Colors.white,
                              fontSize: 14,
                              fontWeight: FontWeight.w600)),
                ),
              ),
            ],
          ),
        ],
      ),
    );
  }
}

// ── 带单分享卡片内容 ─────────────────────────────────────────

class _TradeShareCard extends StatelessWidget {
  const _TradeShareCard({
    required this.symbol,
    required this.isLong,
    required this.leverage,
    required this.profitRateStr,
    required this.pnlPositive,
    required this.openPrice,
    required this.closePrice,
    required this.openTime,
    required this.closeTime,
    this.inviteCode,
    this.inviteUrl,
  });

  final String symbol;
  final bool isLong;
  final String leverage;
  final String profitRateStr;
  final bool pnlPositive;
  final String openPrice;
  final String closePrice;
  final String openTime;
  final String closeTime;
  final String? inviteCode;
  final String? inviteUrl;

  String _baseCoin(String sym) {
    if (sym.contains('/')) return sym.split('/').first;
    return sym.toUpperCase().replaceFirst(RegExp(r'USDT$'), '');
  }

  @override
  Widget build(BuildContext context) {
    final isDark = Theme.of(context).brightness == Brightness.dark;
    final l10n = AppLocalizations.of(context)!;
    final sideColor = isLong ? AppColors.rise : AppColors.fall;
    final pnlColor = pnlPositive ? AppColors.rise : AppColors.fall;
    final coinSymbol = _baseCoin(symbol);

    // 主题色变量
    final bgColors = isDark
        ? const [Color(0xFF1A1F2E), Color(0xFF0D1117)]
        : const [Color(0xFFF8F9FB), Color(0xFFEEF0F3)];
    final textPrimary = isDark ? Colors.white : const Color(0xFF1A1F2E);
    final textSecondary = isDark
        ? Colors.white.withAlpha(120)
        : const Color(0xFF1A1F2E).withAlpha(120);
    final textMuted = isDark
        ? Colors.white.withAlpha(80)
        : const Color(0xFF1A1F2E).withAlpha(80);
    final borderColor = isDark
        ? Colors.white.withAlpha(40)
        : const Color(0xFF1A1F2E).withAlpha(30);
    final qrFgColor = isDark ? Colors.white : Colors.black;
    final qrBgColor = isDark ? const Color(0xFF1A1F2E) : Colors.white;

    return Container(
      width: double.infinity,
      decoration: BoxDecoration(
        gradient: LinearGradient(
          begin: Alignment.topLeft,
          end: Alignment.bottomRight,
          colors: bgColors,
        ),
        borderRadius: BorderRadius.circular(16),
      ),
      clipBehavior: Clip.antiAlias,
      child: Padding(
        padding: const EdgeInsets.all(20),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            // LOGO + 品牌名
            Row(
              children: [
                Image.asset(
                  'assets/images/app_icon.png',
                  height: 28,
                  width: 28,
                  errorBuilder: (_, __, ___) => const SizedBox.shrink(),
                ),
                const SizedBox(width: 8),
                Text(
                  'iBit',
                  style: TextStyle(
                      color: textPrimary,
                      fontSize: 14,
                      fontWeight: FontWeight.w700,
                      letterSpacing: 0.5),
                ),
              ],
            ),
            const SizedBox(height: 14),

            // 币对 + 永续 tag
            Row(
              children: [
                Text(
                  '${coinSymbol}USDT',
                  style: TextStyle(
                      color: textPrimary,
                      fontSize: 22,
                      fontWeight: FontWeight.w800),
                ),
                const SizedBox(width: 8),
                Container(
                  padding:
                      const EdgeInsets.symmetric(horizontal: 7, vertical: 2),
                  decoration: BoxDecoration(
                    color: const Color(0xFFFFAB00),
                    borderRadius: BorderRadius.circular(4),
                  ),
                  child: Text(l10n.perpetual,
                      style: const TextStyle(
                          color: Colors.white,
                          fontSize: 11,
                          fontWeight: FontWeight.w700)),
                ),
              ],
            ),
            const SizedBox(height: 4),

            // 方向 + 杠杆
            Text(
              '${isLong ? l10n.openLong : l10n.openShort} ${leverage}X',
              style: TextStyle(
                  color: sideColor, fontSize: 15, fontWeight: FontWeight.w700),
            ),
            const SizedBox(height: 14),

            // 收益率（大字）
            Text(l10n.returnRate,
                style: TextStyle(color: textSecondary, fontSize: 12)),
            const SizedBox(height: 4),
            Text(profitRateStr,
                style: TextStyle(
                    color: pnlColor,
                    fontSize: 36,
                    fontWeight: FontWeight.w800,
                    letterSpacing: -0.5)),
            const SizedBox(height: 16),

            // 开仓均价 + 平仓均价
            Row(
              children: [
                Expanded(
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Text(l10n.openAvgPrice,
                          style: TextStyle(color: textSecondary, fontSize: 11)),
                      const SizedBox(height: 2),
                      Text(openPrice,
                          style: TextStyle(
                              color: textPrimary,
                              fontSize: 13,
                              fontWeight: FontWeight.w600)),
                    ],
                  ),
                ),
                Expanded(
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.end,
                    children: [
                      Text(l10n.avgClosePrice,
                          style: TextStyle(color: textSecondary, fontSize: 11)),
                      const SizedBox(height: 2),
                      Text(closePrice,
                          style: TextStyle(
                              color: textPrimary,
                              fontSize: 13,
                              fontWeight: FontWeight.w600)),
                    ],
                  ),
                ),
              ],
            ),
            const SizedBox(height: 10),

            // 时间
            Text(closeTime != '--' ? closeTime : openTime,
                style: TextStyle(color: textMuted, fontSize: 11)),
            const SizedBox(height: 14),

            // 分隔线
            Divider(color: borderColor, height: 1),
            const SizedBox(height: 14),

            // 邀请码 + 二维码
            Row(
              crossAxisAlignment: CrossAxisAlignment.center,
              children: [
                Expanded(
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      if (inviteCode != null)
                        RichText(
                          text: TextSpan(
                            style: const TextStyle(fontSize: 15),
                            children: [
                              TextSpan(
                                text: l10n.inviteCodeLabel,
                                style: TextStyle(color: textSecondary),
                              ),
                              TextSpan(
                                text: inviteCode!,
                                style: const TextStyle(
                                    color: AppColors.brand,
                                    fontWeight: FontWeight.w700),
                              ),
                            ],
                          ),
                        ),
                      const SizedBox(height: 4),
                      Text(l10n.registerAndEarnRebate,
                          style: TextStyle(color: textMuted, fontSize: 12)),
                    ],
                  ),
                ),
                Container(
                  decoration: BoxDecoration(
                    border: Border.all(color: borderColor, width: 1),
                    borderRadius: BorderRadius.circular(6),
                  ),
                  padding: const EdgeInsets.all(4),
                  child: inviteUrl != null
                      ? QrImageView(
                          data: inviteUrl!,
                          version: QrVersions.auto,
                          size: 80,
                          eyeStyle: QrEyeStyle(
                            eyeShape: QrEyeShape.square,
                            color: qrFgColor,
                          ),
                          dataModuleStyle: QrDataModuleStyle(
                            dataModuleShape: QrDataModuleShape.square,
                            color: qrFgColor,
                          ),
                          backgroundColor: qrBgColor,
                          errorCorrectionLevel: QrErrorCorrectLevel.M,
                        )
                      : const SizedBox(width: 80, height: 80),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}
