import 'package:ecosim/src/common/models/pvector.dart';
import 'package:ecosim/src/ecosim/models/boid.dart';
import 'package:ecosim/src/ecosim/models/boid_base.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'dart:math' as math;

import '../ecosim/models/food.dart';
import '../seeking/models/pointer_indicator.dart';
import '../ecosim/models/poison.dart';

class BenchmarkSimulation extends ChangeNotifier {
  final TickerProvider vsync;
  late Ticker _ticker;
  BuildContext context;
  final List<Boid> boids = [];
  PointerIndicator pointerIndicator = PointerIndicator(
    position: PVector(
      0.0,
      0.0,
    ),
  );
  List<Food> foods = [];
  List<Poison> poison = [];

  // simulation params
  final int startBoidsCount;
  final int startFoodCount;
  final int startPoisonCount;
  final List<num>? presetDna;

  BenchmarkSimulation(
    this.vsync,
    this.context, {
    required this.startBoidsCount,
    required this.startFoodCount,
    required this.startPoisonCount,
    this.presetDna,
  }) {
    _ticker = vsync.createTicker(_onEachTick)..start();
    final rng = math.Random();
    // final screenSize = MediaQuery.of(context).scale().size;
    const screenSize = Size(1000, 1000);

    for (var i = 0; i < startBoidsCount; i++) {
      double x = rng.nextDouble() * screenSize.width;
      double y = rng.nextDouble() * screenSize.height;
      boids.add(
        Boid(
          position: PVector(x, y),
          velocity: PVector(0, -2),
          tickDamage: 0,
          health: 100,
          maxHealth: 100,
          replicationProbability: 0,
          birthTimestamp: 0,
          dna: BoidBaseDna.rand(mutationThreshold: 1),
          healthyColor: Colors.white,
          unhealthyColor: Colors.red,
          mutationThreshold: 1,
        ),
      );
    }
    for (var i = 0; i < startFoodCount; i++) {
      double x = rng.nextDouble() * screenSize.width;
      double y = rng.nextDouble() * screenSize.height;
      // print('ADD FOOD: $x, $y');
      foods.add(Food(
        position: PVector(x, y),
        nutrition: 1,
        foodDecayRate: 0,
        startNutrition: 1,
      ));
    }
    for (var i = 0; i < startPoisonCount; i++) {
      double x = rng.nextDouble() * screenSize.width;
      double y = rng.nextDouble() * screenSize.height;
      // print('ADD FOOD: $x, $y');
      poison.add(
        Poison(
          position: PVector(x, y),
          damage: 1,
          poisonDecayRate: 0,
          startDamage: 1,
        ),
      );
    }
  }

  void _onEachTick(Duration deltaTime) {
    final rng = math.Random();
    const screenSize = Size(1000, 1000);
    double x = rng.nextDouble() * screenSize.width;
    double y = rng.nextDouble() * screenSize.height;
    foods.add(
      Food(
        position: PVector(x, y),
        nutrition: 1,
        foodDecayRate: 0,
        startNutrition: 1,
      ),
    );

    for (var i = boids.length - 1; i >= 0; i--) {
      const screenSize = Size(1000, 1000);
      boids[i].update();
      boids[i].updateBoidDirection([foods], screenSize);
      boids[i].boundaryBoidsDirectionUpdate(screenSize);
      boids[i].updateBoidTransform();
      boids[i].boundaryBoidsDirectionUpdate(screenSize);
    }

    notifyListeners();
  }

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