#include "core/rendering/overlay.hpp"

#include <algorithm>
#include <memory>
#include <string>
#include <vector>

#include "core/rendering/menu.hpp"
#include "core/rendering/text.hpp"
#include "game/options.hpp"

namespace Overlay {

    static std::unique_ptr<Text> font_;

    // --- Aspecte de la notificació ---
    static constexpr Uint32 NOTIF_BG_COLOR = 0xFF2E1A1A;    // Fons blau fosc (ABGR)
    static constexpr Uint32 NOTIF_TEXT_COLOR = 0xFFFFFF00;  // Text cyan (ABGR)
    static constexpr int NOTIF_PADDING_H = 8;               // Padding horitzontal (esquerra/dreta dins la caixa)
    static constexpr int NOTIF_PADDING_V = 4;               // Padding vertical (dalt/baix dins la caixa)
    static constexpr int NOTIF_MARGIN_X = 4;                // Offset des de la vora esquerra de la pantalla
    static constexpr int NOTIF_MARGIN_Y = 4;                // Offset des de la vora superior de la pantalla

    // --- Animació ---
    static constexpr float SLIDE_SPEED = 4.0F;  // Velocitat de l'animació (unitats/segon)

    // --- Pantalla ---
    static constexpr int SCREEN_W = 320;
    static constexpr int SCREEN_H = 200;

    // --- Estat de les notificacions ---

    enum class Status { RISING,
        STAY,
        VANISHING,
        FINISHED };

    struct Notification {
        std::string message;
        Status status{Status::RISING};
        float anim{0.0F};  // 0 = fora de pantalla, 1 = posició final
        float timer{0.0F};
        float duration{2.0F};
        int box_w{0};  // Ample de la caixa (calculat al crear)
        int box_h{0};  // Alçada de la caixa (calculat al crear)
    };

    static std::vector<Notification> notifications_;
    static Uint32 last_ticks_ = 0;

    // --- Render info ---
    static std::string render_info_text_;

    // --- Doble ESC per a eixir ---
    static bool esc_waiting_ = false;

    void init() {
        font_ = std::make_unique<Text>("fonts/8bithud.fnt", "fonts/8bithud.gif");
        last_ticks_ = SDL_GetTicks();
    }

    void destroy() {
        font_.reset();
        notifications_.clear();
    }

    // Pinta un rectangle sòlid dins els límits de la pantalla
    static void drawRect(Uint32* pixel_data, int rx, int ry, int rw, int rh, Uint32 color) {
        for (int row = ry; row < ry + rh; row++) {
            if (row < 0 || row >= SCREEN_H) continue;
            for (int col = rx; col < rx + rw; col++) {
                if (col < 0 || col >= SCREEN_W) continue;
                pixel_data[col + row * SCREEN_W] = color;
            }
        }
    }

    void render(Uint32* pixel_data) {
        if (!font_ || !pixel_data) return;

        // Calcula delta time
        Uint32 now = SDL_GetTicks();
        float dt = static_cast<float>(now - last_ticks_) / 1000.0F;
        last_ticks_ = now;

        // Actualitza i pinta cada notificació
        for (auto& notif : notifications_) {
            switch (notif.status) {
                case Status::RISING:
                    notif.anim += SLIDE_SPEED * dt;
                    if (notif.anim >= 1.0F) {
                        notif.anim = 1.0F;
                        notif.status = Status::STAY;
                        notif.timer = 0.0F;
                    }
                    break;

                case Status::STAY:
                    notif.timer += dt;
                    if (notif.timer >= notif.duration) {
                        notif.status = Status::VANISHING;
                    }
                    break;

                case Status::VANISHING:
                    notif.anim -= SLIDE_SPEED * dt;
                    if (notif.anim <= 0.0F) {
                        notif.status = Status::FINISHED;
                    }
                    break;

                case Status::FINISHED:
                    break;
            }

            if (notif.status == Status::FINISHED) continue;

            // Posició: entra des de l'esquerra
            int target_x = NOTIF_MARGIN_X;
            int target_y = NOTIF_MARGIN_Y;
            int box_x = target_x - static_cast<int>((1.0F - notif.anim) * (notif.box_w + NOTIF_MARGIN_X));
            int box_y = target_y;

            // Pinta fons de la caixa
            drawRect(pixel_data, box_x, box_y, notif.box_w, notif.box_h, NOTIF_BG_COLOR);

            // Pinta text dins la caixa
            font_->draw(pixel_data, box_x + NOTIF_PADDING_H, box_y + NOTIF_PADDING_V, notif.message.c_str(), NOTIF_TEXT_COLOR);
        }

        // Render info (FPS, driver, shader) — centrat, posició configurable
        if (Options::render_info.position != Options::RenderInfoPosition::OFF && !render_info_text_.empty()) {
            int info_w = font_->width(render_info_text_.c_str());
            int info_x = (SCREEN_W - info_w) / 2;
            int info_y = (Options::render_info.position == Options::RenderInfoPosition::TOP)
                ? 1
                : SCREEN_H - font_->charHeight() - 1;
            // Ombra (1px desplaçat)
            font_->draw(pixel_data, info_x + 1, info_y + 1, render_info_text_.c_str(), Options::render_info.shadow_color);
            // Text
            font_->draw(pixel_data, info_x, info_y, render_info_text_.c_str(), Options::render_info.text_color);
        }

        // Elimina les acabades
        notifications_.erase(
            std::remove_if(notifications_.begin(), notifications_.end(), [](const Notification& n) { return n.status == Status::FINISHED; }),
            notifications_.end());

        // Si la notificació d'ESC ha desaparegut, reseteja l'estat
        if (esc_waiting_ && notifications_.empty()) {
            esc_waiting_ = false;
        }

        // Menú flotant per damunt de tot
        if (Menu::isOpen()) {
            Menu::render(pixel_data);
        }
    }

    void showNotification(const char* text, float duration_seconds) {
        // Reemplaça la notificació anterior
        notifications_.clear();

        Notification notif;
        notif.message = text;
        notif.duration = duration_seconds;
        notif.box_w = font_->width(text) + NOTIF_PADDING_H * 2;
        notif.box_h = font_->charHeight() + NOTIF_PADDING_V * 2;

        notifications_.push_back(notif);
    }

    void toggleRenderInfo() { cycleRenderInfo(+1); }

    void cycleRenderInfo(int dir) {
        // Seqüència: OFF → TOP → BOTTOM → OFF
        int pos = static_cast<int>(Options::render_info.position);
        pos = (pos + (dir >= 0 ? 1 : -1) + 3) % 3;
        Options::render_info.position = static_cast<Options::RenderInfoPosition>(pos);
    }

    void setRenderInfoText(const char* text) {
        render_info_text_ = text;
    }

    auto isEscConsumed() -> bool {
        return esc_waiting_;
    }

    auto handleEscape() -> bool {
        if (!esc_waiting_) {
            // Primera pulsació: mostra avís i consumeix
            esc_waiting_ = true;
            showNotification("TORNA A PULSAR ESC PER EIXIR", 2.0F);
            return true;  // Consumit
        }
        // Segona pulsació: deixa passar
        esc_waiting_ = false;
        return false;
    }

}  // namespace Overlay
