import 'dart:collection';
import 'dart:io';
import 'dart:math';

import 'package:flame/components.dart';
import 'package:flame/game.dart';
import 'package:flame/text.dart';
import 'package:flutter/material.dart';

import '../../../data/models/ember.dart';
import 'benchmark_world.dart';

class SpriteBenchmark extends FlameGame with HasGameRef {
  static const description = '''
See how many SpriteAnimationComponent's your platform can handle before it
starts to drop in FPS, this is without any sprite batching and such.
  ''';

  SpriteBenchmark() : super(world: BenchmarkWorld());

  // 30 minutes countdown
  final countdown = Timer(1800);

  final emberSize = Vector2.all(20);
  late final TextComponent emberCounter;
  final counterPrefix = 'Animations: ';
  double posX = 0;
  double posY = 0;

  final Queue<double> window = Queue();

  @override
  Color backgroundColor() => Colors.black;

  double _sum = 0;
  int spriteCount = 0;

  final int windowSize = 60;

  TextPaint textPaint = TextPaint(
    style: TextStyle(
      fontSize: 20.0,
      fontFamily: 'Awesome Font',
      background: Paint()
        ..color = Colors.indigo
        ..strokeJoin = StrokeJoin.round
        ..strokeCap = StrokeCap.round
        ..style = PaintingStyle.stroke
        ..strokeWidth = 25.0,
    ),
  );

  @override
  Future<void> onLoad() async {
    await camera.viewport.addAll([
      FpsTextComponent(
        position: size - Vector2(20, 80),
        anchor: Anchor.bottomRight,
        textRenderer: textPaint,
      ),
      emberCounter = TextComponent(
        position: size - Vector2(20, 25),
        anchor: Anchor.bottomRight,
        priority: 1,
        textRenderer: textPaint,
      ),
    ]);
    // world.add(Ember(size: emberSize));
    children.register<Ember>();
  }

  double get fps {
    return window.isEmpty ? 0 : window.length / _sum;
  }

  @override
  void update(double dt) async {
    // add text to the screen only once
    if (countdown.finished) {
      showDialog(
        context: gameRef.buildContext!,
        builder: (context) {
          return AlertDialog(
            title: const Text('Benchmark finished'),
            content: Text(
              'After 30 minutes, the benchmark finished with $spriteCount sprite animations.',
            ),
            actions: [
              TextButton(
                onPressed: () {
                  Navigator.of(context).pop();
                  Navigator.of(context).pop();
                },
                child: const Text('Close'),
              ),
            ],
          );
        },
      );
      countdown.reset();
    }
    if (!countdown.finished && countdown.isRunning()) {
      countdown.update(dt);

      window.addLast(dt);
      _sum += dt;
      if (window.length > windowSize) {
        _sum -= window.removeFirst();
      }
      if (fps > 59) {
        if (posY > size.y) {
          final Random random = Random();
          add(
            Ember(
              size: emberSize,
              position: Vector2(
                (size.x) * random.nextDouble() * (random.nextBool() ? 1 : -1),
                (size.y) * random.nextDouble() * (random.nextBool() ? 1 : -1),
              ),
            ),
          );
          sleep(const Duration(milliseconds: 50));
        } else {
          for (int i = 0; i < 1; i++) {
            add(Ember(
              size: emberSize,
              position: Vector2(10 + posX, 10 + posY),
            ));
            if (posX < size.x) {
              posX += 20;
            } else {
              posY += 20;
              posX = 0;
            }
          }
          sleep(const Duration(milliseconds: 50));
        }
        spriteCount += 1;
      }
      super.update(dt);
      emberCounter.text = '$counterPrefix $spriteCount';
    }
  }
}
