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线宽度，不传则自动计算

  static const Color _green = Color(0xFF10B981);
  static const Color _red = Color(0xFFEF4444);
  static const Color _gridColor = Color(0xFFE5E7EB);
  static const Color _textColor = Color(0xFF6B7280);
  static const Color _crossLineColor = 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,
  });

  @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 = 8.0;

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

    // 计算价格范围
    double minPrice = double.infinity;
    double maxPrice = double.negativeInfinity;

    for (final kline in klines) {
      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 (final v in values) {
          if (v != null) {
            if (v < minPrice) minPrice = v;
            if (v > maxPrice) maxPrice = v;
          }
        }
      }
    }

    if (emaData != null) {
      for (final values in emaData!.values) {
        for (final v in values) {
          if (v != null) {
            if (v < minPrice) minPrice = v;
            if (v > maxPrice) maxPrice = v;
          }
        }
      }
    }

    if (bollData != null) {
      for (final values in bollData!.values) {
        for (final v in values) {
          if (v != null) {
            if (v < minPrice) minPrice = v;
            if (v > maxPrice) maxPrice = v;
          }
        }
      }
    }

    // 添加上下留白
    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线宽度 - 使用传入的宽度或自动计算
    final actualCandleWidth = candleWidth ?? (chartWidth / klines.length);
    final bodyWidth = math.max(actualCandleWidth * 0.7, 2.0);
    final gap = actualCandleWidth * 0.15;

    // 绘制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;

      final x = leftPadding + i * actualCandleWidth + actualCandleWidth / 2;
      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);
      final actualBodyBottom = bodyBottom - bodyTop < 1 ? bodyTop + 1 : 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,
        );
      }
    }

    // 绘制MA线
    if (maData != null) {
      int colorIndex = 0;
      for (final entry in maData!.entries) {
        _drawLine(
          canvas,
          entry.value,
          _maColors[colorIndex % _maColors.length],
          leftPadding,
          actualCandleWidth,
          priceToY,
        );
        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,
        );
        colorIndex++;
      }
    }

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

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

    // 绘制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: const TextStyle(color: _textColor, fontSize: 9),
      );
      textPainter.layout();
      textPainter.paint(canvas, Offset(size.width - rightPadding + 4, y - textPainter.height / 2));
    }
  }

  void _drawLine(
    Canvas canvas,
    List<double?> data,
    Color color,
    double leftPadding,
    double candleWidth,
    double Function(double) priceToY, {
    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;
        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,
  ) {
    final paint = Paint()
      ..color = _crossLineColor
      ..strokeWidth = 0.5;

    final x = leftPadding + index * candleWidth + candleWidth / 2;
    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: TextSpan(
        text: _formatPrice(close),
        style: const TextStyle(color: Colors.white, fontSize: 9),
      ),
      textDirection: ui.TextDirection.ltr,
    );
    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);
    return price.toStringAsExponential(2);
  }

  @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;
  }
}
