using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Godot;
using Godot.Collections;

namespace KarrotStarterTemplate.Common.StateMachines;

public abstract partial class State : Node
{
	[Export] public string id { get; private set; }
	// [Export] public bool queueable { get; private set; }
	[Export] public bool canTransitionToSelf { get; private set; }
	[Export] public float minimumStateDuration { get; private set; }

	public bool checkRelevance { get; protected set; } = true;
	public bool queueRelevance { get; protected set; } = true;
	
	protected List<string> statesInQueue = new();
	
	private double _startTime;
	protected float timeElapsed => (float)(Time.GetUnixTimeFromSystem() - _startTime);
	
	protected StateMachine parentStateMachine;
	public StateInputsPackage package => parentStateMachine.package;
	public bool isActive => parentStateMachine?.currentState == this;
	public bool isTransitioning => parentStateMachine?.currentState == this && parentStateMachine.isTransitioning;
	// Called when the node enters the scene tree for the first time.
	public override void _Ready()
	{
		parentStateMachine = GetParent<StateMachine>();
		
	}

	protected abstract Task OnEnter();
	protected abstract Task OnExit();
	protected virtual void OnStateProcess(double delta) {}
	protected virtual void OnStatePhysicsProcess(double delta) {}

	protected virtual string OnCheckRelevance()
	{
		return null;
	}
	
	public async Task Enter()
	{
		_startTime = Time.GetUnixTimeFromSystem();
		await OnEnter();
	}
	
	public async Task Exit()
	{
		statesInQueue.Clear();
		await OnExit();
	}

	public void StateProcess(double delta)
	{
		OnStateProcess(delta);
	}

	public void StatePhysicsProcess(double delta)
	{
		OnStatePhysicsProcess(delta);
	}

	public string CheckRelevance()
	{
		string value = OnCheckRelevance();
		
		if (timeElapsed <= (minimumStateDuration <= 0 ? 0.01f : minimumStateDuration) || !checkRelevance)
		{
			// if (queueRelevance && value != null && parentStateMachine.states[value].queueable)
			// {
			// 	statesInQueue.Add(value);
			// }
			return null;
		}
		
		// if (statesInQueue.Count > 0) return statesInQueue.Last();
		
		return value;
	}
	
}