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

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Iterator;
import net.minecraft.client.gui.screen.ChatScreen;
import net.minecraft.text.Text;
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.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 NotifyComponent extends DraggableHudElement {
    private final Animation toggleAnimation = new Animation(200L, Easing.QUAD_IN_OUT);
    private final Deque<NotifyComponent.BaseNotification> notifications = new ArrayDeque<>();

    public NotifyComponent(
        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);
    }

    public void addNotification(Module module, boolean enabled) {
        this.notifications.addLast(new NotifyComponent.ModuleNotification(module, enabled));
    }

    public void addTextNotification(String icon, Text text) {
        this.notifications.addLast(new NotifyComponent.TextNotification(icon, text));
    }

    @Override
    public void render(CustomDrawContext ctx) {
        this.width = 100.0F;
        this.height = 18.0F;
        long now = System.currentTimeMillis();
        Iterator<NotifyComponent.BaseNotification> iterator = this.notifications.iterator();
        this.toggleAnimation.update(mc.currentScreen instanceof ChatScreen && this.notifications.isEmpty());
        Theme theme = Zenith.getInstance().getThemeManager().getCurrentTheme();
        Font textFont = Fonts.MEDIUM.getFont(6.0F);
        Font iconFont = Fonts.ICONS.getFont(6.0F);
        float baseX = this.x;
        float baseY = this.y;
        ctx.pushMatrix();
        ctx.getMatrices().translate(this.x + 50.0F, this.y + 9.0F, 0.0F);
        ctx.getMatrices().scale(this.toggleAnimation.getValue(), this.toggleAnimation.getValue(), 1.0F);
        ctx.getMatrices().translate(-(this.x + 50.0F), -(this.y + 9.0F), 0.0F);
        float notificationHeight = 18.0F;
        DrawUtil.drawBlurHud(ctx.getMatrices(), this.x, this.y, 90.0F, notificationHeight, 21.0F, BorderRadius.all(4.0F), ColorRGBA.WHITE);
        ctx.drawRoundedRect(this.x, this.y, 90.0F, notificationHeight, BorderRadius.all(4.0F), theme.getForegroundColor());
        ctx.drawRoundedRect(this.x, this.y, 16.0F, notificationHeight, BorderRadius.left(4.0F, 4.0F), theme.getForegroundLight());
        DrawUtil.drawRoundedCorner(ctx.getMatrices(), this.x, this.y, 90.0F, notificationHeight, 0.1F, 14.0F, theme.getColor(), BorderRadius.all(4.0F));
        ctx.drawText(
            iconFont, "A", this.x + (16.0F - iconFont.width("A")) / 2.0F + 1.0F, this.y + (notificationHeight - iconFont.height()) / 2.0F, theme.getColor()
        );
        ctx.drawText(textFont, "Example notification", this.x + 16.0F + 4.0F, this.y + (18.0F - textFont.height()) / 2.0F, theme.getWhite());
        baseY += (notificationHeight + 6.0F) * this.toggleAnimation.getValue();
        ctx.popMatrix();

        for (NotifyComponent.BaseNotification n : this.notifications) {
            float gap = 6.0F;
            float offset = n.offsetAnimation.getValue() * (notificationHeight + gap);
            if (offset < 100.0F) {
                n.render(ctx, baseX, baseY + offset, textFont, theme, notificationHeight, this);
            } else {
                n.timestamp = System.currentTimeMillis();
            }
        }

        int index = 0;

        while (iterator.hasNext()) {
            NotifyComponent.BaseNotification nx = iterator.next();
            if (!nx.fadingOut && now - nx.timestamp > 1500L) {
                nx.fadingOut = true;
                nx.alphaAnimation.update(0.0F);
            }

            if (nx.fadingOut && nx.alphaAnimation.getValue() < 0.01F) {
                iterator.remove();
            } else {
                if (!nx.fadingOut) {
                    if (nx.offsetAnimation.isDone() && nx.offsetAnimation.getValue() == 0.0F) {
                        nx.offsetAnimation.reset((float)index);
                    }

                    nx.offsetAnimation.update((float)index);
                    index++;
                }

                nx.alphaAnimation.update(nx.fadingOut ? 0.0F : 1.0F);
            }
        }
    }

    private abstract static class BaseNotification {
        long timestamp;
        boolean fadingOut = false;
        final Animation offsetAnimation = new Animation(300L, Easing.QUAD_IN_OUT);
        final Animation alphaAnimation = new Animation(300L, Easing.QUAD_IN_OUT);

        abstract void render(CustomDrawContext var1, float var2, float var3, Font var4, Theme var5, float var6, NotifyComponent var7);
    }

    private static class ModuleNotification extends NotifyComponent.BaseNotification {
        final Module module;
        final boolean enabled;

        ModuleNotification(Module module, boolean enabled) {
            this.module = module;
            this.enabled = enabled;
        }

        @Override
        void render(CustomDrawContext ctx, float x, float y, Font textFont, Theme theme, float notificationHeight, NotifyComponent parent) {
            if (this.timestamp == 0L) {
                this.timestamp = System.currentTimeMillis();
            }

            float borderRadius = 4.0F;
            float iconBgWidth = 16.0F;
            ColorRGBA headerBg = theme.getForegroundLight();
            ColorRGBA rowBg = theme.getForegroundColor();
            ColorRGBA primary = this.enabled ? theme.getColor() : theme.getGrayLight();
            ColorRGBA textColor = this.enabled ? theme.getWhite() : theme.getGray();
            String moduleName = this.module.getName();
            String statusText = "  was " + (this.enabled ? "enabled" : "disabled");
            float moduleNameWidth = textFont.width(moduleName);
            float statusTextWidth = textFont.width(statusText);
            float width = iconBgWidth + 4.0F + moduleNameWidth + statusTextWidth + 4.0F;
            parent.height = notificationHeight;
            parent.width = 100.0F;
            x += (100.0F - width) / 2.0F;
            float alpha = this.alphaAnimation.getValue();
            Font iconFont = Fonts.ICONS.getFont(6.0F);
            ctx.getMatrices().push();
            ctx.getMatrices().translate(x + width / 2.0F, y + notificationHeight / 2.0F, 0.0F);
            ctx.getMatrices().scale(alpha, alpha, 1.0F);
            ctx.getMatrices().translate(-(x + width / 2.0F), -(y + notificationHeight / 2.0F), 0.0F);
            DrawUtil.drawBlurHud(ctx.getMatrices(), x, y, width, notificationHeight, 21.0F, BorderRadius.all(borderRadius), ColorRGBA.WHITE);
            ctx.drawRoundedRect(x, y, width, notificationHeight, BorderRadius.all(borderRadius), rowBg);
            ctx.drawRoundedRect(x, y, iconBgWidth, notificationHeight, BorderRadius.left(borderRadius, borderRadius), headerBg);
            String icon = this.module.getCategory().getIcon();
            float iconX = x + (iconBgWidth - iconFont.width(icon)) / 2.0F + 1.0F;
            float iconY = y + (notificationHeight - iconFont.height()) / 2.0F;
            ctx.drawText(iconFont, icon, iconX, iconY, primary);
            float textX = x + iconBgWidth + 4.0F;
            float textY = y + (notificationHeight - textFont.height()) / 2.0F;
            ctx.drawText(textFont, moduleName, textX, textY, primary);
            ctx.drawText(textFont, statusText, textX + moduleNameWidth, textY, textColor);
            ctx.getMatrices().pop();
        }
    }

    private static class TextNotification extends NotifyComponent.BaseNotification {
        final String icon;
        final Text text;

        TextNotification(String icon, Text text) {
            this.icon = icon;
            this.text = text;
        }

        @Override
        void render(CustomDrawContext ctx, float x, float y, Font textFont, Theme theme, float notificationHeight, NotifyComponent parent) {
            if (this.timestamp == 0L) {
                this.timestamp = System.currentTimeMillis();
            }

            float borderRadius = 4.0F;
            float iconBgWidth = 16.0F;
            ColorRGBA headerBg = theme.getForegroundLight();
            ColorRGBA rowBg = theme.getForegroundColor();
            ColorRGBA primary = theme.getColor();
            ColorRGBA textColor = theme.getWhite();
            float contentWidth = textFont.width(this.text);
            float width = iconBgWidth + 4.0F + contentWidth + 4.0F;
            parent.height = notificationHeight;
            parent.width = Math.max(parent.width, 100.0F);
            x += (100.0F - width) / 2.0F;
            float alpha = this.alphaAnimation.getValue();
            Font iconFont = Fonts.ICONS.getFont(6.0F);
            ctx.getMatrices().push();
            ctx.getMatrices().translate(x + width / 2.0F, y + notificationHeight / 2.0F, 0.0F);
            ctx.getMatrices().scale(alpha, alpha, 1.0F);
            ctx.getMatrices().translate(-(x + width / 2.0F), -(y + notificationHeight / 2.0F), 0.0F);
            DrawUtil.drawBlurHud(ctx.getMatrices(), x, y, width, notificationHeight, 21.0F, BorderRadius.all(borderRadius), ColorRGBA.WHITE);
            ctx.drawRoundedRect(x, y, width, notificationHeight, BorderRadius.all(borderRadius), rowBg);
            ctx.drawRoundedRect(x, y, iconBgWidth, notificationHeight, BorderRadius.left(borderRadius, borderRadius), headerBg);
            float iconX = x + (iconBgWidth - iconFont.width(this.icon)) / 2.0F + 1.0F;
            float iconY = y + (notificationHeight - iconFont.height()) / 2.0F;
            ctx.drawText(iconFont, this.icon, iconX, iconY, primary);
            float textX = x + iconBgWidth + 4.0F;
            float textY = y + (notificationHeight - textFont.height()) / 2.0F;
            ctx.drawText(textFont, this.text, textX, textY);
            ctx.getMatrices().pop();
        }
    }
}
