import 'dart:math' as math;

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

class PieChartPainter extends CustomPainter {
  List<Paint> _paintList = [];
  List<double> _subParts;
  List<String> _subTitles;
  double _total = 0;
  double _totalAngle = math.pi * 2;

  final TextStyle chartValueStyle;
  final Color chartValueBackgroundColor;
  final double initialAngle;
  final bool showValuesInPercentage;
  final bool showChartValues;
  final bool showChartValuesOutside;
  final int decimalPlaces;
  final bool showChartValueLabel;
  final ChartType chartType;
  final Function formatChartValues;
  final double strokeWidth;
  final bool selected;
  final List<Color> colorList;
  double _prevAngle = 0;
  final TextStyle sideTextStyle;

  PieChartPainter(
    double angleFactor,
    this.showChartValues,
    this.showChartValuesOutside,
    this.colorList, {
    this.chartValueStyle,
    this.chartValueBackgroundColor,
    List<double> values,
    List<String> titles,
    this.initialAngle,
    this.showValuesInPercentage,
    this.decimalPlaces,
    this.showChartValueLabel,
    this.chartType,
    this.formatChartValues,
    this.strokeWidth,
    this.selected = false,
    this.sideTextStyle,
  }) {
    for (int i = 0; i < values.length; i++) {
      final paint = Paint()..color = getColor(colorList, i);
      if (chartType == ChartType.ring) {
        paint.style = PaintingStyle.stroke;
        paint.strokeWidth = strokeWidth;
      }

      _paintList.add(paint);
    }
    _totalAngle = angleFactor * math.pi * 2;
    _subParts = values;
    _subTitles = titles;
    _total = values.fold(0, (v1, v2) => v1 + v2);
  }

  @override
  void paint(Canvas canvas, Size size) {
    final side = size.width < size.height ? size.width : size.height;
    _prevAngle = initialAngle * math.pi / 180;
    for (int i = 0; i < _subParts.length; i++) {
      canvas.drawArc(
        Rect.fromLTWH(0.0, 0.0, side, size.height),
        _prevAngle,
        (((_totalAngle) / _total) * _subParts[i]),
        chartType == ChartType.disc ? true : false,
        _paintList[i],
      );
      final radius = showChartValuesOutside ? (side / 2) + 16 : side / 3;
      final x = (radius) * math.cos(_prevAngle + ((((_totalAngle) / _total) * _subParts[i]) / 2));
      final y = (radius) * math.sin(_prevAngle + ((((_totalAngle) / _total) * _subParts[i]) / 2));
      if (_subParts.elementAt(i).toInt() != 0) {
        final value = formatChartValues != null ? formatChartValues(_subParts.elementAt(i)) : _subParts.elementAt(i).toStringAsFixed(this.decimalPlaces);

//        final name = showValuesInPercentage
//            ? (((_subParts.elementAt(i) / _total) * 100)
//                    .toStringAsFixed(this.decimalPlaces) +
//                '%')
//            : value;
//         final name = showValuesInPercentage ? (((_subParts.elementAt(i) / _total) * 100).toStringAsFixed(this.decimalPlaces) + '%') : _subTitles.elementAt(i);

        if (showChartValues) {
          final name = "${_subTitles[i]}  " + (showValuesInPercentage ? (((_subParts.elementAt(i) / _total) * 100).toStringAsFixed(this.decimalPlaces) + '%') : value);
          var yLabel = y > size.width ? y + 40 : y + 10;
          var xLabel = (y > size.width ? x - y : x * 1.6) - 15;
          var yPopup = y - 8;
          if (_subParts[i] <= (_total / _subParts.length)) {
            yLabel = y + 8;
            xLabel *= 1.1;
            yPopup *= 1.25;
          }

          if (selected) _drawLabel(canvas, name, x, yPopup, side, true, statusColor: getColor(colorList, i));
          _drawLabel(canvas, _subTitles[i], xLabel, yLabel, side + 8, false);
        }
      }
      _prevAngle = _prevAngle + (((_totalAngle) / _total) * _subParts[i]);
    }
  }

  void _drawLabel(Canvas canvas, String name, double x, double y, double side, bool withBackground, {Color statusColor = Colors.white}) {
    TextSpan span = TextSpan(
      style: withBackground ? chartValueStyle : sideTextStyle,
      text: name,
    );
    TextPainter tp = TextPainter(
      text: span,
      textAlign: TextAlign.center,
      textDirection: TextDirection.ltr,
    );
    tp.layout();

    if (withBackground && showChartValueLabel) {
      //Draw text background box
      final rect = Rect.fromCenter(
        center: Offset((side / 2 + (x + 16)), (side / 2 + y)),
        width: tp.width + 45,
        height: tp.height + 16,
      );
      final rect2 = Rect.fromCenter(
        center: Offset(
          (side / 2 + x) - ((tp.width - 16) / 2),
          (side / 2 + y) - ((tp.height - 16) / 2),
        ),
        width: 12,
        height: 12,
      );
      final rRect = RRect.fromRectAndRadius(rect, const Radius.circular(8));
      final rRect2 = RRect.fromRectAndRadius(rect2, const Radius.circular(1));
      final paint = Paint()
        ..color = chartValueBackgroundColor ?? Colors.grey[200]
        ..style = PaintingStyle.fill;
      canvas.drawRRect(rRect, paint);
      canvas.drawRRect(rRect2, paint..color = statusColor);
    }
    //Finally paint the text above box
    tp.paint(
      canvas,
      Offset(
        (side / 2 + x) - ((tp.width - 50) / 2),
        (side / 2 + y) - ((tp.height) / 2),
      ),
    );
  }

  @override
  bool shouldRepaint(PieChartPainter oldDelegate) => selected != oldDelegate.selected;
}
