import 'dart:math';

import 'package:flutter/material.dart';
import 'package:lightmeter/res/dimens.dart';

class TimerTimeline extends StatelessWidget {
  final double progress;
  final Widget child;

  const TimerTimeline({
    required this.progress,
    required this.child,
  }) : assert(progress >= 0 && progress <= 1);

  @override
  Widget build(BuildContext context) {
    return CustomPaint(
      painter: _TimelinePainter(
        backgroundColor: Theme.of(context).colorScheme.primaryContainer,
        progressColor: Theme.of(context).colorScheme.primary,
        progress: progress,
      ),
      willChange: true,
      child: Center(child: child),
    );
  }
}

class _TimelinePainter extends CustomPainter {
  final Color progressColor;
  final Color backgroundColor;
  final double progress;

  late final double timelineEdgeRadius = strokeWidth / 2;
  static const double radiansQuarterTurn = -pi / 2;
  static const double strokeWidth = Dimens.grid8;

  _TimelinePainter({
    required this.progressColor,
    required this.backgroundColor,
    required this.progress,
  });

  @override
  void paint(Canvas canvas, Size size) {
    late final double radiansProgress = 2 * pi * progress;
    final radius = size.height / 2;
    final timerCenter = Offset(radius, radius);

    final timelineSegmentPath = Path();
    if (progress == 1) {
      timelineSegmentPath.addOval(
        Rect.fromCenter(
          center: timerCenter,
          height: size.height,
          width: size.width,
        ),
      );
    } else {
      timelineSegmentPath
        ..arcTo(
          Rect.fromCenter(
            center: timerCenter,
            height: size.height,
            width: size.width,
          ),
          radiansQuarterTurn,
          radiansProgress,
          false,
        )
        ..lineTo(radius, radius)
        ..lineTo(radius, 0);
    }

    final timelinePath = Path.combine(
      PathOperation.difference,
      timelineSegmentPath,
      Path()
        ..addOval(
          Rect.fromCircle(
            center: timerCenter,
            radius: radius - strokeWidth,
          ),
        ),
    );

    final smoothEdgesPath = Path.combine(
      PathOperation.union,
      Path()
        ..addOval(
          Rect.fromCircle(
            center: Offset(radius, timelineEdgeRadius),
            radius: timelineEdgeRadius,
          ),
        ),
      Path()
        ..addOval(
          Rect.fromCircle(
            center: Offset(
              (radius - timelineEdgeRadius) * cos(radiansProgress + radiansQuarterTurn) + radius,
              (radius - timelineEdgeRadius) * sin(radiansProgress + radiansQuarterTurn) + radius,
            ),
            radius: timelineEdgeRadius,
          ),
        ),
    );

    canvas.drawPath(
      Path.combine(
        PathOperation.difference,
        Path()
          ..addOval(
            Rect.fromCircle(
              center: timerCenter,
              radius: radius,
            ),
          ),
        Path()
          ..addOval(
            Rect.fromCircle(
              center: timerCenter,
              radius: radius - strokeWidth,
            ),
          ),
      ),
      Paint()..color = backgroundColor,
    );

    canvas.drawPath(
      timelinePath,
      Paint()..color = progressColor,
    );

    canvas.drawPath(
      smoothEdgesPath,
      Paint()..color = progressColor,
    );
  }

  @override
  bool shouldRepaint(_TimelinePainter oldDelegate) => oldDelegate.progress != progress;
}