package top.r3944realms.lib39.core.sync;

import com.google.common.collect.Maps;
import net.fabricmc.fabric.api.lookup.v1.entity.EntityApiLookup;
import net.minecraft.resources.Identifier;
import net.minecraft.world.entity.Entity;
import org.jetbrains.annotations.Nullable;

import java.util.Map;
import java.util.Objects;
import java.util.Optional;

/**
 * The type Sync data 2 lookup manager.
 */
public class SyncData2LookupManager extends SyncData2Manager<SyncData2LookupManager.TypedSyncEntry<? extends ISyncData<?>>> {
    /**
     * The Typed entries.
     */
    protected final Map<Identifier, TypedSyncEntry<?>> typedEntries = Maps.newConcurrentMap();

    @Override
    protected Map<Identifier, TypedSyncEntry<?>> getTypedEntries() {
        return typedEntries;
    }

    /**
     * The type Typed sync entry.
     *
     * @param <T> the type parameter
     */
    protected static class TypedSyncEntry<T extends ISyncData<?>> extends SyncData2Manager.TypedSyncEntry<Entity, T> {
        /**
         * Instantiates a new Typed sync entry for Fabric
         *
         * @param manager   the manager
         * @param apiLookup the EntityApiLookup instance
         */
        @SuppressWarnings("unchecked")
        public TypedSyncEntry(ISyncManager<Entity, T> manager, @Nullable EntityApiLookup<T, Void> apiLookup) {
            super(manager, key -> {
                if (apiLookup != null) {
                    T data = ((IEntityApiLookUpImplExtend<T, Void>) apiLookup).lib39$findWithoutCheck(key, null);
                    return Optional.ofNullable(data);
                }
                return Optional.empty();
            });
        }
    }

    /**
     * 使用自定义提供器注册管理器
     *
     * @param <T>       the type parameter
     * @param key       the key
     * @param manager   the manager
     * @param dataClass the data class
     */
    public <T extends ISyncData<?>> void registerManager(
            Identifier key,
            ISyncManager<Entity, T> manager,
            Class<T> dataClass
    ) {
        Objects.requireNonNull(key, "Identifier key cannot be null");
        Objects.requireNonNull(manager, "Sync manager cannot be null");
        Objects.requireNonNull(dataClass, "Data class cannot be null");

        // 创建 EntityApiLookup
        EntityApiLookup<T, Void> apiLookup = EntityApiLookup.get(key, dataClass, Void.class);
        typedEntries.put(key, new TypedSyncEntry<>(manager, apiLookup));
    }

    /**
     * 绑定 EntityApiLookup（用于分离注册的情况）
     *
     * @param <T>       the type parameter
     * @param key       the key
     * @param apiLookup the EntityApiLookup
     */
    public <T extends ISyncData<?>> void bindApiLookup(Identifier key, EntityApiLookup<T, Void> apiLookup) {
        Objects.requireNonNull(key, "Identifier key cannot be null");
        Objects.requireNonNull(apiLookup, "EntityApiLookup cannot be null");

        TypedSyncEntry<?> entry = typedEntries.get(key);
        if (entry != null) {
            updateApiLookupInEntry(key, entry, apiLookup);
        } else {
            throw new IllegalArgumentException("No manager found for " + key);
        }
    }

    /**
     * 解绑 EntityApiLookup
     *
     * @param key the key
     */
    public void unbindApiLookup(Identifier key) {
        Objects.requireNonNull(key, "Identifier key cannot be null");

        TypedSyncEntry<?> entry = typedEntries.get(key);
        if (entry != null) {
            updateApiLookupInEntry(key, entry, null);
        }
    }

    /**
     * 更新条目的 EntityApiLookup
     *
     * @param <T>          the type parameter
     * @param id           the id
     * @param entry        the entry
     * @param newApiLookup the new api lookup
     */
    protected <T extends ISyncData<?>> void updateApiLookupInEntry(
            Identifier id,
            TypedSyncEntry<?> entry,
            EntityApiLookup<T, Void> newApiLookup
    ) {
        updateDataProviderInEntry(id, entry, key -> newApiLookup != null ? Optional.ofNullable(newApiLookup.find(key, null)) : Optional.empty());
    }
}
