import 'dart:math' as math;
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import '../../../domain/entities/kline.dart';

/// K线主图绘制器
class KlinePainter extends CustomPainter {
  final List<Kline> klines;
  final Map<int, List<double?>>? maData;
  final Map<int, List<double?>>? emaData;
  final Map<String, List<double?>>? bollData;
  final int crossLineIndex;
  final double? candleWidth;  // 可选的K线宽度，不传则自动计算
  final bool isDark;  // 深色模式
  final double scrollOffset;  // 滚动偏移（像素）

  static const Color _green = Color(0xFF10B981);
  static const Color _red = Color(0xFFEF4444);

  // 根据主题动态获取颜色
  Color get _gridColor => isDark ? const Color(0xFF374151) : const Color(0xFFE5E7EB);
  Color get _textColor => isDark ? const Color(0xFF9CA3AF) : const Color(0xFF6B7280);
  Color get _crossLineColor => isDark ? const Color(0xFF6B7280) : const Color(0xFF9CA3AF);

  // MA线颜色
  static const List<Color> _maColors = [
    Color(0xFFFF9800), // MA5 橙色
    Color(0xFF2196F3), // MA10 蓝色
    Color(0xFF9C27B0), // MA20 紫色
    Color(0xFF4CAF50), // MA60 绿色
  ];

  // BOLL颜色
  static const Color _bollMiddleColor = Color(0xFF2196F3);
  static const Color _bollUpperColor = Color(0xFFFF5722);
  static const Color _bollLowerColor = Color(0xFF4CAF50);

  KlinePainter({
    required this.klines,
    this.maData,
    this.emaData,
    this.bollData,
    this.crossLineIndex = -1,
    this.candleWidth,
    this.isDark = false,
    this.scrollOffset = 0.0,
  });

  @override
  void paint(Canvas canvas, Size size) {
    if (klines.isEmpty) return;

    // 绘图参数
    const leftPadding = 8.0;
    const rightPadding = 50.0;
    const topPadding = 20.0;
    const bottomPadding = 20.0;  // 增加底部空间用于时间刻度

    final chartWidth = size.width - leftPadding - rightPadding;
    final chartHeight = size.height - topPadding - bottomPadding;

    // 计算K线宽度（提前计算，用于确定可见范围）
    final actualCandleWidth = candleWidth ?? (chartWidth / klines.length);
    final bodyWidth = math.max(actualCandleWidth * 0.7, 2.0);

    // 计算可见K线的索引范围
    final visibleStart = math.max(0, (scrollOffset / actualCandleWidth - 2).floor());
    final visibleEnd = math.min(klines.length - 1, ((scrollOffset + chartWidth) / actualCandleWidth + 1).ceil());

    // 计算价格范围（只基于可见K线，实现Y轴动态缩放）
    double minPrice = double.infinity;
    double maxPrice = double.negativeInfinity;

    for (int i = visibleStart; i <= visibleEnd; i++) {
      final kline = 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;
    }

    // 考虑可见区域内MA/EMA/BOLL线的范围
    if (maData != null) {
      for (final values in maData!.values) {
        for (int i = visibleStart; i <= visibleEnd && i < values.length; i++) {
          final v = values[i];
          if (v != null) {
            if (v < minPrice) minPrice = v;
            if (v > maxPrice) maxPrice = v;
          }
        }
      }
    }

    if (emaData != null) {
      for (final values in emaData!.values) {
        for (int i = visibleStart; i <= visibleEnd && i < values.length; i++) {
          final v = values[i];
          if (v != null) {
            if (v < minPrice) minPrice = v;
            if (v > maxPrice) maxPrice = v;
          }
        }
      }
    }

    if (bollData != null) {
      for (final values in bollData!.values) {
        for (int i = visibleStart; i <= visibleEnd && i < values.length; i++) {
          final v = values[i];
          if (v != null) {
            if (v < minPrice) minPrice = v;
            if (v > maxPrice) maxPrice = v;
          }
        }
      }
    }

    // 防止无可见数据时的异常
    if (minPrice == double.infinity || maxPrice == double.negativeInfinity) {
      minPrice = 0;
      maxPrice = 1;
    }

    // 添加上下留白
    final priceRange = maxPrice - minPrice;
    // 避免 priceRange 为 0 导致 NaN
    final safePriceRange = priceRange > 0 ? priceRange : (maxPrice > 0 ? maxPrice * 0.1 : 1.0);
    final padding = safePriceRange * 0.1;
    minPrice -= padding;
    maxPrice += padding;
    final adjustedRange = maxPrice - minPrice;

    // Y坐标转换函数
    double priceToY(double price) {
      if (adjustedRange <= 0) return topPadding + chartHeight / 2;
      return topPadding + ((maxPrice - price) / adjustedRange) * chartHeight;
    }

    // 绘制网格和价格标签
    _drawGrid(canvas, size, minPrice, maxPrice, leftPadding, rightPadding, topPadding, chartHeight);

    // 裁剪绘图区域，防止K线超出边界
    canvas.save();
    canvas.clipRect(Rect.fromLTRB(leftPadding, 0, size.width - rightPadding, size.height));

    // 绘制K线
    for (int i = 0; i < klines.length; i++) {
      final kline = klines[i];
      final open = double.tryParse(kline.open) ?? 0;
      final close = double.tryParse(kline.close) ?? 0;
      final high = double.tryParse(kline.high) ?? 0;
      final low = double.tryParse(kline.low) ?? 0;

      final isUp = close >= open;
      final color = isUp ? _green : _red;
      final paint = Paint()..color = color;

      // 应用滚动偏移：scrollOffset为正时，K线向左移动
      final x = leftPadding + i * actualCandleWidth + actualCandleWidth / 2 - scrollOffset;

      // 跳过不在可见区域的K线（优化性能）
      if (x < leftPadding - actualCandleWidth || x > size.width - rightPadding + actualCandleWidth) {
        continue;
      }

      final yOpen = priceToY(open);
      final yClose = priceToY(close);
      final yHigh = priceToY(high);
      final yLow = priceToY(low);

      // 绘制影线
      canvas.drawLine(
        Offset(x, yHigh),
        Offset(x, yLow),
        paint..strokeWidth = 1,
      );

      // 绘制实体
      final bodyTop = math.min(yOpen, yClose);
      final bodyBottom = math.max(yOpen, yClose);
      // 最小实体高度：至少为蜡烛宽度的40%或3像素，避免 open≈close 时显示为横线"-"
      final minBodyHeight = math.max(bodyWidth * 0.4, 3.0);
      final actualBodyBottom = bodyBottom - bodyTop < minBodyHeight ? bodyTop + minBodyHeight : bodyBottom;

      if (isUp) {
        // 阳线：空心或实心
        canvas.drawRect(
          Rect.fromLTRB(x - bodyWidth / 2, bodyTop, x + bodyWidth / 2, actualBodyBottom),
          paint..style = PaintingStyle.fill,
        );
      } else {
        // 阴线：实心
        canvas.drawRect(
          Rect.fromLTRB(x - bodyWidth / 2, bodyTop, x + bodyWidth / 2, actualBodyBottom),
          paint..style = PaintingStyle.fill,
        );
      }
    }

    canvas.restore();

    // 绘制MA线（在裁剪区域内）
    canvas.save();
    canvas.clipRect(Rect.fromLTRB(leftPadding, 0, size.width - rightPadding, size.height));

    if (maData != null) {
      int colorIndex = 0;
      for (final entry in maData!.entries) {
        _drawLine(
          canvas,
          entry.value,
          _maColors[colorIndex % _maColors.length],
          leftPadding,
          actualCandleWidth,
          priceToY,
          scrollOffset,
        );
        colorIndex++;
      }
    }

    // 绘制EMA线
    if (emaData != null) {
      int colorIndex = 0;
      for (final entry in emaData!.entries) {
        _drawLine(
          canvas,
          entry.value,
          _maColors[colorIndex % _maColors.length],
          leftPadding,
          actualCandleWidth,
          priceToY,
          scrollOffset,
        );
        colorIndex++;
      }
    }

    // 绘制BOLL线
    if (bollData != null) {
      _drawLine(canvas, bollData!['middle']!, _bollMiddleColor, leftPadding, actualCandleWidth, priceToY, scrollOffset);
      _drawLine(canvas, bollData!['upper']!, _bollUpperColor, leftPadding, actualCandleWidth, priceToY, scrollOffset, isDashed: true);
      _drawLine(canvas, bollData!['lower']!, _bollLowerColor, leftPadding, actualCandleWidth, priceToY, scrollOffset, isDashed: true);
    }

    canvas.restore();

    // 绘制十字线
    if (crossLineIndex >= 0 && crossLineIndex < klines.length) {
      _drawCrossLine(canvas, size, crossLineIndex, leftPadding, actualCandleWidth, priceToY, scrollOffset);
    }

    // 绘制时间轴
    _drawTimeAxis(canvas, size, leftPadding, rightPadding, bottomPadding, actualCandleWidth, scrollOffset);

    // 绘制MA图例
    _drawLegend(canvas, size, leftPadding, topPadding);
  }

  void _drawGrid(
    Canvas canvas,
    Size size,
    double minPrice,
    double maxPrice,
    double leftPadding,
    double rightPadding,
    double topPadding,
    double chartHeight,
  ) {
    final gridPaint = Paint()
      ..color = _gridColor
      ..strokeWidth = 0.5;

    final textPainter = TextPainter(textDirection: ui.TextDirection.ltr);

    // 绘制水平网格线和价格标签
    const gridLines = 4;
    final priceStep = (maxPrice - minPrice) / gridLines;

    for (int i = 0; i <= gridLines; i++) {
      final y = topPadding + (chartHeight / gridLines) * i;

      // 网格线
      canvas.drawLine(
        Offset(leftPadding, y),
        Offset(size.width - rightPadding, y),
        gridPaint,
      );

      // 价格标签
      final price = maxPrice - priceStep * i;
      textPainter.text = TextSpan(
        text: _formatPrice(price),
        style: TextStyle(color: _textColor, fontSize: 9),
      );
      textPainter.layout();
      textPainter.paint(canvas, Offset(size.width - rightPadding + 4, y - textPainter.height / 2));
    }
  }

  void _drawTimeAxis(
    Canvas canvas,
    Size size,
    double leftPadding,
    double rightPadding,
    double bottomPadding,
    double candleWidth,
    double scrollOffset,
  ) {
    if (klines.isEmpty) return;

    final textPainter = TextPainter(textDirection: ui.TextDirection.ltr);
    final drawableWidth = size.width - leftPadding - rightPadding;

    // 根据K线宽度动态计算时间标签间隔
    // 目标：标签之间至少间隔60像素
    final minLabelSpacing = 60.0;
    final klinePerLabel = (minLabelSpacing / candleWidth).ceil();
    // 确保间隔是合理的数字（5, 10, 15, 20, 30, 60等）
    final intervals = [5, 10, 15, 20, 30, 60, 120, 240];
    int labelInterval = intervals.firstWhere(
      (i) => i >= klinePerLabel,
      orElse: () => klinePerLabel,
    );

    // 计算可见区域的起始和结束索引
    final startIndex = (scrollOffset / candleWidth).floor();
    final endIndex = ((scrollOffset + drawableWidth) / candleWidth).ceil();

    // 找到第一个应该显示标签的索引（对齐到间隔）
    final firstLabelIndex = ((startIndex / labelInterval).ceil()) * labelInterval;

    final y = size.height - bottomPadding + 4;

    for (int i = firstLabelIndex; i <= endIndex && i < klines.length; i += labelInterval) {
      if (i < 0) continue;

      final x = leftPadding + i * candleWidth + candleWidth / 2 - scrollOffset;

      // 检查是否在可见区域内
      if (x < leftPadding - 20 || x > size.width - rightPadding + 20) continue;

      final time = klines[i].time;
      final timeStr = _formatTimeLabel(time);

      textPainter.text = TextSpan(
        text: timeStr,
        style: TextStyle(color: _textColor, fontSize: 9),
      );
      textPainter.layout();

      // 居中绘制时间标签
      final textX = x - textPainter.width / 2;
      // 确保不超出边界
      final clampedX = textX.clamp(leftPadding, size.width - rightPadding - textPainter.width);
      textPainter.paint(canvas, Offset(clampedX, y));
    }
  }

  String _formatTimeLabel(DateTime time) {
    // 转换为本地时间
    final localTime = time.toLocal();
    // 根据时间显示不同格式
    // 如果是新的一天，显示日期；否则显示时间
    final hour = localTime.hour.toString().padLeft(2, '0');
    final minute = localTime.minute.toString().padLeft(2, '0');
    if (localTime.hour == 0 && localTime.minute == 0) {
      // 新的一天，显示月/日
      return '${localTime.month}/${localTime.day}';
    }
    return '$hour:$minute';
  }

  void _drawLine(
    Canvas canvas,
    List<double?> data,
    Color color,
    double leftPadding,
    double candleWidth,
    double Function(double) priceToY,
    double scrollOffset, {
    bool isDashed = false,
  }) {
    final paint = Paint()
      ..color = color
      ..strokeWidth = 1
      ..style = PaintingStyle.stroke;

    final path = Path();
    bool started = false;

    for (int i = 0; i < data.length; i++) {
      if (data[i] != null) {
        final x = leftPadding + i * candleWidth + candleWidth / 2 - scrollOffset;
        final y = priceToY(data[i]!);

        if (!started) {
          path.moveTo(x, y);
          started = true;
        } else {
          path.lineTo(x, y);
        }
      }
    }

    if (isDashed) {
      // 绘制虚线
      final dashPath = _createDashedPath(path, 4, 2);
      canvas.drawPath(dashPath, paint);
    } else {
      canvas.drawPath(path, paint);
    }
  }

  Path _createDashedPath(Path source, double dashLength, double gapLength) {
    final path = Path();
    for (final metric in source.computeMetrics()) {
      double distance = 0.0;
      while (distance < metric.length) {
        final next = distance + dashLength;
        path.addPath(
          metric.extractPath(distance, math.min(next, metric.length)),
          Offset.zero,
        );
        distance = next + gapLength;
      }
    }
    return path;
  }

  void _drawCrossLine(
    Canvas canvas,
    Size size,
    int index,
    double leftPadding,
    double candleWidth,
    double Function(double) priceToY,
    double scrollOffset,
  ) {
    final paint = Paint()
      ..color = _crossLineColor
      ..strokeWidth = 0.5;

    final x = leftPadding + index * candleWidth + candleWidth / 2 - scrollOffset;
    final kline = klines[index];
    final close = double.tryParse(kline.close) ?? 0;
    final y = priceToY(close);

    // 垂直线
    canvas.drawLine(
      Offset(x, 0),
      Offset(x, size.height),
      paint,
    );

    // 水平线
    canvas.drawLine(
      Offset(0, y),
      Offset(size.width, y),
      paint,
    );

    // 价格标签
    final textPainter = TextPainter(
      text: const TextSpan(
        text: '',
        style: TextStyle(color: Colors.white, fontSize: 9),
      ),
      textDirection: ui.TextDirection.ltr,
    );
    textPainter.text = TextSpan(
      text: _formatPrice(close),
      style: const TextStyle(color: Colors.white, fontSize: 9),
    );
    textPainter.layout();

    final labelRect = RRect.fromRectAndRadius(
      Rect.fromLTWH(
        size.width - 50,
        y - textPainter.height / 2 - 2,
        textPainter.width + 8,
        textPainter.height + 4,
      ),
      const Radius.circular(2),
    );

    canvas.drawRRect(labelRect, Paint()..color = _crossLineColor);
    textPainter.paint(
      canvas,
      Offset(size.width - 50 + 4, y - textPainter.height / 2),
    );
  }

  void _drawLegend(Canvas canvas, Size size, double leftPadding, double topPadding) {
    final textPainter = TextPainter(textDirection: ui.TextDirection.ltr);
    double x = leftPadding;
    final y = 4.0;
    final maxX = size.width - 60;  // 留出右侧价格标签空间

    if (maData != null) {
      int colorIndex = 0;
      for (final entry in maData!.entries) {
        if (x > maxX) break;  // 超出边界则停止绘制
        final lastValue = entry.value.lastWhere((v) => v != null, orElse: () => null);
        if (lastValue != null) {
          textPainter.text = TextSpan(
            text: 'MA${entry.key}: ${_formatPrice(lastValue)}',
            style: TextStyle(color: _maColors[colorIndex % _maColors.length], fontSize: 9),
          );
          textPainter.layout();
          if (x + textPainter.width > maxX) break;
          textPainter.paint(canvas, Offset(x, y));
          x += textPainter.width + 8;
        }
        colorIndex++;
      }
    }

    if (emaData != null) {
      int colorIndex = 0;
      for (final entry in emaData!.entries) {
        if (x > maxX) break;
        final lastValue = entry.value.lastWhere((v) => v != null, orElse: () => null);
        if (lastValue != null) {
          textPainter.text = TextSpan(
            text: 'EMA${entry.key}: ${_formatPrice(lastValue)}',
            style: TextStyle(color: _maColors[colorIndex % _maColors.length], fontSize: 9),
          );
          textPainter.layout();
          if (x + textPainter.width > maxX) break;
          textPainter.paint(canvas, Offset(x, y));
          x += textPainter.width + 8;
        }
        colorIndex++;
      }
    }

    if (bollData != null && x <= maxX) {
      final middle = bollData!['middle']?.lastWhere((v) => v != null, orElse: () => null);

      if (middle != null) {
        textPainter.text = TextSpan(
          text: 'BOLL: ${_formatPrice(middle)}',
          style: const TextStyle(color: _bollMiddleColor, fontSize: 9),
        );
        textPainter.layout();
        if (x + textPainter.width <= maxX) {
          textPainter.paint(canvas, Offset(x, y));
          x += textPainter.width + 8;
        }
      }
    }
  }

  String _formatPrice(double price) {
    if (price >= 1) return price.toStringAsFixed(4);
    if (price >= 0.0001) return price.toStringAsFixed(6);
    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 + 4, str.length);
    final significant = str.substring(sigStart, sigEnd);
    return '0.0{$zeroCount}$significant';
  }

  @override
  bool shouldRepaint(covariant KlinePainter oldDelegate) {
    return oldDelegate.klines != klines ||
        oldDelegate.maData != maData ||
        oldDelegate.emaData != emaData ||
        oldDelegate.bollData != bollData ||
        oldDelegate.crossLineIndex != crossLineIndex ||
        oldDelegate.candleWidth != candleWidth ||
        oldDelegate.isDark != isDark ||
        oldDelegate.scrollOffset != scrollOffset;
  }
}
