#pragma once

#include <SDL3/SDL.h>

#include <cstdint>
#include <string>
#include <unordered_map>
#include <vector>

class Text {
   public:
    Text(const char* fnt_file, const char* gif_file);

    // Pinta texto sobre un buffer ARGB de 320x200
    void draw(Uint32* pixel_data, int x, int y, const char* text, Uint32 color) const;
    void drawCentered(Uint32* pixel_data, int y, const char* text, Uint32 color) const;
    // Com draw, però clippat a [clip_x_min, clip_x_max) × [clip_y_min, clip_y_max)
    void drawClipped(Uint32* pixel_data, int x, int y, const char* text, Uint32 color, int clip_x_min, int clip_x_max, int clip_y_min, int clip_y_max) const;

    // Dibuixa text monoespaiat: cada glif ocupa `cell_w` i es centra dins la cel·la.
    // Útil per a comptadors (FPS, hora) on cada dígit pot tenir amplades diferents.
    void drawMono(Uint32* pixel_data, int x, int y, const char* text, Uint32 color, int cell_w) const;

    // Mono només per a dígits (0-9): cada dígit ocupa `digit_cell_w` centrat;
    // la resta de glifs mantenen l'amplada natural. Ideal per a comptadors tipus "9:59.59".
    void drawMonoDigits(Uint32* pixel_data, int x, int y, const char* text, Uint32 color, int digit_cell_w) const;

    // Calcula ancho en píxeles d'un text
    [[nodiscard]] auto width(const char* text) const -> int;
    // Amplada mono: nombre de codepoints × cell_w
    [[nodiscard]] static auto widthMono(const char* text, int cell_w) -> int;
    // Amplada mono-dígits: amplada natural, però substituint els dígits per digit_cell_w
    [[nodiscard]] auto widthMonoDigits(const char* text, int digit_cell_w) const -> int;
    [[nodiscard]] auto charHeight() const -> int { return box_height_; }
    [[nodiscard]] auto charBoxWidth() const -> int { return box_width_; }

   private:
    struct GlyphInfo {
        int x, y;  // posició en el bitmap
        int w;     // ample visual
    };

    int box_width_{0};
    int box_height_{0};
    int columns_{0};
    int cell_spacing_{0};
    int row_spacing_{0};

    std::vector<Uint8> bitmap_;  // píxels 8-bit del GIF de la font
    int bitmap_width_{0};
    int bitmap_height_{0};

    std::unordered_map<uint32_t, GlyphInfo> glyphs_;

    static auto nextCodepoint(const char*& ptr) -> uint32_t;

    void loadFont(const char* fnt_file);
    void loadBitmap(const char* gif_file);

    // Resolt un codepoint al GlyphInfo corresponent o al fallback '?'.
    // Retorna nullptr si ni el codepoint ni el fallback existeixen.
    [[nodiscard]] auto resolveGlyph(uint32_t cp) const -> const GlyphInfo*;
    // Pinta un glif a (dst_x, dst_y) amb clipping per finestra.
    // Si la finestra és tota la pantalla, passar clip_x_min=0, clip_x_max=SCREEN_WIDTH, idem y.
    void blitGlyph(Uint32* pixel_data, int dst_x, int dst_y, const GlyphInfo& glyph, Uint32 color, int clip_x_min, int clip_x_max, int clip_y_min, int clip_y_max) const;

    static constexpr int SCREEN_WIDTH = 320;
    static constexpr int SCREEN_HEIGHT = 200;
};
