import 'dart:math';

import 'package:flutter/material.dart';

class ShiningStars extends StatefulWidget {
  final int count; // 星星个数
  final double size; // 星星尺寸
  final int duration; // 动画时长, ms

  const ShiningStars({super.key, this.count = 20, this.size = 100, this.duration = 1200});
  @override
  State<StatefulWidget> createState() => _ShiningStarsState();
}

class _ShiningStarsState extends State<ShiningStars> with SingleTickerProviderStateMixin {
  late AnimationController controller;
  Stars? stars;

  @override
  void initState() {
    controller = AnimationController(
      vsync: this,
      value: 0,
      duration: Duration(milliseconds: widget.duration),
    )..forward();
    super.initState();
  }

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

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      width: double.infinity,
      height: double.infinity,
      child: LayoutBuilder(
        builder: (context, constraints) {
          final Size biggest = constraints.biggest;
          stars = Stars(canvasSize: biggest, starSize: widget.size, count: widget.count);
          return CustomPaint(painter: StarPainter(controller, stars!));
        },
      ),
    );
  }
}

class StarPainter extends CustomPainter {
  final AnimationController controller;
  final Stars stars;

  StarPainter(this.controller, this.stars) : super(repaint: controller);

  @override
  void paint(Canvas canvas, Size size) {
    if (!controller.isAnimating) return;
    stars.update(controller.value);
    stars.draw(canvas);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return false;
  }
}

class Stars {
  final int count; // 星星数量
  final double starSize; // 星星尺寸大小
  final Size canvasSize; // 画布尺寸

  final List<StarParticle> particles = [];

  Stars({required this.canvasSize, this.starSize = 100, this.count = 10}) {
    final list = List.generate(count, (index) => StarParticle(canvasSize: canvasSize, starSize: starSize));

    particles.addAll(list);
  }

  update(double t) {
    for (var p in particles) {
      p.update(t);
    }
  }

  draw(canvas) {
    for (var p in particles) {
      p.draw(canvas);
    }
  }
}

class StarParticle {
  final double starSize; //星星尺寸大小
  final Size canvasSize; // 画布尺寸
  final Path path;
  final Color color;

  late Offset startPos; // 起点
  late Offset endPos; // 终点
  Offset translate; // 当前位置（根据 animation.value 动态计算）
  double scale; // 当前缩放系数（根据 animation.value 动态计算）
  double angle; // 当前旋转角度（根据 animation.value 动态计算）
  late int rotateDirection; // 旋转方向

  StarParticle({required this.canvasSize, this.starSize = 100, this.color = const Color.fromARGB(255, 242, 207, 31)})
    : path = Path(),
      translate = Offset.zero,
      scale = 1.0,
      angle = 0 {
    Offset center = canvasSize.center(Offset.zero);

    Random random = Random();

    // startPos 限定在中心 100x100 的矩形内
    startPos = Offset(center.dx + randomDoubleInRange(-100, 100), center.dy + randomDoubleInRange(-50, 50));

    // endPos 完全随机
    endPos = Offset(
      center.dx + randomDoubleInRange(-canvasSize.width / 2, canvasSize.width / 2),
      center.dy + randomDoubleInRange(-canvasSize.height / 2, canvasSize.height / 2),
    );

    // endPos 固定在边界
    // int rand = random.nextInt(4);
    // if (rand == 0) {
    //   endPos = Offset(0.0, random.nextDouble() * canvasSize.height);
    // } else if (rand == 1) {
    //   endPos = Offset(canvasSize.width, random.nextDouble() * canvasSize.height);
    // } else if (rand == 2) {
    //   endPos = Offset(random.nextDouble() * canvasSize.width, 0.0);
    // } else if (rand == 3) {
    //   endPos = Offset(random.nextDouble() * canvasSize.width, canvasSize.height);
    // }
    path
      ..moveTo(startPos.dx, startPos.dy - starSize * 0.8 / 2)
      ..quadraticBezierTo(startPos.dx, startPos.dy, startPos.dx + starSize * 0.75 / 2, startPos.dy)
      ..quadraticBezierTo(startPos.dx, startPos.dy, startPos.dx, startPos.dy + starSize * 0.75 / 2)
      ..quadraticBezierTo(startPos.dx, startPos.dy, startPos.dx - starSize * 0.75 / 2, startPos.dy)
      ..quadraticBezierTo(startPos.dx, startPos.dy, startPos.dx, startPos.dy - starSize * 0.75 / 2);

    rotateDirection = random.nextBool() ? 1 : -1;
  }

  double randomDoubleInRange(double min, double max) {
    final random = Random();
    final range = max - min;
    final randomValue = random.nextDouble() * range + min;
    return randomValue;
  }

  update(double t) {
    scale = Curves.easeOut.transform(1 - t);
    angle = t * pi * rotateDirection / 4;
    translate = Tween(begin: Offset.zero, end: endPos - startPos).transform(t);
  }

  draw(Canvas canvas) {
    canvas.save();

    Matrix4 m = Matrix4.identity()
      ..translate(startPos.dx, startPos.dy)
      ..translate(translate.dx, translate.dy)
      ..scale(scale)
      ..rotateZ(angle)
      ..translate(-startPos.dx, -startPos.dy);

    canvas.transform(m.storage);

    // 绘制光晕
    Paint paint = Paint()
      ..color = color
      ..style = PaintingStyle.fill
      ..shader = shader
      ..maskFilter = MaskFilter.blur(BlurStyle.normal, starSize / 6);

    canvas.drawCircle(startPos, starSize / 2, paint);

    // 绘制四角星
    paint.shader = null;
    paint.maskFilter = null;
    canvas.drawPath(path, paint);

    canvas.restore();
  }

  RadialGradient get gradient =>
      RadialGradient(center: Alignment.center, colors: <Color>[color.withOpacity(0.5), color.withOpacity(0.2)], stops: const <double>[0.2, 1.0]);

  Shader get shader => gradient.createShader(Rect.fromCircle(center: startPos, radius: starSize / 2));
}
