package zenith.zov.client.hud.elements.component;

import java.util.List;
import java.util.stream.Collectors;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.hud.InGameHud;
import net.minecraft.scoreboard.Scoreboard;
import net.minecraft.scoreboard.ScoreboardDisplaySlot;
import net.minecraft.scoreboard.ScoreboardObjective;
import net.minecraft.scoreboard.Team;
import net.minecraft.scoreboard.number.NumberFormat;
import net.minecraft.scoreboard.number.StyledNumberFormat;
import net.minecraft.text.Text;
import zenith.zov.Zenith;
import zenith.zov.base.theme.Theme;
import zenith.zov.client.hud.elements.draggable.DraggableHudElement;
import zenith.zov.utility.render.display.base.BorderRadius;
import zenith.zov.utility.render.display.base.CustomDrawContext;
import zenith.zov.utility.render.display.base.color.ColorRGBA;
import zenith.zov.utility.render.display.shader.DrawUtil;

public class ScoreBoardComponent extends DraggableHudElement {
    public ScoreBoardComponent(
        String name, float initialX, float initialY, float windowWidth, float windowHeight, float offsetX, float offsetY, DraggableHudElement.Align align
    ) {
        super(name, initialX, initialY, windowWidth, windowHeight, offsetX, offsetY, align);
    }

    @Override
    public void render(CustomDrawContext ctx) {
        Scoreboard scoreboard = mc.world.getScoreboard();
        ScoreboardObjective scoreboardObjective = null;
        Team team = scoreboard.getScoreHolderTeam(mc.player.getNameForScoreboard());
        if (team != null) {
            ScoreboardDisplaySlot scoreboardDisplaySlot = ScoreboardDisplaySlot.fromFormatting(team.getColor());
            if (scoreboardDisplaySlot != null) {
                scoreboardObjective = scoreboard.getObjectiveForSlot(scoreboardDisplaySlot);
            }
        }

        ScoreboardObjective scoreboardObjective2 = scoreboardObjective != null
            ? scoreboardObjective
            : scoreboard.getObjectiveForSlot(ScoreboardDisplaySlot.SIDEBAR);
        if (scoreboardObjective2 != null) {
            this.renderScoreboardSidebar(ctx, scoreboardObjective2);
        }
    }

    private void renderScoreboardSidebar(DrawContext ctx, ScoreboardObjective objective) {
        Scoreboard sb = objective.getScoreboard();
        TextRenderer tr = mc.textRenderer;
        NumberFormat numberFormat = objective.getNumberFormatOr(StyledNumberFormat.RED);
        List<ScoreBoardComponent.SidebarRow> rows = sb.getScoreboardEntries(objective)
            .stream()
            .filter(score -> !score.hidden())
            .sorted(InGameHud.SCOREBOARD_ENTRY_COMPARATOR)
            .limit(15L)
            .map(entry -> {
                Team team = sb.getScoreHolderTeam(entry.owner());
                Text name = Team.decorateName(team, entry.name());
                Text scoreText = entry.formatted(numberFormat);
                int scoreW = tr.getWidth(scoreText);
                return new ScoreBoardComponent.SidebarRow(name, scoreText, scoreW);
            })
            .collect(Collectors.toList());
        Text title = objective.getDisplayName();
        int titleWidth = tr.getWidth(title);
        int colonWidth = tr.getWidth(": ");
        int contentWidth = titleWidth;

        for (ScoreBoardComponent.SidebarRow row : rows) {
            int nameW = tr.getWidth(row.name());
            int rowW = nameW + (row.scoreWidth() > 0 ? colonWidth + row.scoreWidth() : 0);
            contentWidth = Math.max(contentWidth, rowW);
        }

        int count = rows.size();
        int totalHeight = count * 9;
        int headerBaseY = (int)this.y;
        int boxBottomY = headerBaseY + totalHeight + 9;
        int rightMargin = 3;
        int xLeft = (int)(this.x + 2.0F);
        int xRight = (int)(this.x + (float)contentWidth + (float)rightMargin + 1.0F);
        this.width = (float)(contentWidth + rightMargin + 1);
        this.height = (float)(totalHeight + 9);
        int bodyBg = mc.options.getTextBackgroundColor(0.3F);
        int headerBg = mc.options.getTextBackgroundColor(0.4F);
        Theme theme = Zenith.getInstance().getThemeManager().getCurrentTheme();
        if (ctx instanceof CustomDrawContext context) {
            DrawUtil.drawBlurHud(ctx.getMatrices(), this.getX(), this.getY(), this.width, this.height, 21.0F, BorderRadius.all(4.0F), ColorRGBA.WHITE);
            context.drawRoundedRect(this.getX(), (float)headerBaseY, this.width, 14.0F, BorderRadius.top(4.0F, 4.0F), theme.getForegroundLight());
            context.drawRoundedRect(
                this.getX(), (float)(headerBaseY + 14), this.width, this.height - 14.0F, BorderRadius.bottom(4.0F, 4.0F), theme.getForegroundColor()
            );
            DrawUtil.drawRoundedCorner(ctx.getMatrices(), this.x, this.y, this.width, this.height, 0.01F, 20.0F, theme.getColor(), BorderRadius.all(4.0F));
        }

        this.windowResized((float)ctx.getScaledWindowWidth(), (float)ctx.getScaledWindowHeight());
        int titleX = xLeft + contentWidth / 2 - titleWidth / 2;
        ctx.drawText(tr, title, titleX, headerBaseY + 3, -1, false);

        for (int i = 0; i < count; i++) {
            ScoreBoardComponent.SidebarRow row = rows.get(i);
            int y = boxBottomY - (count - i) * 9;
            ctx.drawText(tr, row.name(), xLeft, y, -1, false);
        }
    }

    @Environment(EnvType.CLIENT)
    private static final class SidebarRow {
        private final Text name;
        private final Text score;
        private final int scoreWidth;

        private SidebarRow(Text name, Text score, int scoreWidth) {
            this.name = name;
            this.score = score;
            this.scoreWidth = scoreWidth;
        }

        public Text name() {
            return this.name;
        }

        public Text score() {
            return this.score;
        }

        public int scoreWidth() {
            return this.scoreWidth;
        }
    }
}
