using System.Collections;
using System.Collections.Generic;

using Syntriax.Engine.Core;
using Syntriax.Engine.Core.Abstract;
using Syntriax.Engine.Physics2D.Abstract;

namespace Syntriax.Engine.Physics2D;

public class PhysicsCoroutineManager : HierarchyObject
{
    private readonly List<IEnumerator> enumerators = [];
    private IPhysicsEngine2D? physicsEngine = null;

    public IEnumerator CreateCoroutine(IEnumerator enumerator)
    {
        enumerators.Add(enumerator);
        return enumerator;
    }

    public void StopCoroutine(IEnumerator enumerator)
    {
        enumerators.Remove(enumerator);
    }

    protected override void OnEnteringHierarchy(IGameManager gameManager)
    {
        physicsEngine = gameManager.FindHierarchyObject<IPhysicsEngine2D>();
        if (physicsEngine is IPhysicsEngine2D foundPhysicsEngine)
            foundPhysicsEngine.OnPhysicsStep += OnPhysicsStep;
        else
            gameManager.OnUpdate += OnUpdate;
    }

    private void OnPhysicsStep(IPhysicsEngine2D sender, float stepDeltaTime)
    {
        for (int i = enumerators.Count - 1; i >= 0; i--)
        {
            if (enumerators[i].Current is ICoroutineYield coroutineYield && coroutineYield.Yield())
                continue;

            if (!enumerators[i].MoveNext())
                enumerators.RemoveAt(i);
        }
    }

    protected override void OnExitingHierarchy(IGameManager gameManager)
    {
        if (physicsEngine is IPhysicsEngine2D existingPhysicsEngine)
            existingPhysicsEngine.OnPhysicsStep -= OnPhysicsStep;
        gameManager.OnUpdate -= OnUpdate;
    }

    private void OnUpdate(IGameManager sender, EngineTime engineTime)
    {
        if (GameManager is not IGameManager gameManager)
            return;

        physicsEngine = gameManager.FindHierarchyObject<IPhysicsEngine2D>();
        if (physicsEngine is IPhysicsEngine2D foundPhysicsEngine)
        {
            foundPhysicsEngine.OnPhysicsStep += OnPhysicsStep;
            gameManager.OnUpdate -= OnUpdate;
        }
    }
}