package com.tiedup.remake.commands.subcommands;

import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.tiedup.remake.commands.CommandHelper;
import com.tiedup.remake.entities.EntityMaster;
import com.tiedup.remake.entities.ModEntities;
import com.tiedup.remake.entities.ai.master.MasterState;
import com.tiedup.remake.state.PlayerBindState;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.Commands;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.MobSpawnType;

/**
 * Master/pet-play test sub-commands for /tiedup.
 * Handles: mastertest, masterchair, mastertask
 */
@SuppressWarnings("null")
public class MasterTestSubCommand {

    public static void register(
        LiteralArgumentBuilder<CommandSourceStack> root
    ) {
        // /tiedup mastertest
        root.then(
            Commands.literal("mastertest")
                .requires(CommandHelper.REQUIRES_OP)
                .executes(MasterTestSubCommand::mastertest)
        );
        // /tiedup masterchair
        root.then(
            Commands.literal("masterchair")
                .requires(CommandHelper.REQUIRES_OP)
                .executes(MasterTestSubCommand::masterchair)
        );
        // /tiedup mastertask <task>
        root.then(
            Commands.literal("mastertask")
                .requires(CommandHelper.REQUIRES_OP)
                .then(
                    Commands.argument("task", StringArgumentType.word())
                        .suggests((ctx, builder) -> {
                            for (MasterState s : MasterState.values()) {
                                builder.suggest(s.name().toLowerCase());
                            }
                            return builder.buildFuture();
                        })
                        .executes(MasterTestSubCommand::mastertask)
                )
        );
    }

    // Command Implementations

    /**
     * /tiedup mastertest
     *
     * Spawn a Master NPC nearby and immediately become its pet.
     * For testing the pet play system without going through capture.
     */
    private static int mastertest(CommandContext<CommandSourceStack> context)
        throws CommandSyntaxException {
        ServerPlayer player = context.getSource().getPlayerOrException();
        ServerLevel level = context.getSource().getLevel();

        double x = player.getX() + player.getLookAngle().x * 2;
        double y = player.getY();
        double z = player.getZ() + player.getLookAngle().z * 2;

        EntityMaster master = ModEntities.MASTER.get().create(level);
        if (master == null) {
            context
                .getSource()
                .sendFailure(
                    Component.translatable("command.tiedup.master.spawn_failed")
                );
            return 0;
        }

        master.moveTo(x, y, z, player.getYRot() + 180F, 0.0F);
        master.finalizeSpawn(
            level,
            level.getCurrentDifficultyAt(master.blockPosition()),
            MobSpawnType.COMMAND,
            null,
            null
        );
        level.addFreshEntity(master);

        master.setPetPlayer(player);
        master.putPetCollar(player);

        CommandHelper.syncPlayerState(
            player,
            PlayerBindState.getInstance(player)
        );

        String masterName = master.getNpcName();
        if (masterName == null || masterName.isEmpty()) masterName = "Master";

        String finalName = masterName;
        context
            .getSource()
            .sendSuccess(
                () ->
                    Component.translatable(
                        "command.tiedup.master.spawned", finalName
                    ),
                true
            );
        return 1;
    }

    /**
     * /tiedup masterchair
     *
     * Force the nearest Master NPC into HUMAN_CHAIR state.
     * Requires the player to be that Master's pet.
     */
    private static int masterchair(CommandContext<CommandSourceStack> context)
        throws CommandSyntaxException {
        ServerPlayer player = context.getSource().getPlayerOrException();
        EntityMaster master = findNearestMaster(player);

        if (master == null) {
            context
                .getSource()
                .sendFailure(
                    Component.translatable("command.tiedup.master.no_master_nearby")
                );
            return 0;
        }

        if (!master.hasPet()) {
            master.setPetPlayer(player);
            master.putPetCollar(player);
            CommandHelper.syncPlayerState(
                player,
                PlayerBindState.getInstance(player)
            );
        }

        master.setMasterState(MasterState.HUMAN_CHAIR);

        String masterName = master.getNpcName();
        if (masterName == null || masterName.isEmpty()) masterName = "Master";
        String finalName = masterName;

        context
            .getSource()
            .sendSuccess(
                () ->
                    Component.translatable(
                        "command.tiedup.master.forced_state", finalName, "HUMAN_CHAIR"
                    ),
                true
            );
        return 1;
    }

    /**
     * /tiedup mastertask <state>
     *
     * Force the nearest Master NPC into any MasterState.
     * Useful for testing specific master behaviors.
     */
    private static int mastertask(CommandContext<CommandSourceStack> context)
        throws CommandSyntaxException {
        ServerPlayer player = context.getSource().getPlayerOrException();
        String taskName = StringArgumentType.getString(context, "task");

        MasterState targetState;
        try {
            targetState = MasterState.valueOf(taskName.toUpperCase());
        } catch (IllegalArgumentException e) {
            context
                .getSource()
                .sendFailure(
                    Component.translatable("command.tiedup.master.unknown_state", taskName)
                );
            return 0;
        }

        EntityMaster master = findNearestMaster(player);
        if (master == null) {
            context
                .getSource()
                .sendFailure(
                    Component.translatable("command.tiedup.master.no_master_nearby")
                );
            return 0;
        }

        if (!master.hasPet()) {
            master.setPetPlayer(player);
            master.putPetCollar(player);
            CommandHelper.syncPlayerState(
                player,
                PlayerBindState.getInstance(player)
            );
        }

        master.setMasterState(targetState);

        String masterName = master.getNpcName();
        if (masterName == null || masterName.isEmpty()) masterName = "Master";
        String finalName = masterName;

        context
            .getSource()
            .sendSuccess(
                () ->
                    Component.translatable(
                        "command.tiedup.master.forced_state", finalName, targetState.name()
                    ),
                true
            );
        return 1;
    }

    /**
     * Find the nearest EntityMaster within 20 blocks of a player.
     */
    @javax.annotation.Nullable
    private static EntityMaster findNearestMaster(ServerPlayer player) {
        var masters = player
            .level()
            .getEntitiesOfClass(
                EntityMaster.class,
                player.getBoundingBox().inflate(20.0),
                m -> m.isAlive()
            );
        if (masters.isEmpty()) return null;
        return masters
            .stream()
            .min((a, b) ->
                Double.compare(a.distanceToSqr(player), b.distanceToSqr(player))
            )
            .orElse(null);
    }
}
