package net.minecraft.world.item;

import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.Block;
import net.minecraft.tags.Tag;
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.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.resources.ResourceKey;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerLevel;
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 bqb, final int integer2, final int integer3, final byte byte4, final boolean boolean5, final boolean boolean6) {
        final ItemStack bki7 = new ItemStack(Items.FILLED_MAP);
        createAndStoreSavedData(bki7, bqb, integer2, integer3, byte4, boolean5, boolean6, bqb.dimension());
        return bki7;
    }
    
    @Nullable
    public static MapItemSavedData getSavedData(final ItemStack bki, final Level bqb) {
        return bqb.getMapData(makeKey(getMapId(bki)));
    }
    
    @Nullable
    public static MapItemSavedData getOrCreateSavedData(final ItemStack bki, final Level bqb) {
        MapItemSavedData czv3 = getSavedData(bki, bqb);
        if (czv3 == null && bqb instanceof ServerLevel) {
            czv3 = createAndStoreSavedData(bki, bqb, bqb.getLevelData().getXSpawn(), bqb.getLevelData().getZSpawn(), 3, false, false, bqb.dimension());
        }
        return czv3;
    }
    
    public static int getMapId(final ItemStack bki) {
        final CompoundTag le2 = bki.getTag();
        return (le2 != null && le2.contains("map", 99)) ? le2.getInt("map") : 0;
    }
    
    private static MapItemSavedData createAndStoreSavedData(final ItemStack bki, final Level bqb, final int integer3, final int integer4, final int integer5, final boolean boolean6, final boolean boolean7, final ResourceKey<Level> ug) {
        final int integer6 = bqb.getFreeMapId();
        final MapItemSavedData czv10 = new MapItemSavedData(makeKey(integer6));
        czv10.setProperties(integer3, integer4, integer5, boolean6, boolean7, ug);
        bqb.setMapData(czv10);
        bki.getOrCreateTag().putInt("map", integer6);
        return czv10;
    }
    
    public static String makeKey(final int integer) {
        return "map_" + integer;
    }
    
    public void update(final Level bqb, final Entity aom, final MapItemSavedData czv) {
        if (bqb.dimension() != czv.dimension || !(aom instanceof Player)) {
            return;
        }
        final int integer5 = 1 << czv.scale;
        final int integer6 = czv.x;
        final int integer7 = czv.z;
        final int integer8 = Mth.floor(aom.getX() - integer6) / integer5 + 64;
        final int integer9 = Mth.floor(aom.getZ() - integer7) / integer5 + 64;
        int integer10 = 128 / integer5;
        if (bqb.dimensionType().hasCeiling()) {
            integer10 /= 2;
        }
        final MapItemSavedData.HoldingPlayer holdingPlayer;
        final MapItemSavedData.HoldingPlayer a11 = holdingPlayer = czv.getHoldingPlayer((Player)aom);
        ++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 chj23 = bqb.getChunkAt(new BlockPos(integer15, 0, integer16));
                            if (!chj23.isEmpty()) {
                                final ChunkPos bph24 = chj23.getPos();
                                final int integer17 = integer15 & 0xF;
                                final int integer18 = integer16 & 0xF;
                                int integer19 = 0;
                                double double15 = 0.0;
                                if (bqb.dimensionType().hasCeiling()) {
                                    int integer20 = integer15 + integer16 * 231871;
                                    integer20 = integer20 * integer20 * 31287121 + integer20 * 11;
                                    if ((integer20 >> 20 & 0x1) == 0x0) {
                                        multiset22.add(Blocks.DIRT.defaultBlockState().getMapColor(bqb, BlockPos.ZERO), 10);
                                    }
                                    else {
                                        multiset22.add(Blocks.STONE.defaultBlockState().getMapColor(bqb, 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 = chj23.getHeight(Heightmap.Types.WORLD_SURFACE, integer21 + integer17, integer22 + integer18) + 1;
                                            BlockState cfj35;
                                            if (integer23 > 1) {
                                                do {
                                                    --integer23;
                                                    a12.set(bph24.getMinBlockX() + integer21 + integer17, integer23, bph24.getMinBlockZ() + integer22 + integer18);
                                                    cfj35 = chj23.getBlockState(a12);
                                                } while (cfj35.getMapColor(bqb, a12) == MaterialColor.NONE && integer23 > 0);
                                                if (integer23 > 0 && !cfj35.getFluidState().isEmpty()) {
                                                    int integer24 = integer23 - 1;
                                                    a13.set(a12);
                                                    BlockState cfj36;
                                                    do {
                                                        a13.setY(integer24--);
                                                        cfj36 = chj23.getBlockState(a13);
                                                        ++integer19;
                                                    } while (integer24 > 0 && !cfj36.getFluidState().isEmpty());
                                                    cfj35 = this.getCorrectStateForFluidBlock(bqb, cfj35, a12);
                                                }
                                            }
                                            else {
                                                cfj35 = Blocks.BEDROCK.defaultBlockState();
                                            }
                                            czv.checkBanners(bqb, bph24.getMinBlockX() + integer21 + integer17, bph24.getMinBlockZ() + integer22 + integer18);
                                            double15 += integer23 / (double)(integer5 * integer5);
                                            multiset22.add(cfj35.getMapColor(bqb, 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 cxe33 = Iterables.<MaterialColor>getFirst(Multisets.<MaterialColor>copyHighestCountFirst(multiset22), MaterialColor.NONE);
                                if (cxe33 == 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 = czv.colors[integer11 + integer12 * 128];
                                            final byte byte35 = (byte)(cxe33.id * 4 + integer21);
                                            if (byte34 != byte35) {
                                                czv.colors[integer11 + integer12 * 128] = byte35;
                                                czv.setDirty(integer11, integer12);
                                                boolean12 = true;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    
    private BlockState getCorrectStateForFluidBlock(final Level bqb, final BlockState cfj, final BlockPos fu) {
        final FluidState cxa5 = cfj.getFluidState();
        if (!cxa5.isEmpty() && !cfj.isFaceSturdy(bqb, fu, Direction.UP)) {
            return cxa5.createLegacyBlock();
        }
        return cfj;
    }
    
    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 zd, final ItemStack bki) {
        final MapItemSavedData czv3 = getOrCreateSavedData(bki, zd);
        if (czv3 == null) {
            return;
        }
        if (zd.dimension() != czv3.dimension) {
            return;
        }
        final int integer4 = 1 << czv3.scale;
        final int integer5 = czv3.x;
        final int integer6 = czv3.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] = zd.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 bre10 = 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 cxe13 = MaterialColor.NONE;
                    if (bre10.getDepth() < 0.0f) {
                        cxe13 = 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) {
                            cxe13 = MaterialColor.NONE;
                        }
                        else if (integer9 > 5) {
                            integer10 = 1;
                        }
                        else if (integer9 > 3) {
                            integer10 = 0;
                        }
                        else if (integer9 > 1) {
                            integer10 = 0;
                        }
                    }
                    else if (integer9 > 0) {
                        cxe13 = MaterialColor.COLOR_BROWN;
                        if (integer9 > 3) {
                            integer10 = 1;
                        }
                        else {
                            integer10 = 3;
                        }
                    }
                    if (cxe13 != MaterialColor.NONE) {
                        czv3.colors[integer7 + integer8 * 128] = (byte)(cxe13.id * 4 + integer10);
                        czv3.setDirty(integer7, integer8);
                    }
                }
            }
        }
    }
    
    @Override
    public void inventoryTick(final ItemStack bki, final Level bqb, final Entity aom, final int integer, final boolean boolean5) {
        if (bqb.isClientSide) {
            return;
        }
        final MapItemSavedData czv7 = getOrCreateSavedData(bki, bqb);
        if (czv7 == null) {
            return;
        }
        if (aom instanceof Player) {
            final Player bec8 = (Player)aom;
            czv7.tickCarriedBy(bec8, bki);
        }
        if (!czv7.locked && (boolean5 || (aom instanceof Player && ((Player)aom).getOffhandItem() == bki))) {
            this.update(bqb, aom, czv7);
        }
    }
    
    @Nullable
    @Override
    public Packet<?> getUpdatePacket(final ItemStack bki, final Level bqb, final Player bec) {
        return getOrCreateSavedData(bki, bqb).getUpdatePacket(bki, bqb, bec);
    }
    
    @Override
    public void onCraftedBy(final ItemStack bki, final Level bqb, final Player bec) {
        final CompoundTag le5 = bki.getTag();
        if (le5 != null && le5.contains("map_scale_direction", 99)) {
            scaleMap(bki, bqb, le5.getInt("map_scale_direction"));
            le5.remove("map_scale_direction");
        }
    }
    
    protected static void scaleMap(final ItemStack bki, final Level bqb, final int integer) {
        final MapItemSavedData czv4 = getOrCreateSavedData(bki, bqb);
        if (czv4 != null) {
            createAndStoreSavedData(bki, bqb, czv4.x, czv4.z, Mth.clamp(czv4.scale + integer, 0, 4), czv4.trackingPosition, czv4.unlimitedTracking, czv4.dimension);
        }
    }
    
    @Nullable
    public static ItemStack lockMap(final Level bqb, final ItemStack bki) {
        final MapItemSavedData czv3 = getOrCreateSavedData(bki, bqb);
        if (czv3 != null) {
            final ItemStack bki2 = bki.copy();
            final MapItemSavedData czv4 = createAndStoreSavedData(bki2, bqb, 0, 0, czv3.scale, czv3.trackingPosition, czv3.unlimitedTracking, czv3.dimension);
            czv4.lockData(czv3);
            return bki2;
        }
        return null;
    }
    
    @Override
    public void appendHoverText(final ItemStack bki, @Nullable final Level bqb, final List<Component> list, final TooltipFlag bls) {
        final MapItemSavedData czv6 = (bqb == null) ? null : getOrCreateSavedData(bki, bqb);
        if (czv6 != null && czv6.locked) {
            list.add(new TranslatableComponent("filled_map.locked", new Object[] { getMapId(bki) }).withStyle(ChatFormatting.GRAY));
        }
        if (bls.isAdvanced()) {
            if (czv6 != null) {
                list.add(new TranslatableComponent("filled_map.id", new Object[] { getMapId(bki) }).withStyle(ChatFormatting.GRAY));
                list.add(new TranslatableComponent("filled_map.scale", new Object[] { 1 << czv6.scale }).withStyle(ChatFormatting.GRAY));
                list.add(new TranslatableComponent("filled_map.level", new Object[] { czv6.scale, 4 }).withStyle(ChatFormatting.GRAY));
            }
            else {
                list.add(new TranslatableComponent("filled_map.unknown").withStyle(ChatFormatting.GRAY));
            }
        }
    }
    
    public static int getColor(final ItemStack bki) {
        final CompoundTag le2 = bki.getTagElement("display");
        if (le2 != null && le2.contains("MapColor", 99)) {
            final int integer3 = le2.getInt("MapColor");
            return 0xFF000000 | (integer3 & 0xFFFFFF);
        }
        return -12173266;
    }
    
    @Override
    public InteractionResult useOn(final UseOnContext blv) {
        final BlockState cfj3 = blv.getLevel().getBlockState(blv.getClickedPos());
        if (cfj3.is(BlockTags.BANNERS)) {
            if (!blv.level.isClientSide) {
                final MapItemSavedData czv4 = getOrCreateSavedData(blv.getItemInHand(), blv.getLevel());
                czv4.toggleBanner(blv.getLevel(), blv.getClickedPos());
            }
            return InteractionResult.sidedSuccess(blv.level.isClientSide);
        }
        return super.useOn(blv);
    }
}
