using MoonTools.ECS;
using Nerfed.Runtime.Components;
using Nerfed.Runtime.Util;
using System.Numerics;

// TODO:
// Explore if having a WorldTransform and LocalTransfom component each holding position, rotation, scale values and the matricies is useful.
// Often you need to either get or set these values.
// If so, we probably need a utility funciton to do so. Since changing these values means that we need to update all the related data + children as well.

// TODO:
// When modifying transform all the children need to be updated as well.

namespace Nerfed.Runtime.Systems
{
    public class LocalToWorldSystem : MoonTools.ECS.System
    {
        private readonly Filter rootEntitiesFilter;

        public LocalToWorldSystem(World world) : base(world)
        {
            rootEntitiesFilter = FilterBuilder.Include<LocalTransform>().Exclude<Parent>().Build();
        }

        public override void Update(TimeSpan delta)
        {
            Matrix4x4 rootMatrix = Matrix4x4.Identity;

            foreach (Entity entity in rootEntitiesFilter.Entities)
            {
                UpdateWorldTransform(entity, rootMatrix);
            }
        }

        private void UpdateWorldTransform(in Entity entity, in Matrix4x4 parentLocalToWorld)
        {
            // TODO: Only update dirty transforms.
            // If a parent is dirty all the children need to update their localToWorld matrix.
            // How do we check if something is dirty? How do we know if a LocalTransform has been changed?

            LocalTransform localTransform = Get<LocalTransform>(entity);
            Matrix4x4 localToWorldMatrix = Matrix4x4.Multiply(parentLocalToWorld, localTransform.TRS());
            LocalToWorld localToWorld = new(localToWorldMatrix);
            Set(entity, localToWorld);

            Log.Info($"Entity {entity} | local position {localTransform.position} | world position {localToWorldMatrix.Translation}");

            ReverseSpanEnumerator<Entity> childEntities = World.OutRelations<ChildRelation>(entity);
            foreach (Entity childEntity in childEntities)
            {
                UpdateWorldTransform(childEntity, localToWorldMatrix);
            }
        }
    }
}