import 'dart:math' as math;
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import '../../../domain/entities/kline.dart';
import '../../../core/constants/app_colors.dart';
import 'kline_painter.dart';
import 'kline_indicator_painter.dart';
import 'kline_volume_painter.dart';
import 'kline_data_processor.dart';

/// K线图主组件
class KlineChartWidget extends StatefulWidget {
  final List<Kline> klines;
  final String currentPrice;
  final bool showVolume;
  final bool isFullScreen;
  final VoidCallback? onFullScreenToggle;
  final List<String> timeRanges;
  final int selectedTimeIndex;
  final Function(int)? onTimeRangeChanged;
  /// 是否正在加载更多历史数据
  final bool isLoadingMore;
  /// 是否还有更多历史数据可加载
  final bool hasMoreHistory;
  /// 加载更多历史数据的回调
  final VoidCallback? onLoadMoreHistory;

  const KlineChartWidget({
    super.key,
    required this.klines,
    required this.currentPrice,
    this.showVolume = true,
    this.isFullScreen = false,
    this.onFullScreenToggle,
    this.timeRanges = const ['1分', '5分', '15分', '30分', '1时', '4时', '日'],
    this.selectedTimeIndex = 4,
    this.onTimeRangeChanged,
    this.isLoadingMore = false,
    this.hasMoreHistory = true,
    this.onLoadMoreHistory,
  });

  @override
  State<KlineChartWidget> createState() => _KlineChartWidgetState();
}

class _KlineChartWidgetState extends State<KlineChartWidget> {
  // 品牌色彩（不随主题变化）
  static const Color _orange = AppColors.orange;
  static const Color _green = Color(0xFF10B981);
  static const Color _red = Color(0xFFEF4444);

  // 缩放和滑动状态 - 基于candleWidth的缩放模式（大厂标准做法）
  double _candleWidth = 8.0;  // 单根K线宽度（像素）
  double _prevCandleWidth = 8.0;
  double _scrollX = 0.0;  // 滚动偏移（像素）
  double _startScrollX = 0.0;
  Offset? _startFocalPoint;
  bool _isScaling = false;
  double _chartWidth = 0.0;  // 缓存图表宽度
  bool _initialized = false;  // 是否已初始化K线宽度

  // K线宽度范围
  static const double _minCandleWidth = 3.0;
  static const double _maxCandleWidth = 30.0;

  // 指标选择
  // -1: 无（不显示主图指标）, 0: MA, 1: EMA, 2: BOLL
  int _selectedMainIndicator = -1;
  int _selectedSubIndicator = 0; // 0: MACD, 1: KDJ, 2: RSI

  // 十字线
  bool _showCrossLine = false;
  int _crossLineIndex = -1;

  @override
  void initState() {
    super.initState();
    // 初始化会在 LayoutBuilder 中完成
  }

  /// 初始化 K 线宽度和滚动位置
  ///
  /// 逻辑：
  /// - K线从左边开始排列
  /// - 数据不够时，保持默认宽度，有多少显示多少
  /// - 数据量大时，计算滚动位置让最新K线在屏幕中心
  void _initializeCandleWidth(double chartWidth) {
    if (_initialized || widget.klines.isEmpty || chartWidth == 0) return;

    _initialized = true;
    _chartWidth = chartWidth;

    // 保持默认K线宽度，不根据数据量缩放
    // _candleWidth 保持初始值 8.0
    _prevCandleWidth = _candleWidth;

    // 计算滚动位置，让最新K线在屏幕中心
    _scrollToCenter();

    // 如果数据不足以填满屏幕且还有更多历史数据，自动加载更多
    _checkAndLoadMoreIfNeeded();
  }

  /// 检查是否需要自动加载更多历史数据
  void _checkAndLoadMoreIfNeeded() {
    if (!widget.hasMoreHistory || widget.isLoadingMore) return;

    const leftPadding = 8.0;
    const rightPadding = 50.0;
    final drawableWidth = _chartWidth - leftPadding - rightPadding;
    final totalKlineWidth = widget.klines.length * _candleWidth;

    // 如果K线总宽度不足以填满可绘制区域，自动加载更多历史
    if (totalKlineWidth < drawableWidth) {
      widget.onLoadMoreHistory?.call();
    }
  }

  /// 滚动使最新 K 线在屏幕中心显示
  ///
  /// 计算逻辑：
  /// - K线从左边开始排列
  /// - 数据不够时，不滚动，有多少显示多少
  /// - 数据量大时，计算滚动位置让最新K线在屏幕中心
  void _scrollToCenter() {
    if (widget.klines.isEmpty || _chartWidth == 0) return;

    // painter 内部的 padding 常量
    const leftPadding = 8.0;
    const rightPadding = 50.0;
    final drawableWidth = _chartWidth - leftPadding - rightPadding;

    // 所有K线的总宽度
    final totalKlineWidth = widget.klines.length * _candleWidth;

    if (totalKlineWidth <= drawableWidth) {
      // 数据不够填满可绘制区域，不滚动
      _scrollX = 0;
    } else {
      // 数据量足够，滚动使最新K线在屏幕中心
      // 最新K线的中心位置（从leftPadding开始）= (N-0.5) * candleWidth
      // 目标：让这个位置对齐到 drawableWidth/2
      // scrollOffset = (N-0.5) * candleWidth - drawableWidth/2
      _scrollX = (widget.klines.length - 0.5) * _candleWidth - drawableWidth / 2;
      _scrollX = math.max(0.0, _scrollX);
    }
  }

  /// 滚动到最右边（显示最新数据在右侧）
  void _scrollToEnd() {
    if (widget.klines.isEmpty || _chartWidth == 0) return;
    final totalWidth = widget.klines.length * _candleWidth;
    final maxScroll = math.max(0.0, totalWidth - _chartWidth);
    _scrollX = maxScroll;
  }

  @override
  void didUpdateWidget(KlineChartWidget oldWidget) {
    super.didUpdateWidget(oldWidget);
    // 当 K 线数据变化时，重新初始化
    if (oldWidget.klines.length != widget.klines.length) {
      _initialized = false;
      _scrollX = 0;
    }
  }

  @override
  Widget build(BuildContext context) {
    if (widget.isFullScreen) {
      return _buildFullScreenChart();
    }
    return _buildNormalChart();
  }

  Widget _buildNormalChart() {
    return Container(
      decoration: BoxDecoration(
        color: AppColors.cardOf(context),
        borderRadius: BorderRadius.circular(16),
      ),
      child: Column(
        children: [
          // 顶部工具栏
          _buildToolbar(),
          // K线图区域
          _buildChartArea(height: 200),
          // 时间周期选择
          _buildTimeRangeSelector(),
        ],
      ),
    );
  }

  Widget _buildFullScreenChart() {
    return Scaffold(
      backgroundColor: AppColors.backgroundOf(context),
      appBar: AppBar(
        backgroundColor: AppColors.cardOf(context),
        elevation: 0,
        leading: IconButton(
          icon: Icon(Icons.close, color: AppColors.textPrimaryOf(context)),
          onPressed: widget.onFullScreenToggle,
        ),
        title: Text(
          'K线图',
          style: TextStyle(
            fontSize: 18,
            fontWeight: FontWeight.bold,
            color: AppColors.textPrimaryOf(context),
          ),
        ),
        centerTitle: true,
        actions: [
          IconButton(
            icon: const Icon(Icons.refresh, color: _orange),
            onPressed: () {
              setState(() {
                _candleWidth = 8.0;
                _scrollToEnd();
              });
            },
          ),
        ],
      ),
      body: SafeArea(
        child: Column(
          children: [
            // 指标选择器（暂时隐藏，需要时取消注释）
            // _buildIndicatorSelector(),
            // K线图区域（占据大部分空间）
            Expanded(child: _buildChartArea()),
            // 时间周期选择
            _buildTimeRangeSelector(),
            const SizedBox(height: 8),
          ],
        ),
      ),
    );
  }

  Widget _buildToolbar() {
    return Padding(
      padding: const EdgeInsets.fromLTRB(16, 12, 8, 8),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: [
          // 指标切换（暂时隐藏，需要时取消注释）
          // Row(
          //   children: [
          //     _buildIndicatorChip('MA', _selectedMainIndicator == 0, () {
          //       setState(() => _selectedMainIndicator = 0);
          //     }),
          //     const SizedBox(width: 8),
          //     _buildIndicatorChip('MACD', _selectedSubIndicator == 0, () {
          //       setState(() => _selectedSubIndicator = 0);
          //     }),
          //     const SizedBox(width: 8),
          //     _buildIndicatorChip('KDJ', _selectedSubIndicator == 1, () {
          //       setState(() => _selectedSubIndicator = 1);
          //     }),
          //   ],
          // ),
          const SizedBox(), // 占位
          // 全屏按钮
          IconButton(
            icon: Icon(
              widget.isFullScreen ? Icons.fullscreen_exit : Icons.fullscreen,
              color: _orange,
              size: 24,
            ),
            onPressed: widget.onFullScreenToggle,
            padding: EdgeInsets.zero,
            constraints: const BoxConstraints(minWidth: 32, minHeight: 32),
          ),
        ],
      ),
    );
  }

  Widget _buildIndicatorChip(String label, bool isSelected, VoidCallback onTap) {
    final isDark = AppColors.isDark(context);
    return GestureDetector(
      onTap: onTap,
      child: Container(
        padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
        decoration: BoxDecoration(
          color: isSelected ? _orange.withOpacity(isDark ? 0.2 : 0.1) : Colors.transparent,
          borderRadius: BorderRadius.circular(4),
          border: Border.all(
            color: isSelected ? _orange : AppColors.borderOf(context),
          ),
        ),
        child: Text(
          label,
          style: TextStyle(
            fontSize: 11,
            fontWeight: isSelected ? FontWeight.bold : FontWeight.normal,
            color: isSelected ? _orange : AppColors.textSecondaryOf(context),
          ),
        ),
      ),
    );
  }

  Widget _buildIndicatorSelector() {
    return Container(
      padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
      decoration: BoxDecoration(
        border: Border(bottom: BorderSide(color: AppColors.borderOf(context))),
      ),
      child: SingleChildScrollView(
        scrollDirection: Axis.horizontal,
        child: Row(
          children: [
            Text('主图:', style: TextStyle(fontSize: 12, color: AppColors.textSecondaryOf(context))),
            const SizedBox(width: 8),
            _buildIndicatorChip('MA', _selectedMainIndicator == 0, () {
              setState(() => _selectedMainIndicator = 0);
            }),
            const SizedBox(width: 4),
            _buildIndicatorChip('EMA', _selectedMainIndicator == 1, () {
              setState(() => _selectedMainIndicator = 1);
            }),
            const SizedBox(width: 4),
            _buildIndicatorChip('BOLL', _selectedMainIndicator == 2, () {
              setState(() => _selectedMainIndicator = 2);
            }),
            const SizedBox(width: 16),
            Text('副图:', style: TextStyle(fontSize: 12, color: AppColors.textSecondaryOf(context))),
            const SizedBox(width: 8),
            _buildIndicatorChip('MACD', _selectedSubIndicator == 0, () {
              setState(() => _selectedSubIndicator = 0);
            }),
            const SizedBox(width: 4),
            _buildIndicatorChip('KDJ', _selectedSubIndicator == 1, () {
              setState(() => _selectedSubIndicator = 1);
            }),
            const SizedBox(width: 4),
            _buildIndicatorChip('RSI', _selectedSubIndicator == 2, () {
              setState(() => _selectedSubIndicator = 2);
            }),
          ],
        ),
      ),
    );
  }

  Widget _buildChartArea({double? height}) {
    return GestureDetector(
      onScaleStart: _onScaleStart,
      onScaleUpdate: _onScaleUpdate,
      onScaleEnd: _onScaleEnd,
      onLongPressStart: _onLongPressStart,
      onLongPressMoveUpdate: _onLongPressMoveUpdate,
      onLongPressEnd: _onLongPressEnd,
      child: Container(
        height: height,
        padding: const EdgeInsets.symmetric(horizontal: 8),
        child: LayoutBuilder(
          builder: (context, constraints) {
            final chartHeight = height ?? constraints.maxHeight;
            final chartWidth = constraints.maxWidth;

            // 缓存图表宽度用于滚动计算
            _chartWidth = chartWidth;

            // 初始化 K 线宽度（首次加载时让 K 线占满屏幕）
            if (!_initialized && widget.klines.isNotEmpty) {
              WidgetsBinding.instance.addPostFrameCallback((_) {
                _initializeCandleWidth(chartWidth);
                if (mounted) setState(() {});
              });
            }

            if (widget.klines.isEmpty) {
              return Center(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    Icon(Icons.show_chart, size: 48, color: AppColors.textMutedOf(context)),
                    const SizedBox(height: 8),
                    Text('暂无K线数据', style: TextStyle(color: AppColors.textSecondaryOf(context))),
                  ],
                ),
              );
            }

            // 计算指标数据
            final processor = KlineDataProcessor(widget.klines);
            final maData = processor.calculateMA([5, 10, 20, 60]);
            final macdData = processor.calculateMACD();
            final kdjData = processor.calculateKDJ();
            final rsiData = processor.calculateRSI();
            final bollData = processor.calculateBOLL();
            final emaData = processor.calculateEMA([5, 10, 20]);

            // 计算各区域高度 - 隐藏副图指标后重新分配空间
            // 主图：75%，成交量：25%（隐藏副图指标）
            final mainChartHeight = widget.showVolume
                ? chartHeight * 0.75
                : chartHeight * 1.0;
            final volumeHeight = widget.showVolume
                ? chartHeight * 0.25
                : 0.0;
            // 副图指标高度（暂时隐藏，需要时取消注释并恢复下方副图代码）
            // final indicatorHeight = chartHeight * 0.20;

            return Column(
              children: [
                // 主图（K线 + MA/EMA/BOLL）
                SizedBox(
                  height: mainChartHeight,
                  child: Stack(
                    children: [
                      CustomPaint(
                        size: Size(chartWidth, mainChartHeight),
                        painter: KlinePainter(
                          klines: widget.klines,
                          maData: _selectedMainIndicator == 0 ? maData : null,
                          emaData: _selectedMainIndicator == 1 ? emaData : null,
                          bollData: _selectedMainIndicator == 2 ? bollData : null,
                          crossLineIndex: _showCrossLine ? _crossLineIndex : -1,
                          candleWidth: _candleWidth,
                          isDark: AppColors.isDark(context),
                          scrollOffset: _scrollX,
                        ),
                      ),
                      // 加载更多历史数据指示器
                      if (widget.isLoadingMore)
                        Positioned(
                          left: 8,
                          top: mainChartHeight / 2 - 12,
                          child: Container(
                            padding: const EdgeInsets.all(8),
                            decoration: BoxDecoration(
                              color: AppColors.cardOf(context).withOpacity(0.9),
                              borderRadius: BorderRadius.circular(8),
                            ),
                            child: Row(
                              mainAxisSize: MainAxisSize.min,
                              children: [
                                SizedBox(
                                  width: 16,
                                  height: 16,
                                  child: CircularProgressIndicator(
                                    strokeWidth: 2,
                                    color: _orange,
                                  ),
                                ),
                                const SizedBox(width: 8),
                                Text(
                                  '加载中...',
                                  style: TextStyle(
                                    fontSize: 11,
                                    color: AppColors.textSecondaryOf(context),
                                  ),
                                ),
                              ],
                            ),
                          ),
                        ),
                      // 十字线信息
                      if (_showCrossLine && _crossLineIndex >= 0 && _crossLineIndex < widget.klines.length)
                        _buildCrossLineInfo(),
                      // 当前价格标签
                      if (widget.klines.isNotEmpty)
                        Positioned(
                          right: 0,
                          top: _calcPriceY(
                            double.tryParse(widget.currentPrice) ?? 0,
                            mainChartHeight,
                          ),
                          child: Container(
                            padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 2),
                            decoration: BoxDecoration(
                              color: _orange,
                              borderRadius: BorderRadius.circular(2),
                            ),
                            child: Text(
                              _formatPrice(double.tryParse(widget.currentPrice) ?? 0),
                              style: const TextStyle(fontSize: 9, color: Colors.white),
                            ),
                          ),
                        ),
                    ],
                  ),
                ),
                // 成交量图
                if (widget.showVolume)
                  SizedBox(
                    height: volumeHeight,
                    child: CustomPaint(
                      size: Size(chartWidth, volumeHeight),
                      painter: KlineVolumePainter(
                        klines: widget.klines,
                        crossLineIndex: _showCrossLine ? _crossLineIndex : -1,
                        candleWidth: _candleWidth,
                        isDark: AppColors.isDark(context),
                        scrollOffset: _scrollX,
                      ),
                    ),
                  ),
                // 副图指标（MACD/KDJ/RSI）- 暂时隐藏，需要时取消注释
                // SizedBox(
                //   height: indicatorHeight,
                //   child: CustomPaint(
                //     size: Size(chartWidth, indicatorHeight),
                //     painter: KlineIndicatorPainter(
                //       indicatorType: _selectedSubIndicator,
                //       macdData: _selectedSubIndicator == 0 ? macdData : null,
                //       kdjData: _selectedSubIndicator == 1 ? kdjData : null,
                //       rsiData: _selectedSubIndicator == 2 ? rsiData : null,
                //       crossLineIndex: _showCrossLine ? _crossLineIndex : -1,
                //       candleWidth: _candleWidth,
                //       scrollOffset: _scrollX,
                //     ),
                //   ),
                // ),
              ],
            );
          },
        ),
      ),
    );
  }

  Widget _buildTimeRangeSelector() {
    return Padding(
      padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 8),
      child: SingleChildScrollView(
        scrollDirection: Axis.horizontal,
        child: Row(
          children: List.generate(widget.timeRanges.length, (index) {
            final isSelected = widget.selectedTimeIndex == index;
            return Padding(
              padding: const EdgeInsets.only(right: 8),
              child: GestureDetector(
                onTap: () => widget.onTimeRangeChanged?.call(index),
                child: Container(
                  padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 6),
                  decoration: BoxDecoration(
                    color: isSelected ? _orange : AppColors.cardOf(context),
                    borderRadius: BorderRadius.circular(9999),
                    border: isSelected ? null : Border.all(color: AppColors.borderOf(context)),
                  ),
                  child: Text(
                    widget.timeRanges[index],
                    style: TextStyle(
                      fontSize: 12,
                      fontWeight: FontWeight.w500,
                      color: isSelected ? Colors.white : AppColors.textSecondaryOf(context),
                    ),
                  ),
                ),
              ),
            );
          }),
        ),
      ),
    );
  }

  // 手势处理
  void _onScaleStart(ScaleStartDetails details) {
    _prevCandleWidth = _candleWidth;
    _startFocalPoint = details.focalPoint;
    _isScaling = details.pointerCount > 1;
    _startScrollX = _scrollX;
  }

  void _onScaleUpdate(ScaleUpdateDetails details) {
    setState(() {
      // painter 内部的 padding 常量
      const leftPadding = 8.0;
      const rightPadding = 50.0;
      final drawableWidth = _chartWidth - leftPadding - rightPadding;

      // 两指缩放
      if (_isScaling) {
        final newCandleWidth = (_prevCandleWidth * details.scale).clamp(_minCandleWidth, _maxCandleWidth);

        if (_startFocalPoint != null && _chartWidth > 0) {
          final focalRatio = _startFocalPoint!.dx / _chartWidth;
          final oldFocalIndex = (_startScrollX + _startFocalPoint!.dx) / _prevCandleWidth;
          final newFocalX = oldFocalIndex * newCandleWidth;
          // 缩放后重新计算maxScroll
          final newDrawableWidth = _chartWidth - leftPadding - rightPadding;
          final double maxScroll = math.max(0.0, (widget.klines.length - 0.5) * newCandleWidth - newDrawableWidth / 2);
          _scrollX = (newFocalX - focalRatio * _chartWidth).clamp(0.0, maxScroll);
        }

        _candleWidth = newCandleWidth;
      } else if (_startFocalPoint != null) {
        // 单指平移
        // dx > 0 向右滑（看更早历史），dx < 0 向左滑（看更新数据）
        final dx = details.focalPoint.dx - _startFocalPoint!.dx;
        // 最大滚动位置：让最新K线在屏幕中心
        final double maxScroll = math.max(0.0, (widget.klines.length - 0.5) * _candleWidth - drawableWidth / 2);
        // 向右滑 dx>0，scrollX 减小，显示更早的数据
        _scrollX = (_startScrollX - dx).clamp(0.0, maxScroll);
      }
    });
  }

  void _onScaleEnd(ScaleEndDetails details) {
    _startFocalPoint = null;
    _isScaling = false;

    // 检查是否滚动到了左边界（历史数据边界）
    // 如果滚动接近0且还有更多历史数据，触发加载
    if (_scrollX <= 50 && widget.hasMoreHistory && !widget.isLoadingMore) {
      widget.onLoadMoreHistory?.call();
    }
  }

  void _onLongPressStart(LongPressStartDetails details) {
    _updateCrossLine(details.localPosition);
    HapticFeedback.mediumImpact();
  }

  void _onLongPressMoveUpdate(LongPressMoveUpdateDetails details) {
    _updateCrossLine(details.localPosition);
  }

  void _onLongPressEnd(LongPressEndDetails details) {
    setState(() {
      _showCrossLine = false;
      _crossLineIndex = -1;
    });
  }

  void _updateCrossLine(Offset position) {
    if (widget.klines.isEmpty || _chartWidth == 0) return;

    setState(() {
      _showCrossLine = true;

      // 计算对应的K线索引（基于像素位置）
      // position.dx 是相对于widget的位置
      // painter 中第i根K线的x坐标 = leftPadding + i * candleWidth + candleWidth/2 - scrollOffset
      // 所以 i = (position.dx + scrollOffset - leftPadding - candleWidth/2) / candleWidth
      //      i = (position.dx + scrollOffset - leftPadding) / candleWidth - 0.5
      const leftPadding = 8.0;
      final index = ((position.dx + _scrollX - leftPadding) / _candleWidth).floor().clamp(0, widget.klines.length - 1);
      _crossLineIndex = index;
    });
  }

  Widget _buildCrossLineInfo() {
    if (_crossLineIndex < 0 || _crossLineIndex >= widget.klines.length) {
      return const SizedBox.shrink();
    }

    final kline = widget.klines[_crossLineIndex];
    final open = double.tryParse(kline.open) ?? 0;
    final high = double.tryParse(kline.high) ?? 0;
    final low = double.tryParse(kline.low) ?? 0;
    final close = double.tryParse(kline.close) ?? 0;
    final volume = double.tryParse(kline.volume) ?? 0;
    final isUp = close >= open;

    final isDark = AppColors.isDark(context);
    return Positioned(
      left: 8,
      top: 8,
      child: Container(
        padding: const EdgeInsets.all(8),
        decoration: BoxDecoration(
          color: AppColors.cardOf(context).withOpacity(0.95),
          borderRadius: BorderRadius.circular(8),
          border: Border.all(color: AppColors.borderOf(context)),
          boxShadow: [
            BoxShadow(
              color: Colors.black.withOpacity(isDark ? 0.3 : 0.1),
              blurRadius: 4,
            ),
          ],
        ),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          mainAxisSize: MainAxisSize.min,
          children: [
            Text(
              _formatDateTime(kline.time),
              style: TextStyle(fontSize: 10, color: AppColors.textSecondaryOf(context)),
            ),
            const SizedBox(height: 4),
            Row(
              mainAxisSize: MainAxisSize.min,
              children: [
                _buildInfoItem('开', _formatPrice(open), isUp ? _green : _red),
                const SizedBox(width: 12),
                _buildInfoItem('高', _formatPrice(high), _red),
              ],
            ),
            const SizedBox(height: 2),
            Row(
              mainAxisSize: MainAxisSize.min,
              children: [
                _buildInfoItem('低', _formatPrice(low), _green),
                const SizedBox(width: 12),
                _buildInfoItem('收', _formatPrice(close), isUp ? _green : _red),
              ],
            ),
            const SizedBox(height: 2),
            _buildInfoItem('量', _formatVolume(volume), AppColors.textSecondaryOf(context)),
          ],
        ),
      ),
    );
  }

  Widget _buildInfoItem(String label, String value, Color valueColor) {
    return Row(
      mainAxisSize: MainAxisSize.min,
      children: [
        Text(
          '$label: ',
          style: TextStyle(fontSize: 10, color: AppColors.textSecondaryOf(context)),
        ),
        Text(
          value,
          style: TextStyle(fontSize: 10, fontWeight: FontWeight.w500, color: valueColor),
        ),
      ],
    );
  }

  String _formatPrice(double price) {
    if (price >= 1) return price.toStringAsFixed(9);
    if (price >= 0.0001) return price.toStringAsFixed(11);
    if (price <= 0) return '0';
    // 0.00000980 → 0.0{5}980
    final str = price.toStringAsFixed(18);
    final dotIndex = str.indexOf('.');
    int zeroCount = 0;
    for (int i = dotIndex + 1; i < str.length; i++) {
      if (str[i] == '0') {
        zeroCount++;
      } else {
        break;
      }
    }
    final sigStart = dotIndex + 1 + zeroCount;
    final sigEnd = math.min(sigStart + 9, str.length);
    final significant = str.substring(sigStart, sigEnd);
    return '0.0{$zeroCount}$significant';
  }

  String _formatVolume(double volume) {
    if (volume >= 1000000) return '${(volume / 1000000).toStringAsFixed(2)}M';
    if (volume >= 1000) return '${(volume / 1000).toStringAsFixed(2)}K';
    return volume.toStringAsFixed(2);
  }

  String _formatDateTime(DateTime time) {
    // 转换为本地时间
    final localTime = time.toLocal();
    return '${localTime.month}/${localTime.day} ${localTime.hour.toString().padLeft(2, '0')}:${localTime.minute.toString().padLeft(2, '0')}';
  }

  double _calcPriceY(double price, double chartHeight) {
    if (widget.klines.isEmpty || _chartWidth == 0) return chartHeight / 2;

    // 与 KlinePainter 保持一致：只基于可见K线计算Y轴范围
    const leftPadding = 8.0;
    const rightPadding = 50.0;
    final drawableWidth = _chartWidth - leftPadding - rightPadding;

    final visibleStart = math.max(0, (_scrollX / _candleWidth - 2).floor());
    final visibleEnd = math.min(widget.klines.length - 1, ((_scrollX + drawableWidth) / _candleWidth + 1).ceil());

    double minPrice = double.infinity;
    double maxPrice = double.negativeInfinity;
    for (int i = visibleStart; i <= visibleEnd; i++) {
      final kline = widget.klines[i];
      final low = double.tryParse(kline.low) ?? 0;
      final high = double.tryParse(kline.high) ?? 0;
      if (low < minPrice) minPrice = low;
      if (high > maxPrice) maxPrice = high;
    }

    if (minPrice == double.infinity || maxPrice == double.negativeInfinity) {
      return chartHeight / 2;
    }

    final range = maxPrice - minPrice;
    // 防止 range 为 0 导致 NaN
    final safeRange = range > 0 ? range : (maxPrice > 0 ? maxPrice * 0.1 : 1.0);
    final padding = safeRange * 0.1;
    minPrice -= padding;
    maxPrice += padding;

    final adjustedRange = maxPrice - minPrice;
    if (adjustedRange <= 0) return chartHeight / 2;

    final y = 10 + ((maxPrice - price) / adjustedRange) * (chartHeight - 20);
    return y.clamp(0.0, chartHeight - 20);
  }
}
