package top.r3944realms.lib39.api.callback;

import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.fabricmc.fabric.api.lookup.v1.entity.EntityApiLookup;
import net.minecraft.resources.Identifier;
import net.minecraft.world.entity.Entity;
import org.jetbrains.annotations.NotNull;
import top.r3944realms.lib39.core.sync.ISyncData;
import top.r3944realms.lib39.core.sync.ISyncManager;
import top.r3944realms.lib39.core.sync.SyncData2LookupManager;


/**
 * Fabric 的同步管理器注册回调
 */
@FunctionalInterface
public interface SyncManagerRegisterCallback {

    /**
     * 注册同步管理器的回调方法
     *
     * @param registrar 注册器实例
     * @return the action result
     */
    ActionResult registerSyncManagers(Registrar registrar);

    /**
     * 创建 Event 实例
     */
    Event<SyncManagerRegisterCallback> EVENT = EventFactory.createArrayBacked(
            SyncManagerRegisterCallback.class,
            (listeners) -> (registrar) -> {
                for (SyncManagerRegisterCallback listener : listeners) {
                    ActionResult result = listener.registerSyncManagers(registrar);
                    if (result != ActionResult.PASS) {
                        return result;
                    }
                }
                return ActionResult.PASS;
            }
    );

    /**
     * 注册器接口 - 提供注册同步管理器的方法
     */
    interface Registrar {

        /**
         * 获取 Fabric 同步管理器实例
         *
         * @return the sync data 2 lookup manager
         */
        SyncData2LookupManager manager();

        /**
         * 注册同步管理器
         *
         * @param <T>         the type parameter
         * @param id          the id
         * @param syncManager the sync manager
         * @param dataClass   the data class
         */
        <T extends ISyncData<?>> void register(
                Identifier id,
                ISyncManager<Entity, T> syncManager,
                Class<T> dataClass
        );

        /**
         * 允许实体类
         *
         * @param id            the id
         * @param entityClasses the entity classes
         */
        void allowEntityClass(Identifier id, Class<?>... entityClasses);

        /**
         * 移除允许的实体类
         *
         * @param id            the id
         * @param entityClasses the entity classes
         */
        void disallowEntityClass(Identifier id, Class<?>... entityClasses);

        /**
         * 绑定 EntityApiLookup（用于分离注册的情况）
         *
         * @param <T>       the type parameter
         * @param id        必须先注册安全同步管理器，再绑定 Lookup，否则会抛出 {@link IllegalStateException}
         * @param apiLookup the EntityApiLookup
         */
        <T extends ISyncData<?>> void bindApiLookup(
                Identifier id,
                net.fabricmc.fabric.api.lookup.v1.entity.EntityApiLookup<T, Void> apiLookup
        );

        /**
         * 解绑 EntityApiLookup
         *
         * @param id the id
         */
        void unbindApiLookup(Identifier id);

        /**
         * 完整的类型安全注册
         *
         * @param <T>                  the type parameter
         * @param id                   the id
         * @param syncManager          the sync manager
         * @param dataClass            the data class
         * @param allowedEntityClasses the allowed entity classes
         */
        default <T extends ISyncData<?>> void registerComplete(
                Identifier id,
                ISyncManager<Entity, T> syncManager,
                Class<T> dataClass,
                Class<?>... allowedEntityClasses
        ) {
            register(id, syncManager, dataClass);
            if (allowedEntityClasses.length > 0) {
                allowEntityClass(id, allowedEntityClasses);
            }
        }
    }

    /**
     * The type Sync manager registrar.
     */
    record SyncManagerRegistrar(
            SyncData2LookupManager manager) implements SyncManagerRegisterCallback.Registrar {

        @Override
        public <T extends ISyncData<?>> void register(
                @NotNull Identifier id,
                @NotNull ISyncManager<Entity, T> syncManager,
                @NotNull Class<T> dataClass
        ) {
            manager.registerManager(id, syncManager, dataClass);
        }

        @Override
        public void allowEntityClass(@NotNull Identifier id, @NotNull Class<?>... entityClasses) {
            manager.allowEntityClass(id, entityClasses);
        }

        @Override
        public void disallowEntityClass(@NotNull Identifier id, @NotNull Class<?>... entityClasses) {
            manager.disallowEntityClass(id, entityClasses);
        }

        @Override
        public <T extends ISyncData<?>> void bindApiLookup(
                @NotNull Identifier id,
                @NotNull EntityApiLookup<T, Void> apiLookup
        ) {
            manager.bindApiLookup(id, apiLookup);
        }

        @Override
        public void unbindApiLookup(@NotNull Identifier id) {
            manager.unbindApiLookup(id);
        }
    }
}