import 'dart:async';

import 'package:ecosim/src/ecosim/ecosystem_visualizer.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

import 'ecosystem_sim.dart';
import 'utils.dart';

final showDebugInfosProvider = StateProvider<bool>((ref) {
  return false;
});

// Ecosystem Simulation Screen
// This Screen only initializes the simulation
// with the users parameters
// It then launches the stateless EcosystemSimulationVisualizer
class EcosystemSimulationScreen extends ConsumerStatefulWidget {
  const EcosystemSimulationScreen({
    super.key,
    required this.boidStartCount,
    required this.worldFoodNutrition,
    required this.worldPoisonDamage,
    required this.boidHealthyColor,
    required this.boidUnhealthyColor,
    required this.predatorStartCount,
    required this.predatorBoidNutrition,
    required this.predatorHealthyColor,
    required this.predatorUnhealthyColor,
    required this.worldReplicationRadiusFood,
    required this.worldReplicationRadiusPoison,
    required this.worldReplicationRadiusCooldown,
    required this.worldFoodDecayRate,
    required this.worldPoisonDecayRate,
    required this.worldWidth,
    required this.worldHeight,
    required this.worldFoodStartCount,
    required this.worldPoisonStartCount,
    required this.boidTickDamage,
    required this.boidReplicateInterval,
    required this.boidReplicateProbability,
    required this.boidMutationThreshold,
    required this.boidCollisionRadius,
    required this.boidMaxHealth,
    required this.predatorCollisionRadius,
  });

  // boid configuration
  final int boidStartCount;
  final Color boidHealthyColor;
  final Color boidUnhealthyColor;
  final double boidTickDamage;
  final double boidReplicateInterval;
  final double boidReplicateProbability;
  final double boidMutationThreshold;
  final double boidCollisionRadius;
  final double boidMaxHealth;

  // predator configuration
  final int predatorStartCount;
  final double predatorBoidNutrition;
  final double predatorCollisionRadius;
  final Color predatorHealthyColor;
  final Color predatorUnhealthyColor;

  // world configuration
  final double worldFoodNutrition;
  final double worldPoisonDamage;
  final double worldReplicationRadiusFood;
  final double worldReplicationRadiusPoison;
  final double worldReplicationRadiusCooldown;
  final double worldFoodDecayRate;
  final double worldPoisonDecayRate;

  // more world configuration
  final double worldWidth;
  final double worldHeight;
  final int worldFoodStartCount;
  final int worldPoisonStartCount;

  @override
  ConsumerState<EcosystemSimulationScreen> createState() =>
      _EcosystemSimulationScreenState();
}

class _EcosystemSimulationScreenState
    extends ConsumerState<EcosystemSimulationScreen>
    with SingleTickerProviderStateMixin {
  double pointerx = 0.0;
  double pointery = 0.0;
  // double get currentTime =>
  //     DateTime.now().difference(_initialTime).inMilliseconds / 1000.0;

  bool _onKey(KeyEvent event) {
    final key = event.logicalKey.keyLabel;

    if (event is KeyDownEvent && key == "Tab") {
      ref.read(showDebugInfosProvider.notifier).state =
          !ref.read(showDebugInfosProvider);
    } else if (event is KeyRepeatEvent) {
      return false;
    }

    return false;
  }

  late Timer worldTickTimer;
  late Timer worldReplicateBoidsTimer;
  late Timer worldReplicateConsumablesTimer;
  late EcosystemSimulation simulation;

  Future<EcosystemSimulation> initializeSimulation() async {
    setState(() {
      simulation = EcosystemSimulation(
        vsync: this,
        context: context,
        worldPoisonDamage: widget.worldPoisonDamage,
        boidStartCount: widget.boidStartCount,
        predatorStartCount: widget.predatorStartCount,
        worldFoodStartCount: widget.worldFoodStartCount,
        worldPoisonStartCount: widget.worldPoisonStartCount,
        screenSize: Size(widget.worldWidth, widget.worldHeight),
        predatorBoidNutrition: widget.predatorBoidNutrition,
        predatorCollisionRadius: widget.predatorCollisionRadius,
        predatorHealthyColor: widget.predatorHealthyColor,
        predatorUnhealthyColor: widget.predatorUnhealthyColor,
        worldReplicationRadiusFood: widget.worldReplicationRadiusFood,
        worldReplicationRadiusPoison: widget.worldReplicationRadiusPoison,
        worldReplicationRadiusCooldown: widget.worldReplicationRadiusCooldown,
        worldFoodDecayRate: widget.worldFoodDecayRate,
        worldPoisonDecayRate: widget.worldPoisonDecayRate,
        boidHealthyColor: widget.boidHealthyColor,
        boidUnhealthyColor: widget.boidUnhealthyColor,
        boidTickDamage: widget.boidTickDamage,
        boidReplicateInterval: widget.boidReplicateInterval,
        boidReplicateProbability: widget.boidReplicateProbability,
        boidMutationThreshold: widget.boidMutationThreshold,
        boidCollisionRadius: widget.boidCollisionRadius,
        worldFoodNutrition: widget.worldFoodNutrition,
        boidMaxHealth: widget.boidMaxHealth,
      );
    });
    return simulation;
  }

  @override
  void initState() {
    super.initState();
    ServicesBinding.instance.keyboard.addHandler(_onKey);
  }

  @override
  void dispose() {
    worldTickTimer.cancel();
    worldReplicateBoidsTimer.cancel();
    worldReplicateConsumablesTimer.cancel();
    simulation.dispose();
    ServicesBinding.instance.keyboard.removeHandler(_onKey);
    super.dispose();
  }

  void pointerUpdate(details) {
    pointerx = details.globalPosition.dx;
    pointery = details.globalPosition.dy;
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
      future: initializeSimulation(),
      builder: (context, snapshot) {
        if (snapshot.hasData) {
          // timer for the world ticker, always one second
          worldTickTimer = Timer.periodic(
            const Duration(
              seconds: 1,
            ),
            (_) {
              simulation.worldTick();
            },
          );
          // timer for the boid population interval
          // and the boid replication
          final boidReplicationInterval = getTimerMillisecondsFromSeconds(
            interval: widget.boidReplicateInterval,
          );
          debugPrint('Boid Replication Interval: $boidReplicationInterval');
          worldReplicateBoidsTimer = Timer.periodic(
            Duration(milliseconds: boidReplicationInterval),
            (_) {
              debugPrint('BOID REPLICATION TICK');
              simulation.populateBoidsTick();
              simulation.replicateBoidsTick();
            },
          );
          // Timer for the consumables replication
          final worldReplicationRadiusCooldown =
              getTimerMillisecondsFromSeconds(
            interval: widget.worldReplicationRadiusCooldown,
          );
          debugPrint(
              'Consumables Replication Interval: $worldReplicationRadiusCooldown');
          worldReplicateConsumablesTimer = Timer.periodic(
            Duration(milliseconds: worldReplicationRadiusCooldown),
            (_) {
              debugPrint("CONSUMABLES REPLICATION TICK");
              simulation.replicateConsumablesTick();
            },
          );
          return GestureDetector(
            onLongPress: () {
              ref.read(showDebugInfosProvider.notifier).state =
                  !ref.read(showDebugInfosProvider);
            },
            child: EcosystemSimulationVisualizer(
              simulation: simulation,
              worldTickTimer: worldTickTimer,
              worldReplicateBoidsTimer: worldReplicateBoidsTimer,
              worldReplicateConsumablesTimer: worldReplicateConsumablesTimer,
            ),
          );
        } else {
          return const Center(
            child: CircularProgressIndicator(),
          );
        }
      },
    );
  }
}
