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

import java.util.LinkedHashSet;
import java.util.Objects;
import net.minecraft.client.gui.screen.ChatScreen;
import zenith.zov.Zenith;
import zenith.zov.base.animations.base.Animation;
import zenith.zov.base.animations.base.Easing;
import zenith.zov.base.font.Font;
import zenith.zov.base.font.Fonts;
import zenith.zov.base.theme.Theme;
import zenith.zov.client.hud.elements.draggable.DraggableHudElement;
import zenith.zov.client.modules.api.Module;
import zenith.zov.utility.render.display.Keyboard;
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 KeybindsComponent extends DraggableHudElement {
    private final LinkedHashSet<KeybindsComponent.KeyModule> keyModules = new LinkedHashSet<>();
    private final Animation animationWidth = new Animation(200L, 100.0F, Easing.QUAD_IN_OUT);
    private final Animation animationScale = new Animation(200L, 0.0F, Easing.QUAD_IN_OUT);
    private final Animation animationVisible = new Animation(200L, 0.0F, Easing.QUAD_IN_OUT);

    public KeybindsComponent(
        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) {
        Font iconFont = Fonts.ICONS.getFont(6.0F);
        Zenith.getInstance().getModuleManager().getActiveModules().forEach(module -> {
            if (module.getKeyCode() != -1 && !this.keyModules.contains(new KeybindsComponent.KeyModule(module))) {
                this.keyModules.addLast(new KeybindsComponent.KeyModule(module));
            }
        });
        this.keyModules.removeIf(kmx -> (!kmx.module.isEnabled() || kmx.module.getKeyCode() == -1) && kmx.isDelete());
        if (this.keyModules.isEmpty()) {
            this.animationScale.update(0.0F);
        } else {
            this.animationScale.update(this.keyModules.size() == 1 && this.keyModules.getFirst().animation.getTargetValue() == 0.0F ? 0.0F : 1.0F);
        }

        float x = this.x;
        float y = this.y;
        float thickness = 1.5F;
        float height = (float)(18.0 + this.keyModules.stream().mapToDouble(key -> (double)key.getHeight()).sum());
        float width = (float)this.keyModules.stream().mapToDouble(KeybindsComponent.KeyModule::updateWidth).max().orElse(100.0);
        width = this.animationWidth.update(width);
        this.width = width;
        this.height = height;
        this.animationVisible.update(mc.currentScreen instanceof ChatScreen || !this.keyModules.isEmpty());
        Theme theme = Zenith.getInstance().getThemeManager().getCurrentTheme();
        ctx.pushMatrix();
        ctx.getMatrices().translate(x + width / 2.0F, y + height / 2.0F, 0.0F);
        ctx.getMatrices().scale(this.animationVisible.getValue(), this.animationVisible.getValue(), 1.0F);
        ctx.getMatrices().translate(-(x + width / 2.0F), -(y + height / 2.0F), 0.0F);
        BorderRadius radius6 = BorderRadius.all(6.0F);
        DrawUtil.drawBlurHud(ctx.getMatrices(), x, y, width, height, 21.0F, BorderRadius.all(4.0F), ColorRGBA.WHITE);
        ctx.drawRoundedRect(x, y, width, height, radius6, theme.getForegroundLight());
        ctx.drawText(iconFont, "L", x + 8.0F, y + (18.0F - iconFont.height()) / 2.0F, theme.getColor());
        ctx.drawText(iconFont, "M", x + width - 8.0F - iconFont.width("M"), y + (18.0F - iconFont.height()) / 2.0F, theme.getWhiteGray());
        Font font = Fonts.MEDIUM.getFont(6.0F);
        ctx.drawText(font, "Keybinds", x + 8.0F + 8.0F + 2.0F, y + (18.0F - font.height()) / 2.0F, theme.getWhite());
        if (this.animationVisible.getValue() == 1.0F) {
            float kmY = y + 18.0F;
            int i = 0;
            ctx.enableScissor((int)x, (int)y, (int)(x + width), (int)(y + height));

            for (KeybindsComponent.KeyModule km : this.keyModules) {
                km.render(ctx, x, kmY, width, i);
                kmY += km.getHeight();
                i++;
            }

            ctx.disableScissor();
        }

        ctx.drawRoundedBorder(x, y, width, height, 0.1F, BorderRadius.all(4.0F), theme.getForegroundStroke());
        DrawUtil.drawRoundedCorner(
            ctx.getMatrices(), x, y, width, height, 0.1F, Math.min(20.0F, Math.max(12.0F, height / 2.5F)), theme.getColor(), BorderRadius.all(4.0F)
        );
        ctx.popMatrix();
    }

    class KeyModule implements Comparable<KeybindsComponent.KeyModule> {
        private final Animation animation = new Animation(150L, Easing.QUAD_IN_OUT);
        private final Animation animationColor = new Animation(200L, Easing.QUAD_IN_OUT);
        private final Module module;
        private float width;

        public KeyModule(Module module) {
            this.module = module;
        }

        public float updateWidth() {
            float width = 100.0F;
            float moduleTextWidth = Fonts.MEDIUM.getWidth(this.module.getName(), 6.0F);
            float sizeBind = (float)Math.round(Fonts.MEDIUM.getWidth(Keyboard.getKeyName(this.module.getKeyCode()), 6.0F));
            float keyTextWidth = 24.0F + sizeBind;
            float widthText = width - (keyTextWidth + 8.0F);
            if (widthText < 8.0F + moduleTextWidth + 8.0F) {
                float deltaWidth = moduleTextWidth + 8.0F + 8.0F - widthText;
                width += deltaWidth;
            }

            return width;
        }

        public float getHeight() {
            return 18.0F * this.animation.getValue();
        }

        public void render(CustomDrawContext ctx, float x, float y, float width, int i) {
            Theme theme = Zenith.getInstance().getThemeManager().getCurrentTheme();
            Font iconFont = Fonts.ICONS.getFont(6.0F);
            Font font = Fonts.MEDIUM.getFont(6.0F);
            this.animation.update(this.module.isEnabled() && this.module.getKeyCode() != -1 ? 1.0F : 0.0F);
            ctx.pushMatrix();
            ctx.getMatrices().translate(x + width / 2.0F, y + 9.0F, 0.0F);
            float deltaANim = this.animation.getValue();
            ctx.getMatrices().scale(deltaANim, deltaANim, 1.0F);
            ctx.getMatrices().translate(-(x + width / 2.0F), -(y + 9.0F), 0.0F);
            float sizeBind = (float)Math.round(Fonts.MEDIUM.getWidth(Keyboard.getKeyName(this.module.getKeyCode()), 6.0F));
            float keyTextWidth = 8.0F + sizeBind;
            float widthText = width - (keyTextWidth + 10.0F + 5.0F + 10.0F);
            this.animationColor.update(i % 2 == 0 ? 1.0F : 0.0F);
            ColorRGBA backgroundColor = theme.getForegroundLight().mix(theme.getForegroundColor(), this.animationColor.getValue());
            ctx.drawRoundedRect(
                x, y, width, 18.0F, i == KeybindsComponent.this.keyModules.size() - 1 ? BorderRadius.bottom(4.0F, 4.0F) : BorderRadius.ZERO, backgroundColor
            );
            ctx.drawText(iconFont, this.module.getCategory().getIcon(), x + 8.0F, y + (18.0F - iconFont.height()) / 2.0F, theme.getColor());
            ctx.drawText(font, this.module.getName(), x + 8.0F + 8.0F + 8.0F, y + (18.0F - font.height()) / 2.0F, theme.getWhite());
            ctx.drawText(Fonts.BOLD.getFont(8.0F), ".", x + 8.0F + 8.0F + 2.0F, y + 4.0F, theme.getWhiteGray());
            ctx.drawText(font, Keyboard.getKeyName(this.module.getKeyCode()), x + width - keyTextWidth, y + (18.0F - font.height()) / 2.0F, theme.getColor());
            ctx.popMatrix();
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            } else if (obj != null && this.getClass() == obj.getClass()) {
                KeybindsComponent.KeyModule keyModule = (KeybindsComponent.KeyModule)obj;
                return Objects.equals(this.module.getName(), keyModule.module.getName());
            } else {
                return false;
            }
        }

        public boolean isDelete() {
            return this.animation.getValue() == 0.0F;
        }

        @Override
        public int hashCode() {
            return Objects.hash(this.module);
        }

        public int compareTo(KeybindsComponent.KeyModule o) {
            return this.module.getName().compareTo(o.module.getName());
        }
    }
}
