/// 行情 Ticker 数据模型（不可变）
/// 实现 == / hashCode 让 .select() 能正确判断单个 ticker 是否变化，
/// 只有该 symbol 的价格/涨跌幅真正变了才触发对应行重建。
class MarketTicker {
  final String symbol;    // e.g. "BTCUSDT"
  final String baseAsset; // e.g. "BTC"
  final double lastPrice;
  final double change24h; // 24h 涨跌幅（百分比）
  final double volume24h; // 24h 成交额（USDT）
  final bool isFutures;   // true = 永续合约，false = 现货
  final bool isHot;       // 是否热门
  final String icon;      // 币种图标 URL
  final int? pricePrecision; // 价格精度（小数位数），来自 coinScale
  final String? lastPriceStr; // WS 返回的原始价格字符串

  const MarketTicker({
    required this.symbol,
    required this.baseAsset,
    required this.lastPrice,
    required this.change24h,
    required this.volume24h,
    this.isFutures = true,
    this.isHot = false,
    this.icon = '',
    this.pricePrecision,
    this.lastPriceStr,
  });

  /// 从 /swap/coin/enabled-list 接口解析
  /// 接口字段: symbol("BTC/USDT"), coinSymbol("BTC"), baseSymbol("USDT"), isHot(1/0)
  /// 价格数据由 WebSocket 推送，初始为 0
  factory MarketTicker.fromJson(Map<String, dynamic> json) {
    // symbol 格式 "BTC/USDT" → 转为 "BTCUSDT"
    final rawSymbol = json['symbol'] as String? ?? '';
    final symbol = rawSymbol.replaceAll('/', '');
    final coinSymbol = json['coinSymbol'] as String? ?? '';
    final rawScale = (json['coinScale'] ?? json['minScale']) as num?;
    return MarketTicker(
      symbol: symbol,
      baseAsset: coinSymbol,
      lastPrice: 0,
      change24h: 0,
      volume24h: 0,
      isFutures: true,
      isHot: json['isHot'] == 1 || json['isHot'] == '1',
      icon: json['icon'] as String? ?? '',
      pricePrecision: rawScale?.toInt(),
    );
  }

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is MarketTicker &&
          symbol == other.symbol &&
          baseAsset == other.baseAsset &&
          lastPrice == other.lastPrice &&
          change24h == other.change24h &&
          volume24h == other.volume24h &&
          isFutures == other.isFutures &&
          isHot == other.isHot &&
          icon == other.icon &&
          pricePrecision == other.pricePrecision &&
          lastPriceStr == other.lastPriceStr;

  @override
  int get hashCode =>
      Object.hash(symbol, baseAsset, lastPrice, change24h, volume24h, isFutures, isHot, icon, pricePrecision, lastPriceStr);

  MarketTicker copyWith({
    String? symbol,
    String? baseAsset,
    double? lastPrice,
    double? change24h,
    double? volume24h,
    bool? isFutures,
    bool? isHot,
    String? icon,
    int? pricePrecision,
    String? lastPriceStr,
  }) {
    return MarketTicker(
      symbol: symbol ?? this.symbol,
      baseAsset: baseAsset ?? this.baseAsset,
      lastPrice: lastPrice ?? this.lastPrice,
      change24h: change24h ?? this.change24h,
      volume24h: volume24h ?? this.volume24h,
      isFutures: isFutures ?? this.isFutures,
      isHot: isHot ?? this.isHot,
      icon: icon ?? this.icon,
      pricePrecision: pricePrecision ?? this.pricePrecision,
      lastPriceStr: lastPriceStr ?? this.lastPriceStr,
    );
  }
}
