package com.livingworld.commands;

import java.util.stream.Collectors;

import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.arguments.IntegerArgumentType;

import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.Commands;
import net.minecraft.network.chat.Component;

import com.livingworld.core.simulation.SimulationManager;
import com.livingworld.modules.ModuleRegistry;
import com.livingworld.regions.RegionManager;

/**
 * Registers the root Living World debug command tree.
 */
public final class LivingWorldCommandRoot {

    private static final int OPERATOR_PERMISSION_LEVEL = 2;

    private LivingWorldCommandRoot() {
    }

    public static void register(
            CommandDispatcher<CommandSourceStack> dispatcher,
            RegionManager regionManager,
            ModuleRegistry moduleRegistry,
            SimulationManager simulationManager) {
        if (dispatcher == null) {
            throw new IllegalArgumentException("dispatcher must not be null");
        }
        if (regionManager == null) {
            throw new IllegalArgumentException("regionManager must not be null");
        }
        if (moduleRegistry == null) {
            throw new IllegalArgumentException("moduleRegistry must not be null");
        }
        if (simulationManager == null) {
            throw new IllegalArgumentException("simulationManager must not be null");
        }

        dispatcher.register(Commands.literal("lw")
                .requires(source -> source.hasPermission(OPERATOR_PERMISSION_LEVEL))
                .then(Commands.literal("status")
                        .executes(context -> showStatus(
                                context.getSource(), regionManager, moduleRegistry, simulationManager)))
                .then(Commands.literal("region")
                        .then(Commands.literal("info")
                                .executes(context -> RegionInfoCommand.execute(
                                        context.getSource(), regionManager))))
                .then(Commands.literal("modules")
                        .then(Commands.literal("list")
                                .executes(context -> listModules(
                                        context.getSource(), moduleRegistry))))
                .then(Commands.literal("simulate")
                        .then(Commands.argument(
                                        "ticks",
                                        IntegerArgumentType.integer(
                                                1, SimulationManager.MAX_FORCED_SIMULATION_TICKS))
                                .executes(context -> SimulateCommand.execute(
                                        context.getSource(),
                                        simulationManager,
                                        IntegerArgumentType.getInteger(context, "ticks"))))));
    }

    private static int showStatus(
            CommandSourceStack source,
            RegionManager regionManager,
            ModuleRegistry moduleRegistry,
            SimulationManager simulationManager) {
        String message = "Living World status: activeRegions=" + regionManager.getActiveRegions().size()
                + ", enabledModules=" + moduleRegistry.getEnabledModules().size()
                + ", simulationTick=" + simulationManager.getSimulationTickCounter();
        source.sendSuccess(() -> Component.literal(message), false);
        return 1;
    }

    private static int listModules(
            CommandSourceStack source,
            ModuleRegistry moduleRegistry) {
        String moduleIds = moduleRegistry.getAllModules().stream()
                .map(module -> module.getModuleId()
                        + (module.getMetadata().defaultEnabled() ? " [enabled]" : " [disabled]"))
                .collect(Collectors.joining(", "));
        if (moduleIds.isEmpty()) {
            moduleIds = "none";
        }
        String message = "Living World modules: " + moduleIds;
        source.sendSuccess(() -> Component.literal(message), false);
        return 1;
    }

    private static int placeholder(CommandSourceStack source, String message) {
        source.sendFailure(Component.literal(message));
        return 0;
    }
}
