#pragma once
#include "Font.h"
#include <glm/glm.hpp>
#include <string>
#include <vector>
#include <functional>
#include <algorithm>

// Immediate-mode HUD builder.
//
//   Hud hud(font, width, height);
//   hud.beginPanel(10, 10, 320, 120, {0,0,0,0.55f});
//       hud.label("Title", 16, {1,1,1});
//       hud.bar(200, 14, 0.72f, {0.1f,0.6f,0.2f,1}, {1,1,1,0.2f});
//       hud.label("72% throughput", 12, {0.9f,0.95f,0.9f});
//   hud.endPanel();
//   hud.flush();
//
// Panels are stacked rectangles with translucent backgrounds + optional
// borders. Widgets inside flow top-down from the panel's top, padded by
// `padding`. The font handles text rendering; the Hud draws its own rects
// via the font's fillRect/strokeRect helpers.

class Hud {
public:
    Hud(Font& font, int screen_w, int screen_h)
      : font_(font), w_(screen_w), h_(screen_h) {}

    // --- Panel stacking ---------------------------------------------------
    void beginPanel(float x, float y, float w, float h,
                    const glm::vec4& bg = glm::vec4(0, 0, 0, 0.55f),
                    const glm::vec4& border = glm::vec4(1, 1, 1, 0.0f),
                    float border_thickness = 1.0f) {
        Panel p{x, y, w, h, x + padding_, y + h - padding_ - 16.0f, bg, border, border_thickness};
        panels_.push_back(p);
    }
    void endPanel() {
        if (!panels_.empty()) {
            // Defer the actual draw so text is drawn on top of backgrounds in
            // the right order. For simplicity, draw bg now, widgets are already
            // placed, border last.
            panels_.pop_back();
        }
    }

    // --- Widgets ----------------------------------------------------------
    void label(const std::string& text, float size = 14.0f,
               const glm::vec3& color = glm::vec3(1.0f),
               bool outlined = false) {
        if (panels_.empty()) return;
        Panel& p = panels_.back();
        float y = p.cursor_y;
        draws_.push_back([this, text, p_x = p.cursor_x, y, size, color, outlined]() {
            if (outlined) font_.drawOutlinedText(text, p_x, y, size, color);
            else          font_.drawText(text, p_x, y, size, color);
        });
        p.cursor_y -= (size + 4.0f);
    }

    void labelRight(const std::string& text, float size,
                    const glm::vec3& color = glm::vec3(1.0f)) {
        if (panels_.empty()) return;
        Panel& p = panels_.back();
        float right = p.x + p.w - padding_;
        float y = p.cursor_y;
        draws_.push_back([this, text, right, y, size, color]() {
            font_.drawTextRight(text, right, y, size, color);
        });
        p.cursor_y -= (size + 4.0f);
    }

    // Progress bar: value in [0,1]. Width spans the panel minus padding.
    void bar(float height, float value,
             const glm::vec4& fill = glm::vec4(0.2f, 0.7f, 0.3f, 1.0f),
             const glm::vec4& bg   = glm::vec4(1.0f, 1.0f, 1.0f, 0.15f),
             const glm::vec4& border_ = glm::vec4(1.0f, 1.0f, 1.0f, 0.35f)) {
        if (panels_.empty()) return;
        Panel& p = panels_.back();
        float x = p.cursor_x;
        float y = p.cursor_y - height + 10.0f;
        float w = p.w - 2 * padding_;
        float v = std::clamp(value, 0.0f, 1.0f);
        draws_.push_back([this, x, y, w, height, v, fill, bg, border_]() {
            font_.fillRect(x, y, w, height, bg);
            font_.fillRect(x, y, w * v, height, fill);
            font_.strokeRect(x, y, w, height, border_, 1.0f);
        });
        p.cursor_y -= (height + 6.0f);
    }

    // Colored icon: solid rounded rect
    void icon(float w_icon, float h_icon, const glm::vec4& col) {
        if (panels_.empty()) return;
        Panel& p = panels_.back();
        float x = p.cursor_x;
        float y = p.cursor_y - h_icon + 10.0f;
        draws_.push_back([this, x, y, w_icon, h_icon, col]() {
            font_.fillRect(x, y, w_icon, h_icon, col);
        });
        p.cursor_y -= (h_icon + 4.0f);
    }

    // Horizontal separator line
    void separator(float thickness = 1.0f,
                   const glm::vec4& col = glm::vec4(1, 1, 1, 0.25f)) {
        if (panels_.empty()) return;
        Panel& p = panels_.back();
        float x = p.cursor_x;
        float y = p.cursor_y + 6.0f;
        float w = p.w - 2 * padding_;
        draws_.push_back([this, x, y, w, thickness, col]() {
            font_.fillRect(x, y, w, thickness, col);
        });
        p.cursor_y -= (thickness + 6.0f);
    }

    void spacer(float h = 4.0f) {
        if (panels_.empty()) return;
        panels_.back().cursor_y -= h;
    }

    // --- Free-form (outside panels) ---------------------------------------
    void rect(float x, float y, float w, float h, const glm::vec4& col) {
        draws_.push_back([this, x, y, w, h, col]() { font_.fillRect(x, y, w, h, col); });
    }
    void text(float x, float y, const std::string& t, float size,
              const glm::vec3& col, bool outlined = false) {
        draws_.push_back([this, x, y, t, size, col, outlined]() {
            if (outlined) font_.drawOutlinedText(t, x, y, size, col);
            else          font_.drawText(t, x, y, size, col);
        });
    }

    // Draw anchored panel background frames then queued widgets in order
    void flush() {
        for (auto& f : bg_draws_) f();
        for (auto& f : draws_)    f();
        for (auto& f : border_draws_) f();
        bg_draws_.clear();
        draws_.clear();
        border_draws_.clear();
        panels_.clear();
    }

    void setPadding(float p) { padding_ = p; }

private:
    struct Panel {
        float x, y, w, h;
        float cursor_x, cursor_y;
        glm::vec4 bg;
        glm::vec4 border;
        float border_t;
    };

    Font& font_;
    int   w_, h_;
    float padding_ = 12.0f;
    std::vector<Panel> panels_;
    std::vector<std::function<void()>> bg_draws_;
    std::vector<std::function<void()>> draws_;
    std::vector<std::function<void()>> border_draws_;

public:
    // Called instead of endPanel() when you want the panel bg drawn into the
    // background layer (so widget draws appear above it).
    void drawPanelBackgroundNow() {
        if (panels_.empty()) return;
        const Panel& p = panels_.back();
        glm::vec4 bg = p.bg, br = p.border;
        float x = p.x, y = p.y, w = p.w, h = p.h;
        float bt = p.border_t;
        if (bg.a > 0.0f) {
            bg_draws_.push_back([this, x, y, w, h, bg]() {
                font_.fillRect(x, y, w, h, bg);
            });
        }
        if (br.a > 0.0f) {
            border_draws_.push_back([this, x, y, w, h, br, bt]() {
                font_.strokeRect(x, y, w, h, br, bt);
            });
        }
    }
};
