using System;
using System.Runtime.InteropServices;
using gaemstone.Utility;
using static flecs_hub.flecs;

namespace gaemstone.ECS;

public static class ObserverExtensions
{
	public static unsafe EntityRef InitObserver(this EntityRef entity,
		Entity @event, FilterDesc filter, Action<Iterator> callback)
	{
		var world = entity.World;
		using var alloc = TempAllocator.Use();
		var desc = new ecs_observer_desc_t {
			entity = entity,
			filter = filter.ToFlecs(alloc),
			binding_ctx      = (void*)CallbackContextHelper.Create((world, callback)),
			binding_ctx_free = new() { Data = new() { Pointer = &FreeContext } },
			callback         = new() { Data = new() { Pointer = &Callback } },
		};
		desc.events[0] = @event;
		return new(world, new(ecs_observer_init(world, &desc)));
	}

	[UnmanagedCallersOnly]
	private static unsafe void Callback(ecs_iter_t* iter)
	{
		var (world, callback) = CallbackContextHelper
			.Get<(World, Action<Iterator>)>((nint)iter->binding_ctx);
		callback(new Iterator(world, null, *iter));
	}

	[UnmanagedCallersOnly]
	private static unsafe void FreeContext(void* context)
		=> CallbackContextHelper.Free((nint)context);
}