package net.minecraft.world.item;

import net.minecraft.world.level.LevelAccessor;
import net.minecraft.tags.BlockTags;
import net.minecraft.world.InteractionResult;
import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.network.chat.Component;
import java.util.List;
import net.minecraft.network.protocol.Packet;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.core.Direction;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.chunk.LevelChunk;
import com.google.common.collect.Multiset;
import com.google.common.collect.Iterables;
import com.google.common.collect.Multisets;
import net.minecraft.core.Vec3i;
import net.minecraft.world.level.material.MaterialColor;
import net.minecraft.world.level.levelgen.Heightmap;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.core.BlockPos;
import com.google.common.collect.LinkedHashMultiset;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.dimension.DimensionType;
import net.minecraft.nbt.CompoundTag;
import javax.annotation.Nullable;
import net.minecraft.world.level.saveddata.maps.MapItemSavedData;
import net.minecraft.world.level.ItemLike;
import net.minecraft.world.level.Level;

public class MapItem extends ComplexItem {
    public MapItem(final Properties a) {
        super(a);
    }
    
    public static ItemStack create(final Level bjw, final int integer2, final int integer3, final byte byte4, final boolean boolean5, final boolean boolean6) {
        final ItemStack ben7 = new ItemStack(Items.FILLED_MAP);
        createAndStoreSavedData(ben7, bjw, integer2, integer3, byte4, boolean5, boolean6, bjw.dimension.getType());
        return ben7;
    }
    
    @Nullable
    public static MapItemSavedData getSavedData(final ItemStack ben, final Level bjw) {
        return bjw.getMapData(makeKey(getMapId(ben)));
    }
    
    @Nullable
    public static MapItemSavedData getOrCreateSavedData(final ItemStack ben, final Level bjw) {
        MapItemSavedData crg3 = getSavedData(ben, bjw);
        if (crg3 == null && !bjw.isClientSide) {
            crg3 = createAndStoreSavedData(ben, bjw, bjw.getLevelData().getXSpawn(), bjw.getLevelData().getZSpawn(), 3, false, false, bjw.dimension.getType());
        }
        return crg3;
    }
    
    public static int getMapId(final ItemStack ben) {
        final CompoundTag jt2 = ben.getTag();
        return (jt2 != null && jt2.contains("map", 99)) ? jt2.getInt("map") : 0;
    }
    
    private static MapItemSavedData createAndStoreSavedData(final ItemStack ben, final Level bjw, final int integer3, final int integer4, final int integer5, final boolean boolean6, final boolean boolean7, final DimensionType cbi) {
        final int integer6 = bjw.getFreeMapId();
        final MapItemSavedData crg10 = new MapItemSavedData(makeKey(integer6));
        crg10.setProperties(integer3, integer4, integer5, boolean6, boolean7, cbi);
        bjw.setMapData(crg10);
        ben.getOrCreateTag().putInt("map", integer6);
        return crg10;
    }
    
    public static String makeKey(final int integer) {
        return "map_" + integer;
    }
    
    public void update(final Level bjw, final Entity akq, final MapItemSavedData crg) {
        if (bjw.dimension.getType() != crg.dimension || !(akq instanceof Player)) {
            return;
        }
        final int integer5 = 1 << crg.scale;
        final int integer6 = crg.x;
        final int integer7 = crg.z;
        final int integer8 = Mth.floor(akq.getX() - integer6) / integer5 + 64;
        final int integer9 = Mth.floor(akq.getZ() - integer7) / integer5 + 64;
        int integer10 = 128 / integer5;
        if (bjw.dimension.isHasCeiling()) {
            integer10 /= 2;
        }
        final MapItemSavedData.HoldingPlayer holdingPlayer;
        final MapItemSavedData.HoldingPlayer a11 = holdingPlayer = crg.getHoldingPlayer((Player)akq);
        ++holdingPlayer.step;
        boolean boolean12 = false;
        for (int integer11 = integer8 - integer10 + 1; integer11 < integer8 + integer10; ++integer11) {
            if ((integer11 & 0xF) == (a11.step & 0xF) || boolean12) {
                boolean12 = false;
                double double14 = 0.0;
                for (int integer12 = integer9 - integer10 - 1; integer12 < integer9 + integer10; ++integer12) {
                    if (integer11 >= 0 && integer12 >= -1 && integer11 < 128) {
                        if (integer12 < 128) {
                            final int integer13 = integer11 - integer8;
                            final int integer14 = integer12 - integer9;
                            final boolean boolean13 = integer13 * integer13 + integer14 * integer14 > (integer10 - 2) * (integer10 - 2);
                            final int integer15 = (integer6 / integer5 + integer11 - 64) * integer5;
                            final int integer16 = (integer7 / integer5 + integer12 - 64) * integer5;
                            final Multiset<MaterialColor> multiset22 = LinkedHashMultiset.create();
                            final LevelChunk cal23 = bjw.getChunkAt(new BlockPos(integer15, 0, integer16));
                            if (!cal23.isEmpty()) {
                                final ChunkPos bjh24 = cal23.getPos();
                                final int integer17 = integer15 & 0xF;
                                final int integer18 = integer16 & 0xF;
                                int integer19 = 0;
                                double double15 = 0.0;
                                if (bjw.dimension.isHasCeiling()) {
                                    int integer20 = integer15 + integer16 * 231871;
                                    integer20 = integer20 * integer20 * 31287121 + integer20 * 11;
                                    if ((integer20 >> 20 & 0x1) == 0x0) {
                                        multiset22.add(Blocks.DIRT.defaultBlockState().getMapColor(bjw, BlockPos.ZERO), 10);
                                    }
                                    else {
                                        multiset22.add(Blocks.STONE.defaultBlockState().getMapColor(bjw, BlockPos.ZERO), 100);
                                    }
                                    double15 = 100.0;
                                }
                                else {
                                    final BlockPos.MutableBlockPos a12 = new BlockPos.MutableBlockPos();
                                    final BlockPos.MutableBlockPos a13 = new BlockPos.MutableBlockPos();
                                    for (int integer21 = 0; integer21 < integer5; ++integer21) {
                                        for (int integer22 = 0; integer22 < integer5; ++integer22) {
                                            int integer23 = cal23.getHeight(Heightmap.Types.WORLD_SURFACE, integer21 + integer17, integer22 + integer18) + 1;
                                            BlockState byj35;
                                            if (integer23 > 1) {
                                                do {
                                                    --integer23;
                                                    a12.set(bjh24.getMinBlockX() + integer21 + integer17, integer23, bjh24.getMinBlockZ() + integer22 + integer18);
                                                    byj35 = cal23.getBlockState(a12);
                                                } while (byj35.getMapColor(bjw, a12) == MaterialColor.NONE && integer23 > 0);
                                                if (integer23 > 0 && !byj35.getFluidState().isEmpty()) {
                                                    int integer24 = integer23 - 1;
                                                    a13.set(a12);
                                                    BlockState byj36;
                                                    do {
                                                        a13.setY(integer24--);
                                                        byj36 = cal23.getBlockState(a13);
                                                        ++integer19;
                                                    } while (integer24 > 0 && !byj36.getFluidState().isEmpty());
                                                    byj35 = this.getCorrectStateForFluidBlock(bjw, byj35, a12);
                                                }
                                            }
                                            else {
                                                byj35 = Blocks.BEDROCK.defaultBlockState();
                                            }
                                            crg.checkBanners(bjw, bjh24.getMinBlockX() + integer21 + integer17, bjh24.getMinBlockZ() + integer22 + integer18);
                                            double15 += integer23 / (double)(integer5 * integer5);
                                            multiset22.add(byj35.getMapColor(bjw, a12));
                                        }
                                    }
                                }
                                integer19 /= integer5 * integer5;
                                double double16 = (double15 - double14) * 4.0 / (integer5 + 4) + ((integer11 + integer12 & 0x1) - 0.5) * 0.4;
                                int integer21 = 1;
                                if (double16 > 0.6) {
                                    integer21 = 2;
                                }
                                if (double16 < -0.6) {
                                    integer21 = 0;
                                }
                                final MaterialColor cop33 = Iterables.<MaterialColor>getFirst(Multisets.<MaterialColor>copyHighestCountFirst(multiset22), MaterialColor.NONE);
                                if (cop33 == MaterialColor.WATER) {
                                    double16 = integer19 * 0.1 + (integer11 + integer12 & 0x1) * 0.2;
                                    integer21 = 1;
                                    if (double16 < 0.5) {
                                        integer21 = 2;
                                    }
                                    if (double16 > 0.9) {
                                        integer21 = 0;
                                    }
                                }
                                double14 = double15;
                                if (integer12 >= 0) {
                                    if (integer13 * integer13 + integer14 * integer14 < integer10 * integer10) {
                                        if (!boolean13 || (integer11 + integer12 & 0x1) != 0x0) {
                                            final byte byte34 = crg.colors[integer11 + integer12 * 128];
                                            final byte byte35 = (byte)(cop33.id * 4 + integer21);
                                            if (byte34 != byte35) {
                                                crg.colors[integer11 + integer12 * 128] = byte35;
                                                crg.setDirty(integer11, integer12);
                                                boolean12 = true;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    
    private BlockState getCorrectStateForFluidBlock(final Level bjw, final BlockState byj, final BlockPos fk) {
        final FluidState coj5 = byj.getFluidState();
        if (!coj5.isEmpty() && !byj.isFaceSturdy(bjw, fk, Direction.UP)) {
            return coj5.createLegacyBlock();
        }
        return byj;
    }
    
    private static boolean isLand(final Biome[] arr, final int integer2, final int integer3, final int integer4) {
        return arr[integer3 * integer2 + integer4 * integer2 * 128 * integer2].getDepth() >= 0.0f;
    }
    
    public static void renderBiomePreviewMap(final ServerLevel xd, final ItemStack ben) {
        final MapItemSavedData crg3 = getOrCreateSavedData(ben, xd);
        if (crg3 == null) {
            return;
        }
        if (xd.dimension.getType() != crg3.dimension) {
            return;
        }
        final int integer4 = 1 << crg3.scale;
        final int integer5 = crg3.x;
        final int integer6 = crg3.z;
        final Biome[] arr7 = new Biome[128 * integer4 * 128 * integer4];
        for (int integer7 = 0; integer7 < 128 * integer4; ++integer7) {
            for (int integer8 = 0; integer8 < 128 * integer4; ++integer8) {
                arr7[integer7 * 128 * integer4 + integer8] = xd.getBiome(new BlockPos((integer5 / integer4 - 64) * integer4 + integer8, 0, (integer6 / integer4 - 64) * integer4 + integer7));
            }
        }
        for (int integer7 = 0; integer7 < 128; ++integer7) {
            for (int integer8 = 0; integer8 < 128; ++integer8) {
                if (integer7 > 0 && integer8 > 0 && integer7 < 127 && integer8 < 127) {
                    final Biome bkt10 = arr7[integer7 * integer4 + integer8 * integer4 * 128 * integer4];
                    int integer9 = 8;
                    if (isLand(arr7, integer4, integer7 - 1, integer8 - 1)) {
                        --integer9;
                    }
                    if (isLand(arr7, integer4, integer7 - 1, integer8 + 1)) {
                        --integer9;
                    }
                    if (isLand(arr7, integer4, integer7 - 1, integer8)) {
                        --integer9;
                    }
                    if (isLand(arr7, integer4, integer7 + 1, integer8 - 1)) {
                        --integer9;
                    }
                    if (isLand(arr7, integer4, integer7 + 1, integer8 + 1)) {
                        --integer9;
                    }
                    if (isLand(arr7, integer4, integer7 + 1, integer8)) {
                        --integer9;
                    }
                    if (isLand(arr7, integer4, integer7, integer8 - 1)) {
                        --integer9;
                    }
                    if (isLand(arr7, integer4, integer7, integer8 + 1)) {
                        --integer9;
                    }
                    int integer10 = 3;
                    MaterialColor cop13 = MaterialColor.NONE;
                    if (bkt10.getDepth() < 0.0f) {
                        cop13 = MaterialColor.COLOR_ORANGE;
                        if (integer9 > 7 && integer8 % 2 == 0) {
                            integer10 = (integer7 + (int)(Mth.sin(integer8 + 0.0f) * 7.0f)) / 8 % 5;
                            if (integer10 == 3) {
                                integer10 = 1;
                            }
                            else if (integer10 == 4) {
                                integer10 = 0;
                            }
                        }
                        else if (integer9 > 7) {
                            cop13 = MaterialColor.NONE;
                        }
                        else if (integer9 > 5) {
                            integer10 = 1;
                        }
                        else if (integer9 > 3) {
                            integer10 = 0;
                        }
                        else if (integer9 > 1) {
                            integer10 = 0;
                        }
                    }
                    else if (integer9 > 0) {
                        cop13 = MaterialColor.COLOR_BROWN;
                        if (integer9 > 3) {
                            integer10 = 1;
                        }
                        else {
                            integer10 = 3;
                        }
                    }
                    if (cop13 != MaterialColor.NONE) {
                        crg3.colors[integer7 + integer8 * 128] = (byte)(cop13.id * 4 + integer10);
                        crg3.setDirty(integer7, integer8);
                    }
                }
            }
        }
    }
    
    @Override
    public void inventoryTick(final ItemStack ben, final Level bjw, final Entity akq, final int integer, final boolean boolean5) {
        if (bjw.isClientSide) {
            return;
        }
        final MapItemSavedData crg7 = getOrCreateSavedData(ben, bjw);
        if (crg7 == null) {
            return;
        }
        if (akq instanceof Player) {
            final Player ayj8 = (Player)akq;
            crg7.tickCarriedBy(ayj8, ben);
        }
        if (!crg7.locked && (boolean5 || (akq instanceof Player && ((Player)akq).getOffhandItem() == ben))) {
            this.update(bjw, akq, crg7);
        }
    }
    
    @Nullable
    @Override
    public Packet<?> getUpdatePacket(final ItemStack ben, final Level bjw, final Player ayj) {
        return getOrCreateSavedData(ben, bjw).getUpdatePacket(ben, bjw, ayj);
    }
    
    @Override
    public void onCraftedBy(final ItemStack ben, final Level bjw, final Player ayj) {
        final CompoundTag jt5 = ben.getTag();
        if (jt5 != null && jt5.contains("map_scale_direction", 99)) {
            scaleMap(ben, bjw, jt5.getInt("map_scale_direction"));
            jt5.remove("map_scale_direction");
        }
    }
    
    protected static void scaleMap(final ItemStack ben, final Level bjw, final int integer) {
        final MapItemSavedData crg4 = getOrCreateSavedData(ben, bjw);
        if (crg4 != null) {
            createAndStoreSavedData(ben, bjw, crg4.x, crg4.z, Mth.clamp(crg4.scale + integer, 0, 4), crg4.trackingPosition, crg4.unlimitedTracking, crg4.dimension);
        }
    }
    
    @Nullable
    public static ItemStack lockMap(final Level bjw, final ItemStack ben) {
        final MapItemSavedData crg3 = getOrCreateSavedData(ben, bjw);
        if (crg3 != null) {
            final ItemStack ben2 = ben.copy();
            final MapItemSavedData crg4 = createAndStoreSavedData(ben2, bjw, 0, 0, crg3.scale, crg3.trackingPosition, crg3.unlimitedTracking, crg3.dimension);
            crg4.lockData(crg3);
            return ben2;
        }
        return null;
    }
    
    @Override
    public void appendHoverText(final ItemStack ben, @Nullable final Level bjw, final List<Component> list, final TooltipFlag bfw) {
        final MapItemSavedData crg6 = (bjw == null) ? null : getOrCreateSavedData(ben, bjw);
        if (crg6 != null && crg6.locked) {
            list.add(new TranslatableComponent("filled_map.locked", new Object[] { getMapId(ben) }).withStyle(ChatFormatting.GRAY));
        }
        if (bfw.isAdvanced()) {
            if (crg6 != null) {
                list.add(new TranslatableComponent("filled_map.id", new Object[] { getMapId(ben) }).withStyle(ChatFormatting.GRAY));
                list.add(new TranslatableComponent("filled_map.scale", new Object[] { 1 << crg6.scale }).withStyle(ChatFormatting.GRAY));
                list.add(new TranslatableComponent("filled_map.level", new Object[] { crg6.scale, 4 }).withStyle(ChatFormatting.GRAY));
            }
            else {
                list.add(new TranslatableComponent("filled_map.unknown", new Object[0]).withStyle(ChatFormatting.GRAY));
            }
        }
    }
    
    public static int getColor(final ItemStack ben) {
        final CompoundTag jt2 = ben.getTagElement("display");
        if (jt2 != null && jt2.contains("MapColor", 99)) {
            final int integer3 = jt2.getInt("MapColor");
            return 0xFF000000 | (integer3 & 0xFFFFFF);
        }
        return -12173266;
    }
    
    @Override
    public InteractionResult useOn(final UseOnContext bfz) {
        final BlockState byj3 = bfz.getLevel().getBlockState(bfz.getClickedPos());
        if (byj3.is(BlockTags.BANNERS)) {
            if (!bfz.level.isClientSide) {
                final MapItemSavedData crg4 = getOrCreateSavedData(bfz.getItemInHand(), bfz.getLevel());
                crg4.toggleBanner(bfz.getLevel(), bfz.getClickedPos());
            }
            return InteractionResult.SUCCESS;
        }
        return super.useOn(bfz);
    }
}
