/*
 * Copyright (c) 2026 盐灯水母
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
 */

package com.remains_cave.client.model;

import net.minecraft.client.Minecraft;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.resources.PreparableReloadListener;
import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.util.profiling.ProfilerFiller;
import net.minecraft.world.item.Item;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.neoforge.event.AddReloadListenerEvent;
import org.jetbrains.annotations.NotNull;
import software.bernie.geckolib.cache.object.BakedGeoModel;
import software.bernie.geckolib.loading.FileLoader;
import software.bernie.geckolib.loading.json.raw.Model;
import software.bernie.geckolib.loading.object.BakedModelFactory;
import software.bernie.geckolib.loading.object.GeometryTree;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;

public class ArrowModelLoader {
    private static final Map<ResourceLocation, BakedGeoModel> MODEL_CACHE = new HashMap<>();
    private static final ResourceLocation DEFAULT_ARROW_MODEL =
            ResourceLocation.parse("remains_cave:geo/item/arrow_default.geo.json");
    private static BakedGeoModel defaultModel; // 缓存默认模型

    public static BakedGeoModel getArrowModel(Item arrowItem) {
        ResourceLocation itemId = arrowItem.builtInRegistryHolder().key().location();
        String modelPath = "geo/item/arrow_" + itemId.getNamespace() + "_" + itemId.getPath().replace('/', '_') + ".geo.json";
        ResourceLocation modelLocation = ResourceLocation.parse(itemId.getNamespace() + ":" + modelPath);

        // 检查缓存
        if (MODEL_CACHE.containsKey(modelLocation)) {
            return MODEL_CACHE.get(modelLocation);
        }

        ResourceManager resourceManager = Minecraft.getInstance().getResourceManager();
        BakedGeoModel model = null;

        // 尝试加载专属模型
        try {
            Model rawModel = FileLoader.loadModelFile(modelLocation, resourceManager);
            GeometryTree tree = GeometryTree.fromModel(rawModel);
            model = BakedModelFactory.getForNamespace(itemId.getNamespace()).constructGeoModel(tree);
        } catch (Exception e) {
            // 专属模型加载失败，使用默认模型
            model = getDefaultArrowModel(resourceManager);
        }

        // 无论成功加载专属模型还是默认模型，都将结果缓存到专属模型的键下
        MODEL_CACHE.put(modelLocation, model);
        return model;
    }

    private static BakedGeoModel getDefaultArrowModel(ResourceManager resourceManager) {
        if (defaultModel != null) return defaultModel;

        try {
            Model rawDefault = FileLoader.loadModelFile(DEFAULT_ARROW_MODEL, resourceManager);
            GeometryTree defaultTree = GeometryTree.fromModel(rawDefault);
            defaultModel = BakedModelFactory.getForNamespace("remains_cave").constructGeoModel(defaultTree);
        } catch (Exception e) {
            defaultModel = null; // 确保为null
        }
        return defaultModel;
    }

    //提供一个公共方法获取默认模型，供其他地方使用
    public static BakedGeoModel getDefaultArrowModel() {
        if (defaultModel == null) {
            ResourceManager resourceManager = Minecraft.getInstance().getResourceManager();
            return getDefaultArrowModel(resourceManager);
        }
        return defaultModel;
    }
    private static final PreparableReloadListener RELOAD_LISTENER = new PreparableReloadListener() {
        @Override
        public @NotNull CompletableFuture<Void> reload(PreparationBarrier barrier, @NotNull ResourceManager manager,
                                                       @NotNull ProfilerFiller prepareProfiler, @NotNull ProfilerFiller applyProfiler,
                                                       @NotNull Executor prepareExecutor, @NotNull Executor applyExecutor) {
            // 在 apply 阶段清空缓存（此时资源已经重载完成）
            return barrier.wait(manager)
                    .thenRunAsync(() -> {
                        MODEL_CACHE.clear();
                        defaultModel = null;
                    }, applyExecutor);
        }
    };
    @SubscribeEvent
    public static void onAddReloadListeners(AddReloadListenerEvent event) {
        event.addListener(RELOAD_LISTENER);
    }
}