package net.minecraft.client.renderer.debug;

import javax.annotation.Nullable;
import net.minecraft.world.level.pathfinder.Path;
import net.minecraft.world.entity.Entity;
import com.google.common.collect.Lists;
import net.minecraft.world.entity.player.Player;
import java.util.Objects;
import net.minecraft.util.Mth;
import net.minecraft.client.Camera;
import net.minecraft.core.Position;
import java.util.List;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.function.Function;
import net.minecraft.network.protocol.game.DebugEntityNameGenerator;
import java.util.Iterator;
import java.util.Collection;
import com.google.common.collect.Sets;
import java.util.Set;
import net.minecraft.core.Vec3i;
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.renderer.MultiBufferSource;
import com.mojang.blaze3d.vertex.PoseStack;
import com.google.common.collect.Maps;
import java.util.UUID;
import net.minecraft.core.BlockPos;
import java.util.Map;
import net.minecraft.client.Minecraft;

public class BeeDebugRenderer implements DebugRenderer.SimpleDebugRenderer {
    private final Minecraft minecraft;
    private final Map<BlockPos, HiveInfo> hives;
    private final Map<UUID, BeeInfo> beeInfosPerEntity;
    private UUID lastLookedAtUuid;
    
    public BeeDebugRenderer(final Minecraft dlx) {
        this.hives = Maps.newHashMap();
        this.beeInfosPerEntity = Maps.newHashMap();
        this.minecraft = dlx;
    }
    
    @Override
    public void clear() {
        this.hives.clear();
        this.beeInfosPerEntity.clear();
        this.lastLookedAtUuid = null;
    }
    
    public void addOrUpdateHiveInfo(final HiveInfo b) {
        this.hives.put(b.pos, b);
    }
    
    public void addOrUpdateBeeInfo(final BeeInfo a) {
        this.beeInfosPerEntity.put(a.uuid, a);
    }
    
    @Override
    public void render(final PoseStack dhl, final MultiBufferSource ebz, final double double3, final double double4, final double double5) {
        RenderSystem.pushMatrix();
        RenderSystem.enableBlend();
        RenderSystem.defaultBlendFunc();
        RenderSystem.disableTexture();
        this.clearRemovedHives();
        this.clearRemovedBees();
        this.doRender();
        RenderSystem.enableTexture();
        RenderSystem.disableBlend();
        RenderSystem.popMatrix();
        if (!this.minecraft.player.isSpectator()) {
            this.updateLastLookedAtUuid();
        }
    }
    
    private void clearRemovedBees() {
        this.beeInfosPerEntity.entrySet().removeIf(entry -> this.minecraft.level.getEntity(entry.getValue().id) == null);
    }
    
    private void clearRemovedHives() {
        final long long2 = this.minecraft.level.getGameTime() - 20L;
        this.hives.entrySet().removeIf(entry -> entry.getValue().lastSeen < long2);
    }
    
    private void doRender() {
        final BlockPos fu3 = this.getCamera().getBlockPosition();
        this.beeInfosPerEntity.values().forEach(a -> {
            if (this.isPlayerCloseEnoughToMob(a)) {
                this.renderBeeInfo(a);
            }
            return;
        });
        this.renderFlowerInfos();
        for (final BlockPos fu4 : this.hives.keySet()) {
            if (fu3.closerThan(fu4, 30.0)) {
                highlightHive(fu4);
            }
        }
        final Map<BlockPos, Set<UUID>> map3 = this.createHiveBlacklistMap();
        final Vec3i vec3i;
        final Map<K, Set<UUID>> map4;
        Set<UUID> set5;
        this.hives.values().forEach(b -> {
            if (vec3i.closerThan(b.pos, 30.0)) {
                set5 = map4.get(b.pos);
                this.renderHiveInfo(b, (Collection<UUID>)((set5 == null) ? Sets.newHashSet() : set5));
            }
            return;
        });
        this.getGhostHives().forEach((fu2, list) -> {
            if (fu3.closerThan(fu2, 30.0)) {
                this.renderGhostHive(fu2, list);
            }
        });
    }
    
    private Map<BlockPos, Set<UUID>> createHiveBlacklistMap() {
        final Map<BlockPos, Set<UUID>> map2 = Maps.newHashMap();
        this.beeInfosPerEntity.values().forEach(a -> a.blacklistedHives.forEach(fu -> map2.computeIfAbsent(fu, fu -> Sets.newHashSet()).add(a.getUuid())));
        return map2;
    }
    
    private void renderFlowerInfos() {
        final Map<BlockPos, Set<UUID>> map2 = Maps.newHashMap();
        this.beeInfosPerEntity.values().stream().filter(BeeInfo::hasFlower).forEach(a -> map2.computeIfAbsent(a.flowerPos, fu -> Sets.newHashSet()).add(a.getUuid()));
        final BlockPos fu2;
        final Set<UUID> set3;
        final Set<String> set4;
        int integer5;
        final String string;
        final BlockPos fu3;
        final int integer6;
        final String string2;
        final BlockPos fu4;
        final int integer7;
        final float float6;
        map2.entrySet().forEach(entry -> {
            fu2 = entry.getKey();
            set3 = (Set<UUID>)entry.getValue();
            set4 = set3.stream().map(DebugEntityNameGenerator::getEntityName).collect(Collectors.toSet());
            integer5 = 1;
            set4.toString();
            integer5++;
            renderTextOverPos(string, fu3, integer6, -256);
            integer5++;
            renderTextOverPos(string2, fu4, integer7, -1);
            float6 = 0.05f;
            renderTransparentFilledBox(fu2, 0.05f, 0.8f, 0.8f, 0.0f, 0.3f);
        });
    }
    
    private static String getBeeUuidsAsString(final Collection<UUID> collection) {
        if (collection.isEmpty()) {
            return "-";
        }
        if (collection.size() > 3) {
            return "" + collection.size() + " bees";
        }
        return collection.stream().map(DebugEntityNameGenerator::getEntityName).collect(Collectors.toSet()).toString();
    }
    
    private static void highlightHive(final BlockPos fu) {
        final float float2 = 0.05f;
        renderTransparentFilledBox(fu, 0.05f, 0.2f, 0.2f, 1.0f, 0.3f);
    }
    
    private void renderGhostHive(final BlockPos fu, final List<String> list) {
        final float float4 = 0.05f;
        renderTransparentFilledBox(fu, 0.05f, 0.2f, 0.2f, 1.0f, 0.3f);
        renderTextOverPos("" + list, fu, 0, -256);
        renderTextOverPos("Ghost Hive", fu, 1, -65536);
    }
    
    private static void renderTransparentFilledBox(final BlockPos fu, final float float2, final float float3, final float float4, final float float5, final float float6) {
        RenderSystem.enableBlend();
        RenderSystem.defaultBlendFunc();
        DebugRenderer.renderFilledBox(fu, float2, float3, float4, float5, float6);
    }
    
    private void renderHiveInfo(final HiveInfo b, final Collection<UUID> collection) {
        int integer4 = 0;
        if (!collection.isEmpty()) {
            renderTextOverHive("Blacklisted by " + getBeeUuidsAsString(collection), b, integer4++, -65536);
        }
        renderTextOverHive("Out: " + getBeeUuidsAsString(this.getHiveMembers(b.pos)), b, integer4++, -3355444);
        if (b.occupantCount == 0) {
            renderTextOverHive("In: -", b, integer4++, -256);
        }
        else if (b.occupantCount == 1) {
            renderTextOverHive("In: 1 bee", b, integer4++, -256);
        }
        else {
            renderTextOverHive("In: " + b.occupantCount + " bees", b, integer4++, -256);
        }
        renderTextOverHive("Honey: " + b.honeyLevel, b, integer4++, -23296);
        renderTextOverHive(b.hiveType + (b.sedated ? " (sedated)" : ""), b, integer4++, -1);
    }
    
    private void renderPath(final BeeInfo a) {
        if (a.path != null) {
            PathfindingRenderer.renderPath(a.path, 0.5f, false, false, this.getCamera().getPosition().x(), this.getCamera().getPosition().y(), this.getCamera().getPosition().z());
        }
    }
    
    private void renderBeeInfo(final BeeInfo a) {
        final boolean boolean3 = this.isBeeSelected(a);
        int integer4 = 0;
        renderTextOverMob(a.pos, integer4++, a.toString(), -1, 0.03f);
        if (a.hivePos == null) {
            renderTextOverMob(a.pos, integer4++, "No hive", -98404, 0.02f);
        }
        else {
            renderTextOverMob(a.pos, integer4++, "Hive: " + this.getPosDescription(a, a.hivePos), -256, 0.02f);
        }
        if (a.flowerPos == null) {
            renderTextOverMob(a.pos, integer4++, "No flower", -98404, 0.02f);
        }
        else {
            renderTextOverMob(a.pos, integer4++, "Flower: " + this.getPosDescription(a, a.flowerPos), -256, 0.02f);
        }
        for (final String string6 : a.goals) {
            renderTextOverMob(a.pos, integer4++, string6, -16711936, 0.02f);
        }
        if (boolean3) {
            this.renderPath(a);
        }
        if (a.travelTicks > 0) {
            final int integer5 = (a.travelTicks < 600) ? -3355444 : -23296;
            renderTextOverMob(a.pos, integer4++, "Travelling: " + a.travelTicks + " ticks", integer5, 0.02f);
        }
    }
    
    private static void renderTextOverHive(final String string, final HiveInfo b, final int integer3, final int integer4) {
        final BlockPos fu5 = b.pos;
        renderTextOverPos(string, fu5, integer3, integer4);
    }
    
    private static void renderTextOverPos(final String string, final BlockPos fu, final int integer3, final int integer4) {
        final double double5 = 1.3;
        final double double6 = 0.2;
        final double double7 = fu.getX() + 0.5;
        final double double8 = fu.getY() + 1.3 + integer3 * 0.2;
        final double double9 = fu.getZ() + 0.5;
        DebugRenderer.renderFloatingText(string, double7, double8, double9, integer4, 0.02f, true, 0.0f, true);
    }
    
    private static void renderTextOverMob(final Position gj, final int integer2, final String string, final int integer4, final float float5) {
        final double double6 = 2.4;
        final double double7 = 0.25;
        final BlockPos fu10 = new BlockPos(gj);
        final double double8 = fu10.getX() + 0.5;
        final double double9 = gj.y() + 2.4 + integer2 * 0.25;
        final double double10 = fu10.getZ() + 0.5;
        final float float6 = 0.5f;
        DebugRenderer.renderFloatingText(string, double8, double9, double10, integer4, float5, false, 0.5f, true);
    }
    
    private Camera getCamera() {
        return this.minecraft.gameRenderer.getMainCamera();
    }
    
    private String getPosDescription(final BeeInfo a, final BlockPos fu) {
        final float float4 = Mth.sqrt(fu.distSqr(a.pos.x(), a.pos.y(), a.pos.z(), true));
        final double double5 = Math.round(float4 * 10.0f) / 10.0;
        return fu.toShortString() + " (dist " + double5 + ")";
    }
    
    private boolean isBeeSelected(final BeeInfo a) {
        return Objects.equals(this.lastLookedAtUuid, a.uuid);
    }
    
    private boolean isPlayerCloseEnoughToMob(final BeeInfo a) {
        final Player bec3 = this.minecraft.player;
        final BlockPos fu4 = new BlockPos(bec3.getX(), a.pos.y(), bec3.getZ());
        final BlockPos fu5 = new BlockPos(a.pos);
        return fu4.closerThan(fu5, 30.0);
    }
    
    private Collection<UUID> getHiveMembers(final BlockPos fu) {
        return this.beeInfosPerEntity.values().stream().filter(a -> a.hasHive(fu)).map(BeeInfo::getUuid).collect(Collectors.toSet());
    }
    
    private Map<BlockPos, List<String>> getGhostHives() {
        final Map<BlockPos, List<String>> map2 = Maps.newHashMap();
        for (final BeeInfo a4 : this.beeInfosPerEntity.values()) {
            if (a4.hivePos != null && !this.hives.containsKey(a4.hivePos)) {
                map2.computeIfAbsent(a4.hivePos, fu -> Lists.newArrayList()).add(a4.getName());
            }
        }
        return map2;
    }
    
    private void updateLastLookedAtUuid() {
        DebugRenderer.getTargetedEntity(this.minecraft.getCameraEntity(), 8).ifPresent(aom -> this.lastLookedAtUuid = aom.getUUID());
    }
    
    public static class HiveInfo {
        public final BlockPos pos;
        public final String hiveType;
        public final int occupantCount;
        public final int honeyLevel;
        public final boolean sedated;
        public final long lastSeen;
        
        public HiveInfo(final BlockPos fu, final String string, final int integer3, final int integer4, final boolean boolean5, final long long6) {
            this.pos = fu;
            this.hiveType = string;
            this.occupantCount = integer3;
            this.honeyLevel = integer4;
            this.sedated = boolean5;
            this.lastSeen = long6;
        }
    }
    
    public static class BeeInfo {
        public final UUID uuid;
        public final int id;
        public final Position pos;
        @Nullable
        public final Path path;
        @Nullable
        public final BlockPos hivePos;
        @Nullable
        public final BlockPos flowerPos;
        public final int travelTicks;
        public final List<String> goals;
        public final Set<BlockPos> blacklistedHives;
        
        public BeeInfo(final UUID uUID, final int integer2, final Position gj, final Path czf, final BlockPos fu5, final BlockPos fu6, final int integer7) {
            this.goals = Lists.newArrayList();
            this.blacklistedHives = Sets.newHashSet();
            this.uuid = uUID;
            this.id = integer2;
            this.pos = gj;
            this.path = czf;
            this.hivePos = fu5;
            this.flowerPos = fu6;
            this.travelTicks = integer7;
        }
        
        public boolean hasHive(final BlockPos fu) {
            return this.hivePos != null && this.hivePos.equals(fu);
        }
        
        public UUID getUuid() {
            return this.uuid;
        }
        
        public String getName() {
            return DebugEntityNameGenerator.getEntityName(this.uuid);
        }
        
        @Override
        public String toString() {
            return this.getName();
        }
        
        public boolean hasFlower() {
            return this.flowerPos != null;
        }
    }
}
