package com.ptsmods.morecommands.commands.server.elevated;

import com.mojang.brigadier.CommandDispatcher;
import com.ptsmods.morecommands.MoreCommands;
import com.ptsmods.morecommands.api.util.compat.Compat;
import com.ptsmods.morecommands.miscellaneous.Command;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.entity.MobSpawnerBlockEntity;
import net.minecraft.command.argument.EntitySummonArgumentType;
import net.minecraft.command.suggestion.SuggestionProviders;
import net.minecraft.entity.EntityType;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.util.Identifier;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.registry.Registry;
import net.minecraft.world.MobSpawnerLogic;
import net.minecraft.world.World;

import java.util.Objects;

public class SpawnerCommand extends Command {
    @Override
    public void register(CommandDispatcher<ServerCommandSource> dispatcher) {
        dispatcher.register(literalReqOp("spawner")
                .then(argument("type", EntitySummonArgumentType.entitySummon())
                        .suggests(SuggestionProviders.SUMMONABLE_ENTITIES)
                        .executes(ctx -> {
                            BlockHitResult result = (BlockHitResult) MoreCommands.getRayTraceTarget(ctx.getSource().getEntityOrThrow(), ctx.getSource().getWorld(), 160, true, true);
                            BlockState state = ctx.getSource().getWorld().getBlockState(result.getBlockPos());
                            EntityType<?> type = Registry.ENTITY_TYPE.get(ctx.getArgument("type", Identifier.class));
                            BlockPos pos = new BlockPos(ctx.getSource().getPosition());
                            if (!state.isOf(Blocks.SPAWNER)) {
                                if (ctx.getSource().getPlayerOrThrow().getMainHandStack().getItem() == Items.SPAWNER) {
                                    MobSpawnerLogic logic = new MobSpawnerLogic() {
                                        @Override
                                        public void sendStatus(World world, BlockPos pos, int i) {
                                        } // TODO add remapped versions of following methods

                                        public void sendStatus(int status) {
                                        }

                                        public World getWorld() {
                                            return ctx.getSource().getWorld();
                                        }

                                        public BlockPos getPos() {
                                            return pos;
                                        }
                                    }; // Keeping the old methods in there even though they don't override anything in 1.17 for compatibility with 1.16
                                    ItemStack stack = ctx.getSource().getPlayerOrThrow().getMainHandStack();
                                    NbtCompound tag = stack.getOrCreateNbt();
                                    if (tag != null && (tag = tag.getCompound("BlockEntityTag")).contains("Delay"))
                                        Compat.get().readSpawnerLogicNbt(logic, ctx.getSource().getWorld(), pos, tag);
                                    logic.setEntityId(type);
                                    (tag = new NbtCompound()).put("BlockEntityTag", Compat.get().writeSpawnerLogicNbt(logic, ctx.getSource().getWorld(), pos, new NbtCompound()));
                                    ((NbtCompound) tag.getCompound("BlockEntityTag").getList("SpawnPotentials", 10).get(0)).getCompound("Entity").putString("id", Registry.ENTITY_TYPE.getId(type).toString());
                                    stack.setNbt(tag);
                                    sendMsg(ctx, "Poof!");
                                    return 1;
                                } else sendError(ctx, "You do not appear to be looking at or holding a spawner.");
                            } else {
                                MobSpawnerBlockEntity be = (MobSpawnerBlockEntity) ctx.getSource().getWorld().getBlockEntity(result.getBlockPos());
                                MobSpawnerLogic logic = Objects.requireNonNull(be).getLogic();
                                logic.setEntityId(type);
                                NbtCompound tag = Compat.get().writeSpawnerLogicNbt(logic, ctx.getSource().getWorld(), pos, new NbtCompound());
                                ((NbtCompound) tag.getList("SpawnPotentials", 10).get(0)).getCompound("Entity").putString("id", Registry.ENTITY_TYPE.getId(type).toString());
                                Compat.get().readSpawnerLogicNbt(logic, ctx.getSource().getWorld(), pos, tag);
                                be.markDirty();
                                ctx.getSource().getWorld().updateListeners(result.getBlockPos(), state, state, 3);
                                sendMsg(ctx, "Poof!");
                                return 1;
                            }
                            return 0;
                        })));
    }

    @Override
    public String getDocsPath() {
        return "/elevated/spawner";
    }
}

@@ -2128,16 +2128,22 @@
 c = new 
+Legacy
 MobSpawn
@@ -2154,879 +2154,42 @@
 gic(
-) %7B%0A                                        @Override%0A                                        public void sendStatus(World world, BlockPos pos, int i) %7B%0A                                        %7D // TODO add remapped versions of following methods%0A%0A                                        public void sendStatus(int status) %7B%0A                                        %7D%0A%0A                                        public World getWorld() %7B%0A                                            return ctx.getSource().getWorld();%0A                                        %7D%0A%0A                                        public BlockPos getPos() %7B%0A                                            return pos;%0A                                        %7D%0A                                    %7D; // Keeping the old methods in there even though they don't override anything in 1.17 for compatibility with 1.16
+ctx.getSource().getWorld(), pos);%0A
 %0A   
@@ -4550,11 +4550,1184 @@
 %22;%0A    %7D
+%0A%0A    // Keeping the old methods in there even though they don't override anything in 1.17 for compatibility with 1.16%0A    private static class LegacyMobSpawnerLogic extends MobSpawnerLogic %7B%0A        private final World world;%0A        private final BlockPos pos;%0A%0A        public LegacyMobSpawnerLogic(World world, BlockPos pos) %7B%0A            this.world = world;%0A            this.pos = pos;%0A        %7D%0A%0A        @Override%0A        public void sendStatus(World world, BlockPos pos, int i) %7B%0A        %7D%0A%0A        // sendStatus(I)V%0A        public void sendStatus(int status) %7B%7D%0A%0A        public void method_8273(int status) %7B%7D%0A%0A        public void broadcastEvent(int status) %7B%7D%0A%0A        // getWorld()Lnet/minecraft/world/World%0A        public World getWorld() %7B%0A            return world;%0A        %7D%0A%0A        public World method_8271() %7B%0A            return getWorld();%0A        %7D%0A%0A        public World getLevel() %7B%0A            return getWorld();%0A        %7D%0A%0A        // getPos()Lnet/minecraft/util/math/BlockPos (moj name is the same)%0A        public BlockPos getPos() %7B%0A            return pos;%0A        %7D%0A%0A        public BlockPos method_8276() %7B%0A            return getPos();%0A        %7D%0A    %7D
 %0A%7D%0A

Fix /spawner for 1.16