import 'package:flutter/material.dart';
import 'dart:math';

class ScoreProgressChart extends StatefulWidget {
  final List<Map<String, dynamic>> historyScores;
  final double height;
  final Color lineColor;
  final Color fillColor;

  const ScoreProgressChart({
    super.key,
    required this.historyScores,
    this.height = 60.0,
    this.lineColor = Colors.blue,
    this.fillColor = Colors.blueAccent,
  });

  @override
  State<ScoreProgressChart> createState() => _ScoreProgressChartState();
}

class _ScoreProgressChartState extends State<ScoreProgressChart> {
  int? _hoveredIndex;
  Size? _chartSize;

  List<Map<String, dynamic>> get sortedScores {
    if (widget.historyScores.isEmpty) return [];
    return List.from(widget.historyScores)
      ..sort((a, b) => (a['time'] ?? 0).compareTo(b['time'] ?? 0));
  }

  List<double> get achievements => sortedScores.map((s) {
    int ach = s['achievement'] ?? 0;
    return ach / 10000.0;
  }).toList();

  Map<String, double> get range {
    final list = achievements;
    if (list.isEmpty) return {'min': 0, 'max': 1};
    double minV = list.reduce(min);
    double maxV = list.reduce(max);
    if (minV == maxV) {
      minV = max(0, minV - 1);
      maxV = min(101, maxV + 1);
    } else {
      double r = maxV - minV;
      minV = max(0, minV - r * 0.1);
      maxV = min(101, maxV + r * 0.1);
    }
    return {'min': minV, 'max': maxV};
  }

  void _handleTap(TapDownDetails details) {
    if (_chartSize == null || achievements.isEmpty) return;
    final tap = details.localPosition;
    final minV = range['min']!;
    final maxV = range['max']!;
    final r = maxV - minV;

    List<Offset> points = [];
    for (int i = 0; i < achievements.length; i++) {
      double x = achievements.length == 1
          ? _chartSize!.width / 2
          : i * _chartSize!.width / (achievements.length - 1);
      double normY = (achievements[i] - minV) / r;
      double y = _chartSize!.height - normY * _chartSize!.height;
      points.add(Offset(x, y));
    }

    int? index;
    for (int i = 0; i < points.length; i++) {
      if ((tap - points[i]).distance < 15) {
        index = i;
        break;
      }
    }
    setState(() => _hoveredIndex = index);
  }

  @override
  Widget build(BuildContext context) {
    if (widget.historyScores.isEmpty) {
      return SizedBox(height: widget.height);
    }

    return SizedBox(
      height: widget.height,
      width: double.infinity,
      child: LayoutBuilder(
        builder: (ctx, cons) {
          _chartSize = Size(cons.maxWidth, widget.height);
          return GestureDetector(
            behavior: HitTestBehavior.opaque,
            onTapDown: _handleTap,
            child: CustomPaint(
              painter: _ChartPainter(
                achievements: achievements,
                minVal: range['min']!,
                maxVal: range['max']!,
                lineColor: widget.lineColor,
                fillColor: widget.fillColor.withOpacity(0.2),
                rawData: sortedScores,
                hoveredIndex: _hoveredIndex,
              ),
            ),
          );
        },
      ),
    );
  }
}

class _ChartPainter extends CustomPainter {
  final List<double> achievements;
  final double minVal;
  final double maxVal;
  final Color lineColor;
  final Color fillColor;
  final List<Map<String, dynamic>> rawData;
  final int? hoveredIndex;

  _ChartPainter({
    required this.achievements,
    required this.minVal,
    required this.maxVal,
    required this.lineColor,
    required this.fillColor,
    required this.rawData,
    required this.hoveredIndex,
  });

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

    final linePaint = Paint()
      ..color = lineColor
      ..strokeWidth = 2
      ..style = PaintingStyle.stroke;

    final fillPaint = Paint()..color = fillColor;
    final dotPaint = Paint()..color = lineColor;
    final highlightPaint = Paint()..color = Colors.white;

    final r = maxVal - minVal;
    List<Offset> points = [];

    for (int i = 0; i < achievements.length; i++) {
      double x = achievements.length == 1
          ? size.width / 2
          : i * size.width / (achievements.length - 1);
      double normY = (achievements[i] - minVal) / r;
      double y = size.height - normY * size.height;
      points.add(Offset(x, y));
    }

    // 填充
    final fillPath = Path()
      ..moveTo(points.first.dx, size.height)
      ..lineTo(points.first.dx, points.first.dy);
    for (var p in points) fillPath.lineTo(p.dx, p.dy);
    fillPath
      ..lineTo(points.last.dx, size.height)
      ..close();
    canvas.drawPath(fillPath, fillPaint);

    // 线条
    final linePath = Path()..moveTo(points.first.dx, points.first.dy);
    for (var p in points) linePath.lineTo(p.dx, p.dy);
    canvas.drawPath(linePath, linePaint);

    // 点
    for (var p in points) canvas.drawCircle(p, 2.5, dotPaint);

    // 高亮
    if (hoveredIndex != null && hoveredIndex! < rawData.length) {
      final p = points[hoveredIndex!];
      canvas.drawCircle(p, 5, highlightPaint);
      canvas.drawCircle(p, 3, dotPaint);
      _drawTooltip(canvas, size, p, rawData[hoveredIndex!]);
    }
  }

  void _drawTooltip(Canvas canvas, Size size, Offset p, Map<String, dynamic> data) {
    final ach = (data['achievement'] ?? 0) / 10000.0;
    final time = DateTime.fromMillisecondsSinceEpoch(data['time'] ?? 0);
    final level = data['level'] ?? 0;
    final sdx = data['deluxscoreMax'] ?? 0;
    final combo = data["comboStatus"];
    final sync = data["syncStatus"];

    final lines = [
      '达成率: ${ach.toStringAsFixed(4)}%',
      'Lv.$level  DX:$sdx',
      'Combo:$combo  Sync:$sync',
      '${time.month}/${time.day} ${time.hour}:${time.minute.toString().padLeft(2,'0')}',
    ];

    final painter = TextPainter(
      textDirection: TextDirection.ltr,
      text: TextSpan(
        style: TextStyle(color: Colors.white, fontSize: 11),
        children: lines.map((l) => TextSpan(text: '$l\n')).toList(),
      ),
    )..layout();

    final w = painter.width + 10;
    final h = painter.height + 6;
    double dx = p.dx;
    double dy = p.dy - h - 8;

    if (dx + w > size.width) dx = size.width - w;
    if (dx < 0) dx = 0;
    if (dy < 0) dy = p.dy + 8;

    canvas.drawRRect(
      RRect.fromRectAndRadius(Rect.fromLTWH(dx, dy, w, h), Radius.circular(6)),
      Paint()..color = Colors.black54,
    );
    painter.paint(canvas, Offset(dx + 5, dy + 3));
  }

  @override
  bool shouldRepaint(covariant _ChartPainter old) =>
      old.achievements != achievements || old.hoveredIndex != hoveredIndex;
}