import 'dart:async';

import 'package:flutter_riverpod/flutter_riverpod.dart';

import '../core/network/dio_client.dart';
import '../data/models/home/app_header_item.dart';
import '../data/models/home/market_ticker.dart';
import '../data/models/home/activity_banner.dart';
import '../data/services/asset_service.dart';
import '../data/services/market_service.dart';
import '../data/services/spot_service.dart';
import 'auth_provider.dart';
import 'coin_cache_provider.dart';
import 'top_trader_provider.dart';
import 'ws_provider.dart';

// ── UI State ──────────────────────────────────────────────

class HomeState {
  final bool isLoggedIn;
  final bool isLoading;
  final String? errorMessage;

  final double totalAsset;
  final double todayPnl;
  final double todayPnlPct;

  /// false 表示后端收益率分母为 0 / null，此时应显示 "--"
  final bool todayPnlRateAvailable;

  /// 当前市场 Tab 索引：0=自选 1=热门 2=涨幅 3=跌幅
  final int marketTabIndex;

  /// 所有币对（来自 /swap/coin/enabled-list）
  final List<MarketTicker> tickers;

  /// 涨幅榜数据（来自 /market-new/rank/rise）
  final List<MarketTicker> riseTickers;

  /// 跌幅榜数据（来自 /market-new/rank/fall）
  final List<MarketTicker> fallTickers;

  final List<ActivityBanner> banners;
  final List<AppHeaderItem> appHeaders;
  final Set<String> favorites;

  const HomeState({
    this.isLoggedIn = false,
    this.isLoading = false,
    this.errorMessage,
    this.totalAsset = 0,
    this.todayPnl = 0,
    this.todayPnlPct = 0,
    this.todayPnlRateAvailable = true,
    this.marketTabIndex = 1,
    this.tickers = const [],
    this.riseTickers = const [],
    this.fallTickers = const [],
    this.banners = const [],
    this.appHeaders = const [],
    this.favorites = const {},
  });

  HomeState copyWith({
    bool? isLoggedIn,
    bool? isLoading,
    String? errorMessage,
    double? totalAsset,
    double? todayPnl,
    double? todayPnlPct,
    bool? todayPnlRateAvailable,
    int? marketTabIndex,
    List<MarketTicker>? tickers,
    List<MarketTicker>? riseTickers,
    List<MarketTicker>? fallTickers,
    List<ActivityBanner>? banners,
    List<AppHeaderItem>? appHeaders,
    Set<String>? favorites,
  }) {
    return HomeState(
      isLoggedIn: isLoggedIn ?? this.isLoggedIn,
      isLoading: isLoading ?? this.isLoading,
      errorMessage: errorMessage,
      totalAsset: totalAsset ?? this.totalAsset,
      todayPnl: todayPnl ?? this.todayPnl,
      todayPnlPct: todayPnlPct ?? this.todayPnlPct,
      todayPnlRateAvailable: todayPnlRateAvailable ?? this.todayPnlRateAvailable,
      marketTabIndex: marketTabIndex ?? this.marketTabIndex,
      tickers: tickers ?? this.tickers,
      riseTickers: riseTickers ?? this.riseTickers,
      fallTickers: fallTickers ?? this.fallTickers,
      banners: banners ?? this.banners,
      appHeaders: appHeaders ?? this.appHeaders,
      favorites: favorites ?? this.favorites,
    );
  }

  /// 按当前 tab 返回对应数据
  List<MarketTicker> get displayTickers {
    switch (marketTabIndex) {
      case 0: // 自选
        return tickers.where((t) => favorites.contains(t.symbol)).toList();
      case 1: // 热门交易（isHot=1）
        return tickers.where((t) => t.isHot).toList();
      case 2: // 涨幅榜（接口数据）
        return riseTickers;
      case 3: // 跌幅榜（接口数据）
        return fallTickers;
      default:
        return tickers;
    }
  }
}

// ── Notifier ──────────────────────────────────────────────

class HomeNotifier extends Notifier<HomeState> {
  MarketService get _service => MarketService(ref.read(dioClientProvider));

  StreamSubscription? _tickerSub;
  Timer? _throttleTimer;
  final _tickerBuffer = <String, ({double price, double change24h, double volume24h})>{};

  /// 标记当前 notifier 是否已被 dispose；
  /// 用于阻止 in-flight 的 _loadData / _loadAssetData 在 dispose 后写 state
  /// 导致 framework 抛 `_elements.contains(element)` 断言。
  bool _disposed = false;

  void _safeUpdate(HomeState Function(HomeState) update) {
    if (_disposed) return;
    state = update(state);
  }

  @override
  HomeState build() {
    // ⚠️ Notifier 实例在 invalidate 后会被复用（同实例重新 build），
    // class field 不会随之重置，因此必须在 build 入口手动重置 _disposed，
    // 否则 invalidate 之后下次 build 时 _safeUpdate / microtask 守卫
    // 会把整个 _loadData 静默丢掉，导致首页一直停在 shimmer。
    _disposed = false;
    _tickerBuffer.clear();
    ref.listen<bool>(isLoggedInProvider, (prev, loggedIn) {
      _safeUpdate((s) => s.copyWith(isLoggedIn: loggedIn));
      // 登录状态变更：刚登录时立即拉取资产；登出时清零
      if (loggedIn && prev != true) {
        _loadAssetData();
      } else if (!loggedIn) {
        _safeUpdate((s) => s.copyWith(totalAsset: 0, todayPnl: 0, todayPnlPct: 0, todayPnlRateAvailable: true));
      }
    });
    ref.onDispose(() {
      _disposed = true;
      _tickerSub?.cancel();
      _throttleTimer?.cancel();
    });
    // 监听 WS 连接状态，重连成功后清空缓冲并重新加载数据
    ref.listen<AsyncValue<WsConnectionState>>(
      wsConnectionStateProvider,
      (prev, next) {
        final prevState = prev?.valueOrNull;
        final nextState = next.valueOrNull;
        if (prevState == WsConnectionState.reconnecting &&
            nextState == WsConnectionState.connected) {
          _tickerBuffer.clear();
          Future.microtask(() {
            if (_disposed) return;
            _loadData();
          });
        }
      },
    );
    Future.microtask(() {
      if (_disposed) return;
      _loadData();
    });
    final loggedIn = ref.read(isLoggedInProvider);
    return HomeState(isLoading: true, isLoggedIn: loggedIn);
  }

  Future<void> _loadData() async {
    try {
      // 并行请求：币对列表 + 涨幅榜 + 跌幅榜 + Banner + Header
      final results = await Future.wait([
        _service.getEnabledCoins(),
        _service.getRiseRank(),
        _service.getFallRank(),
        _service.getBanners(),
        _service.getAppHeaders(),
      ]);

      final tickers = results[0] as List<MarketTicker>;
      final riseRaw = results[1] as List<MarketTicker>;
      final fallRaw = results[2] as List<MarketTicker>;
      final banners = results[3] as List<ActivityBanner>;
      final appHeaders = results[4] as List<AppHeaderItem>;

      // 用币对缓存合并 icon 等信息到排行榜数据
      final cache = ref.read(coinCacheProvider.notifier);
      final rise = cache.mergeWithRank(riseRaw);
      final fall = cache.mergeWithRank(fallRaw);

      _safeUpdate((s) => s.copyWith(
        isLoading: false,
        tickers: tickers,
        riseTickers: rise,
        fallTickers: fall,
        banners: banners,
        appHeaders: appHeaders,
      ));

      // 已登录时加载总资产 + 今日盈亏
      if (!_disposed && state.isLoggedIn) {
        _loadAssetData();
      }

      // 收集所有需要订阅的 symbol（去重）
      if (_disposed) return;
      final allSymbols = <String>{
        ...tickers.map((t) => t.symbol),
        ...rise.map((t) => t.symbol),
        ...fall.map((t) => t.symbol),
      };
      _subscribeWs(allSymbols.toList());
    } catch (_) {
      _safeUpdate((s) => s.copyWith(isLoading: false));
    }
  }

  /// 订阅 WS ticker 流
  void _subscribeWs(List<String> symbols) {
    final ws = ref.read(wsClientProvider);
    // 差量订阅：自动退订已下架币对，订阅新增币对
    ws.resubscribeTickerBatch(symbols);

    _tickerSub?.cancel();
    _tickerSub = ws.tickerStream.listen(_onTickerUpdate);

    _throttleTimer?.cancel();
    _throttleTimer = Timer.periodic(
      const Duration(milliseconds: 500),
      (_) => _flushTickerBuffer(),
    );
  }

  void _onTickerUpdate(Map<String, dynamic> data) {
    final symbol = data['symbol'] as String?;
    final price = (data['price'] as num?)?.toDouble();
    if (symbol == null || price == null) return;

    _tickerBuffer[symbol] = (
      price: price,
      change24h: (data['change24h'] as num?)?.toDouble() ?? 0,
      volume24h: (data['volume24h'] as num?)?.toDouble() ?? 0,
    );
  }

  /// 批量刷新：将 WS 价格更新合并到 tickers / riseTickers / fallTickers
  void _flushTickerBuffer() {
    if (_disposed) return;
    if (_tickerBuffer.isEmpty) return;

    state = state.copyWith(
      tickers: _mergeBuffer(state.tickers),
      riseTickers: _mergeBuffer(state.riseTickers),
      fallTickers: _mergeBuffer(state.fallTickers),
    );
    _tickerBuffer.clear();
  }

  List<MarketTicker> _mergeBuffer(List<MarketTicker> list) {
    return list.map((t) {
      final u = _tickerBuffer[t.symbol];
      if (u == null) return t;
      return t.copyWith(
        lastPrice: u.price,
        change24h: u.change24h,
        volume24h: u.volume24h,
      );
    }).toList();
  }

  /// 加载总资产 + 今日盈亏（登录状态下调用）
  /// 总资产 = 旧账户体系（合约/跟单/资金）+ 新现货账户
  Future<void> _loadAssetData() async {
    try {
      final dio = ref.read(dioClientProvider);
      final results = await Future.wait([
        AssetService(dio).getTodayPnl(),
        SpotService(dio).getAssets().catchError((_) => <String, dynamic>{}),
      ]);

      final pnl = results[0] as dynamic; // TodayPnl
      final spotData = results[1] as Map<String, dynamic>;

      final legacyTotal = (pnl.accountInfoList as List).isNotEmpty
          ? (pnl.accountInfoList as List).fold(0.0, (sum, a) => sum + (a.currentCapital as dynamic).toDouble())
          : (pnl.cashBalance as dynamic).toDouble();
      final spotTotal = _toDoubleHome(spotData['totalAmount']);

      _safeUpdate((s) => s.copyWith(
        totalAsset: legacyTotal + spotTotal,
        todayPnl: (pnl.revenue as dynamic).toDouble(),
        todayPnlPct: ((pnl.revenueRate as dynamic)?.toDouble() ?? 0) * 100,
        todayPnlRateAvailable: pnl.revenueRate != null,
      ));
    } catch (_) {}
  }

  static double _toDoubleHome(dynamic v) {
    if (v == null) return 0.0;
    if (v is num) return v.toDouble();
    return double.tryParse(v.toString()) ?? 0.0;
  }

  /// 下拉刷新：重新拉取行情 + 资产 + 顶级交易员
  Future<void> refresh() async {
    await Future.wait([
      _loadData(),
      ref.read(topTraderProvider.notifier).refresh(),
    ]);
  }

  /// 仅刷新资产数据（点击资产卡片触发）
  Future<void> refreshAsset() async {
    if (!state.isLoggedIn) return;
    await _loadAssetData();
  }

  /// 切换市场 Tab
  void setMarketTab(int index) {
    state = state.copyWith(marketTabIndex: index);
  }

  /// 切换自选
  void toggleFavorite(String symbol) {
    final favs = Set<String>.from(state.favorites);
    if (favs.contains(symbol)) {
      favs.remove(symbol);
    } else {
      favs.add(symbol);
    }
    state = state.copyWith(favorites: favs);
  }
}

final homeProvider = NotifierProvider<HomeNotifier, HomeState>(
  HomeNotifier.new,
);
