package com.livingworld.platform.neoforge;

import com.livingworld.platform.PlatformAdapter;
import com.mojang.brigadier.CommandDispatcher;
import java.nio.file.Path;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Supplier;
import net.minecraft.SharedConstants;
import net.minecraft.commands.CommandSourceStack;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.fml.ModList;
import net.neoforged.fml.loading.FMLEnvironment;
import net.neoforged.neoforge.common.NeoForge;
import net.neoforged.neoforge.event.RegisterCommandsEvent;
import net.neoforged.neoforge.event.tick.ServerTickEvent;

/**
 * NeoForge implementation of the Living World platform boundary.
 */
public final class NeoForgePlatformAdapter implements PlatformAdapter {

    private static final String NEOFORGE_MOD_ID = "neoforge";

    private final Supplier<Path> worldSaveDirectory;
    private final Consumer<CommandDispatcher<CommandSourceStack>> commandRegistrar;
    private final Runnable serverTickHook;
    private boolean commandsRegistered;
    private boolean serverTickRegistered;

    public NeoForgePlatformAdapter(
            Supplier<Path> worldSaveDirectory,
            Consumer<CommandDispatcher<CommandSourceStack>> commandRegistrar,
            Runnable serverTickHook) {
        this.worldSaveDirectory =
                Objects.requireNonNull(worldSaveDirectory, "worldSaveDirectory");
        this.commandRegistrar = Objects.requireNonNull(commandRegistrar, "commandRegistrar");
        this.serverTickHook = Objects.requireNonNull(serverTickHook, "serverTickHook");
    }

    @Override
    public String getPlatformName() {
        return "NeoForge";
    }

    @Override
    public String getMinecraftVersion() {
        return SharedConstants.getCurrentVersion().getName();
    }

    @Override
    public String getLoaderVersion() {
        return ModList.get()
                .getModContainerById(NEOFORGE_MOD_ID)
                .map(container -> container.getModInfo().getVersion().toString())
                .orElse("unknown");
    }

    @Override
    public boolean isDedicatedServer() {
        return FMLEnvironment.dist == Dist.DEDICATED_SERVER;
    }

    @Override
    public Path getWorldSaveDirectory() {
        Path path = worldSaveDirectory.get();
        if (path == null) {
            throw new IllegalStateException("world save directory is not available yet");
        }
        return path;
    }

    @Override
    public void registerCommands() {
        if (commandsRegistered) {
            return;
        }
        NeoForge.EVENT_BUS.addListener(RegisterCommandsEvent.class, event ->
                commandRegistrar.accept(event.getDispatcher()));
        commandsRegistered = true;
    }

    @Override
    public void registerServerTickHook() {
        if (serverTickRegistered) {
            return;
        }
        NeoForge.EVENT_BUS.addListener(ServerTickEvent.Post.class, event ->
                serverTickHook.run());
        serverTickRegistered = true;
    }

    @Override
    public void registerPlayerEventHooks() {
        // Player activity hooks are intentionally deferred until a module needs them.
    }
}
