import 'dart:math';

import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';

/// Spherical water wave progress bar with animated ripple effect
/// Based on https://github.com/meeziest/spherical_water_wavy_progress_bar
///
/// Usage:
/// WaterWaveProgress(
///   progress: 75.0,
///   size: 200.w,
///   showPercentage: true,
/// )
class WaterWaveProgress extends StatefulWidget {
  final double progress; // 0.0 to 100.0
  final double size;
  final bool showPercentage;
  final bool useCircleClip;
  final Color? waveColor;
  final Color? backgroundColor;
  final Color? progressColor;
  final Color? textColor;
  final Duration? waveDuration;

  // When drawing inside a non-square clip (like bottle area), provide the actual available
  // width and height so the painter can compute vertical fill correctly.
  final double? containerWidth;
  final double? containerHeight;

  const WaterWaveProgress({
    super.key,
    required this.progress,
    this.size = 200,
    this.showPercentage = true,
    this.useCircleClip = true,
    this.waveColor,
    this.backgroundColor,
    this.progressColor,
    this.textColor,
    this.waveDuration,
    this.containerWidth,
    this.containerHeight,
  });

  @override
  State<WaterWaveProgress> createState() => _WaterWaveProgressState();
}

class _WaterWaveProgressState extends State<WaterWaveProgress> with SingleTickerProviderStateMixin {
  late AnimationController _waveController;

  @override
  void initState() {
    super.initState();
    _waveController = AnimationController(
      vsync: this,
      duration: widget.waveDuration ?? const Duration(milliseconds: 2000),
    )..repeat();
  }

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

  @override
  Widget build(BuildContext context) {
    final radius = widget.size / 2;

    // When container dimensions are provided (non-square bottle area), use them so
    // the CustomPaint canvas matches the available clip rect. Otherwise fall back
    // to the square size value.
    final paintWidth = widget.containerWidth ?? widget.size;
    final paintHeight = widget.containerHeight ?? widget.size;

    return SizedBox(
      width: paintWidth,
      height: paintHeight,
      child: CustomPaint(
        painter: _WavePainter(
          progress: widget.progress,
          waveAnimation: _waveController,
          // For circle-based painters we still provide circleRadius; when using
          // rectangular painting the circleRadius is unused.
          circleRadius: radius,
          waveColor: widget.waveColor ?? AppColors.primaryRedColor,
          backgroundColor: widget.backgroundColor ?? AppColors.bgScaffoldColor,
          useCircleClip: widget.useCircleClip,
          containerWidth: widget.containerWidth,
          containerHeight: widget.containerHeight,
        ),
        // Only draw the circular progress/percentage when explicitly requested.
        foregroundPainter: widget.showPercentage
            ? _ProgressPainter(
                progress: widget.progress,
                circleRadius: radius,
                progressColor: widget.progressColor ?? AppColors.primaryRedColor,
                textColor: widget.textColor ?? AppColors.textColor,
                showPercentage: widget.showPercentage,
              )
            : null,
      ),
    );
  }
}

/// Paints the animated water waves inside a circular clip
class _WavePainter extends CustomPainter {
  final double progress;
  final Animation<double> waveAnimation;
  final double circleRadius;
  final Color waveColor;
  final Color backgroundColor;
  final bool useCircleClip;
  final double? containerWidth;
  final double? containerHeight;

  _WavePainter({
    required this.progress,
    required this.waveAnimation,
    required this.circleRadius,
    required this.waveColor,
    required this.backgroundColor,
    this.useCircleClip = true,
    this.containerWidth,
    this.containerHeight,
  }) : super(repaint: waveAnimation);

  @override
  void paint(Canvas canvas, Size size) {
    final center = Offset(size.width / 2, size.height / 2);
    canvas.translate(center.dx, center.dy);

    if (useCircleClip) {
      // Clip to circle
      canvas.clipPath(
        Path()
          ..addOval(
            Rect.fromCircle(
              center: Offset.zero,
              radius: circleRadius,
            ),
          ),
      );

      // Fill background circle if specified
      if (backgroundColor != Colors.transparent) {
        canvas.drawCircle(
          Offset.zero,
          circleRadius,
          Paint()..color = backgroundColor,
        );
      }

      // Draw two sine waves clipped to circle for spherical style
      _drawSineWave(canvas, waveColor.withAlpha((0.5 * 255).round()), shift: 0);
      _drawSineWave(canvas, waveColor, shift: circleRadius / 2, mirror: true);
    } else {
      // No circular clipping: draw waves over the full rectangular area. Use provided container
      // dimensions if available; otherwise fall back to square bounds derived from circleRadius.
      final w = containerWidth ?? (circleRadius * 2);
      final h = containerHeight ?? (circleRadius * 2);

      // use local transforms to center at origin and compute waves relative to the provided rect
      canvas.save();
      canvas.translate(-w / 2, -h / 2); // move origin to top-left of the rect

      _drawSineWaveRect(canvas, waveColor.withAlpha((0.5 * 255).round()), width: w, height: h, shift: 0);
      _drawSineWaveRect(canvas, waveColor, width: w, height: h, shift: w / 4, mirror: true);

      canvas.restore();
    }
  }

  void _drawSineWaveRect(Canvas canvas, Color color, {required double width, required double height, double shift = 0.0, bool mirror = false}) {
    if (mirror) {
      canvas.save();
      canvas.translate(width, 0);
      canvas.scale(-1, 1);
    }

    final amplitude = height * 0.04; // smaller amplitude for rectangular waves
    final angularVelocity = pi / (width / 2);
    final delta = Curves.easeInOut.transform(progress / 100);

    final offsetX = 2 * width * waveAnimation.value + shift;
    final offsetY = height * (1.0 - delta);

    final path = Path();
    for (double x = 0; x <= width; x += 1) {
      final y = amplitude * sin(angularVelocity * (x + offsetX));
      if (x == 0) {
        path.moveTo(x, y + offsetY);
      } else {
        path.lineTo(x, y + offsetY);
      }
    }

    path.lineTo(width, height);
    path.lineTo(0, height);
    path.close();

    final wavePaint = Paint()
      ..color = color
      ..style = PaintingStyle.fill
      ..isAntiAlias = true;

    canvas.drawPath(path, wavePaint);

    if (mirror) canvas.restore();
  }

  void _drawSineWave(Canvas canvas, Color color, {double shift = 0.0, bool mirror = false}) {
    if (mirror) {
      canvas.save();
      canvas.transform(Matrix4.rotationY(pi).storage);
    }

    // original circular/spherical style: compute bounds based on circleRadius
    final startX = -circleRadius;
    final endX = circleRadius;
    final startY = circleRadius;
    final endY = -circleRadius;

    final amplitude = circleRadius * 0.15;
    final angularVelocity = pi / circleRadius;
    final delta = Curves.easeInOut.transform(progress / 100);

    final offsetX = 2 * circleRadius * waveAnimation.value + shift;
    final offsetY = startY + (endY - startY - amplitude) * delta;

    final wavePaint = Paint()
      ..color = color
      ..style = PaintingStyle.fill
      ..isAntiAlias = true;

    final path = Path();

    for (double x = startX; x <= endX; x++) {
      // Sine wave function:  y = A * sin(ωx + φ)
      final y = amplitude * sin(angularVelocity * (x + offsetX));
      if (x == startX) {
        path.moveTo(x, y + offsetY);
      } else {
        path.lineTo(x, y + offsetY);
      }
    }

    path.lineTo(endX, startY);
    path.lineTo(startX, startY);
    path.close();

    canvas.drawPath(path, wavePaint);

    if (mirror) canvas.restore();
  }

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

/// Paints the circular progress arc and percentage text
class _ProgressPainter extends CustomPainter {
  final double progress;
  final double circleRadius;
  final Color progressColor;
  final Color textColor;
  final bool showPercentage;

  _ProgressPainter({
    required this.progress,
    required this.circleRadius,
    required this.progressColor,
    required this.textColor,
    required this.showPercentage,
  });

  @override
  void paint(Canvas canvas, Size size) {
    final center = Offset(size.width / 2, size.height / 2);
    canvas.translate(center.dx, center.dy);

    _drawCircleProgress(canvas);
    if (showPercentage) {
      _drawProgressText(canvas);
    }
  }

  void _drawCircleProgress(Canvas canvas) {
    final strokeWidth = circleRadius * 0.077;

    // Background circle with shadow
    final bgPaint = Paint()
      ..color = progressColor.withAlpha((0.2 * 255).round())
      ..strokeWidth = strokeWidth
      ..style = PaintingStyle.stroke
      ..isAntiAlias = true;

    final shadowPaint = Paint()
      ..color = Colors.black.withAlpha((0.1 * 255).round())
      ..strokeWidth = strokeWidth
      ..style = PaintingStyle.stroke
      ..maskFilter = const MaskFilter.blur(BlurStyle.outer, 10);

    canvas.drawCircle(Offset.zero, circleRadius, bgPaint);
    canvas.drawCircle(Offset.zero, circleRadius, shadowPaint);

    // Progress arc
    final progressPaint = Paint()
      ..color = progressColor
      ..strokeWidth = strokeWidth
      ..strokeCap = StrokeCap.round
      ..style = PaintingStyle.stroke
      ..isAntiAlias = true;

    canvas.drawArc(
      Rect.fromCircle(center: Offset.zero, radius: circleRadius),
      -0.5 * pi,
      2 * pi * (progress / 100),
      false,
      progressPaint,
    );
  }

  void _drawProgressText(Canvas canvas) {
    final textSpan = TextSpan(
      text: "${progress.toInt()}%",
      style: TextStyle(
        color: textColor,
        fontSize: circleRadius * 0.35,
        fontWeight: FontWeight.w700,
        height: 1.0,
      ),
    );

    final textPainter = TextPainter(
      text: textSpan,
      textDirection: TextDirection.ltr,
    )..layout();

    textPainter.paint(
      canvas,
      Offset(-textPainter.width / 2, -textPainter.height / 2),
    );
  }

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