import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:vbvs_app/common/util/FitTool.dart';
import 'package:vbvs_app/common/util/MyUtils.dart';
import 'dart:ui' as ui;

class DotBarChart extends StatefulWidget {
  final List<Map<String, dynamic>> showLabel;
  final int threshold;
  final int startTime;
  final int endTime;

  const DotBarChart({
    Key? key,
    required this.showLabel,
    required this.threshold,
    required this.startTime,
    required this.endTime,
  }) : super(key: key);

  @override
  _DotBarChartState createState() => _DotBarChartState();
}

class _DotBarChartState extends State<DotBarChart> {
  int? selectedIndex;
  OverlayEntry? _overlayEntry;

  @override
  void dispose() {
    _removeOverlay();
    super.dispose();
  }

  void _removeOverlay() {
    _overlayEntry?.remove();
    _overlayEntry = null;
  }

  void _showTooltip(BuildContext context, Map<String, dynamic> data,
      Offset position, double dotY) {
    _removeOverlay();
    final RenderBox renderBox = context.findRenderObject() as RenderBox;
    final Offset globalPosition = renderBox.localToGlobal(position);

    _overlayEntry = OverlayEntry(
      builder: (context) => Positioned(
        left: globalPosition.dx - 60.rpx,
        top: globalPosition.dy - 80.rpx,
        child: Material(
          color: Colors.transparent,
          child: Container(
            padding: EdgeInsets.all(12.rpx),
            decoration: BoxDecoration(
              color: themeController.currentColor.sc5,
              borderRadius: BorderRadius.circular(8.rpx),
              boxShadow: [
                BoxShadow(
                  color: Colors.black.withOpacity(0.5),
                  blurRadius: 12.rpx,
                  spreadRadius: 2.rpx,
                  offset: Offset(0, 6.rpx),
                ),
              ],
            ),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  '时间: ${DateFormat('HH:mm').format(DateTime.fromMillisecondsSinceEpoch(data['time']))}',
                  style: TextStyle(
                    fontSize: 20.rpx,
                    color: themeController.currentColor.sc3,
                  ),
                ),
                SizedBox(height: 4.rpx),
                Text(
                  '时长: ${data['times']}秒',
                  style: TextStyle(
                    fontSize: 20.rpx,
                    color: themeController.currentColor.sc3,
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    );
    Overlay.of(context)?.insert(_overlayEntry!);
  }

  @override
  Widget build(BuildContext context) {
    if (widget.showLabel.isEmpty) return const SizedBox();

    int maxTimes = widget.showLabel
        .map((e) => e['times'] ?? 0)
        .reduce((a, b) => a > b ? a : b);
    int yMax = (maxTimes / 10).ceil() * 10;
    if (yMax == 0) yMax = 10;

    int maxSteps = 6;
    int step = (yMax / maxSteps).ceil();
    step = ((step + 9) ~/ 10) * 10;
    int displayMax = step * maxSteps;
    List<int> yLabels = List.generate(maxSteps + 1, (index) => step * index);

    DateTime startDate = DateTime.fromMillisecondsSinceEpoch(widget.startTime);
    DateTime endDate = DateTime.fromMillisecondsSinceEpoch(widget.endTime);

    // Generate hourly timestamps
    List<int> hourlyTimestamps = [];
    DateTime currentHour = DateTime(
        startDate.year, startDate.month, startDate.day, startDate.hour);
    while (currentHour.isBefore(endDate) ||
        currentHour.isAtSameMomentAs(endDate)) {
      hourlyTimestamps.add(currentHour.millisecondsSinceEpoch);
      currentHour = currentHour.add(const Duration(hours: 1));
    }

    // Calculate positions for hourly labels
    List<Map<String, dynamic>> hourLabels = [];
    if (widget.showLabel.isNotEmpty) {
      int firstDataTime = widget.showLabel.first['time'];
      int lastDataTime = widget.showLabel.last['time'];
      double totalDuration = (lastDataTime - firstDataTime).toDouble();

      for (int timestamp in hourlyTimestamps) {
        if (timestamp >= firstDataTime && timestamp <= lastDataTime) {
          double position = (timestamp - firstDataTime) / totalDuration;
          hourLabels.add({
            'time': timestamp,
            'position': position,
          });
        }
      }
    }

    double yAxisWidth = 36.rpx;
    double xAxisHeight = 40.rpx;
    double chartHeight = 491.rpx;
    double bottomPadding = 10.rpx;

    return GestureDetector(
      onTap: () {
        setState(() {
          selectedIndex = null;
          _removeOverlay();
        });
      },
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          SizedBox(
            height: chartHeight,
            child: Row(
              children: [
                SizedBox(
                  width: yAxisWidth,
                  height: chartHeight + bottomPadding,
                  child: Stack(
                    children: [
                      Positioned(
                        top: 0,
                        right: 6.rpx,
                        child: Text(
                          '秒',
                          style: TextStyle(
                            fontSize: 18.rpx,
                            color: themeController.currentColor.sc4,
                          ),
                        ),
                      ),
                      ...List.generate(yLabels.length, (index) {
                        double yLabelsAreaHeight =
                            chartHeight - (30.rpx + 18.rpx) - bottomPadding;
                        double y = (30.rpx + 18.rpx) +
                            index * (yLabelsAreaHeight / (yLabels.length - 1));
                        double textHeight = 18.rpx;
                        double topPos = y - textHeight / 2;
                        if (index == yLabels.length - 1) {
                          topPos -= bottomPadding / 2;
                        }
                        return Positioned(
                          right: 6.rpx,
                          top: topPos,
                          child: Text(
                            '${yLabels.reversed.toList()[index]}',
                            style: TextStyle(
                              fontSize: 18.rpx,
                              color: themeController.currentColor.sc4,
                            ),
                          ),
                        );
                      }),
                    ],
                  ),
                ),
                Expanded(
                  child: CustomPaint(
                    size: Size(double.infinity, chartHeight),
                    painter: _DotBarChartPainter(
                      data: widget.showLabel,
                      yMax: displayMax,
                      threshold: widget.threshold,
                      yLabelsCount: yLabels.length,
                      yAxisTopPadding: 30.rpx + 18.rpx,
                      horizontalPadding: 20.rpx,
                      selectedIndex: selectedIndex,
                    ),
                    child: LayoutBuilder(
                      builder: (context, constraints) {
                        final double chartWidth =
                            constraints.maxWidth - 2 * 20.rpx;
                        final double xStep = widget.showLabel.length > 1
                            ? chartWidth / (widget.showLabel.length - 1)
                            : 0;
                        final double drawableHeight =
                            chartHeight - (30.rpx + 18.rpx);

                        return Stack(
                          children:
                              widget.showLabel.asMap().entries.map((entry) {
                            int index = entry.key;
                            Map<String, dynamic> data = entry.value;
                            int times = data['times'] ?? 0;
                            double x = 20.rpx + index * xStep;
                            double y = (30.rpx + 18.rpx) +
                                drawableHeight * (1 - times / displayMax);

                            return Positioned(
                              left: x - 20.rpx,
                              top: y - 20.rpx,
                              child: GestureDetector(
                                onTap: () {
                                  setState(() {
                                    selectedIndex = index;
                                  });
                                  _showTooltip(context, data, Offset(x, y), y);
                                },
                                child: Container(
                                  width: 40.rpx,
                                  height: 40.rpx,
                                  color: Colors.transparent,
                                ),
                              ),
                            );
                          }).toList(),
                        );
                      },
                    ),
                  ),
                ),
              ],
            ),
          ),
          Padding(
            padding: EdgeInsets.only(left: yAxisWidth),
            child: SizedBox(
              height: xAxisHeight,
              child: CustomPaint(
                size: Size(double.infinity, xAxisHeight),
                painter: _XAxisPainter(
                  hourLabels: hourLabels,
                  textColor: themeController.currentColor.sc4,
                  fontSize: 18.rpx,
                  startTime: widget.startTime,
                  endTime: widget.endTime,
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

class _DotBarChartPainter extends CustomPainter {
  final List<Map<String, dynamic>> data;
  final int yMax;
  final int threshold;
  final int yLabelsCount;
  final double yAxisTopPadding;
  final double horizontalPadding;
  final int? selectedIndex;

  _DotBarChartPainter({
    required this.data,
    required this.yMax,
    required this.threshold,
    required this.yLabelsCount,
    required this.yAxisTopPadding,
    required this.horizontalPadding,
    this.selectedIndex,
  });

  @override
  void paint(Canvas canvas, Size size) {
    final double chartWidth = size.width - 2 * horizontalPadding;
    final double xStep = data.length > 1 ? chartWidth / (data.length - 1) : 0;
    final double chartHeight = size.height;
    final double drawableHeight = chartHeight - yAxisTopPadding;

    final Paint thresholdPaint = Paint()
      ..style = PaintingStyle.stroke
      ..color = stringToColor("#FF7159")
      ..strokeWidth = 1.rpx;

    double thresholdY =
        yAxisTopPadding + drawableHeight * (1 - threshold / yMax);
    drawDashedLine(
      canvas,
      Offset(0, thresholdY),
      Offset(size.width, thresholdY),
      thresholdPaint,
      8.rpx,
      6.rpx,
    );

    final double dotRadius = 13.rpx;
    for (int i = 0; i < data.length; i++) {
      int times = data[i]['times'] ?? 0;
      double x = horizontalPadding + i * xStep;
      double y = yAxisTopPadding + drawableHeight * (1 - times / yMax);

      Paint dotPaint = Paint()
        ..style = PaintingStyle.fill
        ..color = times >= threshold
            ? stringToColor("#FF7159")
            : stringToColor("#00C1AA");

      // Draw a larger circle for selected dot
      if (i == selectedIndex) {
        Paint borderPaint = Paint()
          ..style = PaintingStyle.stroke
          ..color = Colors.white
          ..strokeWidth = 3.rpx;
        canvas.drawCircle(Offset(x, y), dotRadius + 1.rpx, borderPaint);
      }
      canvas.drawCircle(Offset(x, y), dotRadius, dotPaint);
    }

    final Paint solidLinePaint = Paint()
      ..color = Colors.grey.withOpacity(0.7)
      ..strokeWidth = 1.rpx
      ..style = PaintingStyle.stroke;

    final Paint dashedLinePaint = Paint()
      ..color = Colors.grey.withOpacity(0.4)
      ..strokeWidth = 1.rpx
      ..style = PaintingStyle.stroke;

    for (int i = 0; i < yLabelsCount; i++) {
      double y = yAxisTopPadding + i * (drawableHeight / (yLabelsCount - 1));
      if (i == yLabelsCount - 1) {
        canvas.drawLine(Offset(0, y), Offset(size.width, y), solidLinePaint);
      } else {
        drawDashedLine(
          canvas,
          Offset(0, y),
          Offset(size.width, y),
          dashedLinePaint,
          8.rpx,
          6.rpx,
        );
      }
    }
  }

  void drawDashedLine(
    Canvas canvas,
    Offset start,
    Offset end,
    Paint paint,
    double dashWidth,
    double gapWidth,
  ) {
    double dx = start.dx;
    final double y = start.dy;
    while (dx < end.dx) {
      final double nextDx = (dx + dashWidth).clamp(start.dx, end.dx);
      canvas.drawLine(Offset(dx, y), Offset(nextDx, y), paint);
      dx = nextDx + gapWidth;
    }
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
}

class _XAxisPainter extends CustomPainter {
  final List<Map<String, dynamic>> hourLabels;
  final Color textColor;
  final double fontSize;
  final int startTime;
  final int endTime;

  _XAxisPainter({
    required this.hourLabels,
    required this.textColor,
    required this.fontSize,
    required this.startTime,
    required this.endTime,
  });

  @override
  void paint(Canvas canvas, Size size) {
    final textStyle = TextStyle(
      color: textColor,
      fontSize: fontSize,
    );
    final textPainter = TextPainter(
      textDirection: ui.TextDirection.ltr,
      textAlign: TextAlign.center,
    );

    // Draw start time (leftmost)
    final startText = DateFormat('HH:mm')
        .format(DateTime.fromMillisecondsSinceEpoch(startTime));
    final startTextSpan = TextSpan(text: startText, style: textStyle);
    textPainter.text = startTextSpan;
    textPainter.layout();
    textPainter.paint(canvas, Offset(0, 14.rpx));

    // Draw end time (rightmost)
    final endText = DateFormat('HH:mm')
        .format(DateTime.fromMillisecondsSinceEpoch(endTime));
    final endTextSpan = TextSpan(text: endText, style: textStyle);
    textPainter.text = endTextSpan;
    textPainter.layout();
    textPainter.paint(canvas, Offset(size.width - textPainter.width, 14.rpx));

    // Draw hourly labels in between
    for (var label in hourLabels) {
      final position = label['position'] * size.width;
      final time = DateTime.fromMillisecondsSinceEpoch(label['time']);
      final hourText = DateFormat('h').format(time);
      final textSpan = TextSpan(text: hourText, style: textStyle);
      textPainter.text = textSpan;
      textPainter.layout();
      final offset = Offset(
        position - textPainter.width / 2,
        14.rpx, // Padding from bottom
      );
      textPainter.paint(canvas, offset);
    }
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
}
