package zenith.zov.utility.game.server;

import com.darkmagician6.eventapi.EventManager;
import com.darkmagician6.eventapi.EventTarget;
import lombok.Generated;
import net.minecraft.network.packet.c2s.play.ClientCommandC2SPacket;
import net.minecraft.network.packet.c2s.play.ClientCommandC2SPacket.Mode;
import net.minecraft.network.packet.s2c.play.WorldTimeUpdateS2CPacket;
import net.minecraft.scoreboard.Scoreboard;
import net.minecraft.scoreboard.ScoreboardDisplaySlot;
import net.minecraft.scoreboard.ScoreboardEntry;
import net.minecraft.scoreboard.ScoreboardObjective;
import net.minecraft.scoreboard.Team;
import net.minecraft.util.math.MathHelper;
import org.apache.commons.lang3.StringUtils;
import zenith.zov.base.events.impl.player.EventUpdate;
import zenith.zov.base.events.impl.server.EventPacket;
import zenith.zov.utility.game.player.PlayerIntersectionUtil;
import zenith.zov.utility.interfaces.IMinecraft;
import zenith.zov.utility.math.Timer;

public class ServerHandler implements IMinecraft {
    private final Timer pvpWatch = new Timer();
    private String server = "Vanilla";
    private float TPS = 20.0F;
    private long timestamp;
    private boolean serverSprint;
    private int anarchy;
    private boolean pvpEnd;

    public ServerHandler() {
        EventManager.register(this);
    }

    @EventTarget
    public void tick(EventUpdate eventUpdate) {
        this.anarchy = this.getAnarchyMode();
        this.server = this.updateServer();
        this.pvpEnd = this.inPvpEnd();
        if (this.inPvp()) {
            this.pvpWatch.reset();
        }
    }

    @EventTarget
    public void packet(EventPacket e) {
        if (e.getPacket() instanceof WorldTimeUpdateS2CPacket) {
            long nanoTime = System.nanoTime();
            float maxTPS = 20.0F;
            float rawTPS = maxTPS * (1.0E9F / (float)(nanoTime - this.timestamp));
            this.TPS = MathHelper.clamp(rawTPS, 0.0F, maxTPS);
            this.timestamp = nanoTime;
        }
    }

    @EventTarget
    public void onPacket(EventPacket e) {
        if (e.getPacket() instanceof ClientCommandC2SPacket command) {
            if (command.getMode().equals(Mode.START_SPRINTING)) {
                e.setCancelled(this.serverSprint);
                this.serverSprint = true;
            } else if (command.getMode().equals(Mode.STOP_SPRINTING)) {
                e.setCancelled(!this.serverSprint);
                this.serverSprint = false;
            }
        }
    }

    private String updateServer() {
        if (!PlayerIntersectionUtil.nullCheck()
            && mc.getNetworkHandler() != null
            && mc.getNetworkHandler().getServerInfo() != null
            && mc.getNetworkHandler().getBrand() != null) {
            String serverIp = mc.getNetworkHandler().getServerInfo().address.toLowerCase();
            String brand = mc.getNetworkHandler().getBrand().toLowerCase();
            if (brand.contains("botfilter")) {
                return "FunTime";
            } else if (serverIp.contains("funtime") || serverIp.contains("skytime") || serverIp.contains("space-times") || serverIp.contains("funsky")) {
                return "CopyTime";
            } else if (brand.contains("holyworld") || brand.contains("leaf") || brand.contains("vk.com/idwok")) {
                return "HolyWorld";
            } else {
                return serverIp.contains("reallyworld") ? "ReallyWorld" : "Vanilla";
            }
        } else {
            return "Vanilla";
        }
    }

    private int getAnarchyMode() {
        Scoreboard scoreboard = mc.world.getScoreboard();
        ScoreboardObjective objective = scoreboard.getObjectiveForSlot(ScoreboardDisplaySlot.SIDEBAR);
        String var3 = this.server;
        switch (var3) {
            case "FunTime":
                if (objective != null) {
                    String[] string = objective.getDisplayName().getString().split("-");
                    if (string.length > 1) {
                        return Integer.parseInt(string[1]);
                    }
                }
                break;
            case "HolyWorld":
                for (ScoreboardEntry scoreboardEntry : scoreboard.getScoreboardEntries(objective)) {
                    String text = Team.decorateName(scoreboard.getScoreHolderTeam(scoreboardEntry.owner()), scoreboardEntry.name()).getString();
                    if (!text.isEmpty()) {
                        String string = StringUtils.substringBetween(text, "#", " -◆-");
                        if (string != null && !string.isEmpty()) {
                            return Integer.parseInt(string);
                        }
                    }
                }
        }

        return -1;
    }

    public boolean isPvp() {
        return !this.pvpWatch.finished(250L);
    }

    private boolean inPvp() {
        return mc.inGameHud.getBossBarHud().bossBars.values().stream().map(c -> c.getName().getString().toLowerCase()).anyMatch(s -> s.contains("pvp"));
    }

    private boolean inPvpEnd() {
        return mc.inGameHud
            .getBossBarHud()
            .bossBars
            .values()
            .stream()
            .map(c -> c.getName().getString().toLowerCase())
            .anyMatch(s -> s.contains("pvp") && (s.contains("0") || s.contains("1")));
    }

    public String getWorldType() {
        return mc.world.getRegistryKey().getValue().getPath();
    }

    public boolean isCopyTime() {
        return this.server.equals("CopyTime") || this.server.equals("SpookyTime") || this.server.equals("FunTime");
    }

    public boolean isFunTime() {
        return this.server.equals("FunTime");
    }

    public boolean isReallyWorld() {
        return this.server.equals("ReallyWorld");
    }

    public boolean isHolyWorld() {
        return this.server.equals("HolyWorld");
    }

    public boolean isVanilla() {
        return this.server.equals("Vanilla");
    }

    @Generated
    public Timer getPvpWatch() {
        return this.pvpWatch;
    }

    @Generated
    public String getServer() {
        return this.server;
    }

    @Generated
    public float getTPS() {
        return this.TPS;
    }

    @Generated
    public long getTimestamp() {
        return this.timestamp;
    }

    @Generated
    public boolean isServerSprint() {
        return this.serverSprint;
    }

    @Generated
    public int getAnarchy() {
        return this.anarchy;
    }

    @Generated
    public boolean isPvpEnd() {
        return this.pvpEnd;
    }
}
