#include "DrawUtils.hpp"

extern uint8_t SmallFont[];
extern uint8_t SevenSegNumFont[];
extern uint8_t BigFont[];

DrawUtils::DrawUtils() : lcd(ILI9341_16, 38, 39, 40, 41) {}

void DrawUtils::initLCD() { lcd.InitLCD(); }

void DrawUtils::changeBackground(uint8_t r, uint8_t g, uint8_t b) {
    lcd.setColor(r, g, b);
    lcd.fillRect(0, 0, 319, 239);
}

void DrawUtils::drawSpriteSimple(int x, int y, int w, int h,
                                 const uint16_t *sprite, float scale) {
    for (int row = 0; row < h; row++) {
        for (int col = 0; col < w; col++) {
            uint16_t color = pgm_read_word(&sprite[row * w + col]);

            if (color == TRANSPARENT)
                continue;

            uint8_t r = (color >> 11) & 0x1F;
            r = (r << 3) | (r >> 2);
            uint8_t g = (color >> 5) & 0x3F;
            g = (g << 2) | (g >> 4);
            uint8_t b = color & 0x1F;
            b = (b << 3) | (b >> 2);

            lcd.setColor(r, g, b);

            int px = x + col * scale;
            int py = y + row * scale;

            if (scale == 1) {
                lcd.drawPixel(px, py);
            } else {
                lcd.fillRect(px, py, px + scale - 1, py + scale - 1);
            }
        }
    }
}

void DrawUtils::moveSprite(int x_old, int y_old, int x_new, int y_new, int w,
                           int h, const uint16_t *sprite, uint16_t bgColor) {
    int min_x = min(x_old, x_new);
    int min_y = min(y_old, y_new);
    int max_x = max(x_old + w, x_new + w);
    int max_y = max(y_old + h, y_new + h);
    for (int y = min_y; y < max_y; y++) {
        for (int x = min_x; x < max_x; x++) {
            int col = x - x_new;
            int row = y - y_new;
            if (col >= 0 && col < w && row >= 0 && row < h) {
                uint16_t color = pgm_read_word(&sprite[row * w + col]);
                if (color != TRANSPARENT) {
                    uint8_t r = (color >> 11) & 0x1F;
                    r = (r << 3) | (r >> 2);
                    uint8_t g = (color >> 5) & 0x3F;
                    g = (g << 2) | (g >> 4);
                    uint8_t b = color & 0x1F;
                    b = (b << 3) | (b >> 2);
                    lcd.setColor(r, g, b);
                    lcd.drawPixel(x, y);
                    continue;
                }
            }
            col = x - x_old;
            row = y - y_old;
            if (col >= 0 && col < w && row >= 0 && row < h) {
                uint16_t color = pgm_read_word(&sprite[row * w + col]);
                if (color != TRANSPARENT) {
                    lcd.setColor(bgColor);
                    lcd.drawPixel(x, y);
                }
            }
        }
    }
}

void DrawUtils::drawBullet(int16_t x, int16_t y, uint16_t color) {
    lcd.setColor(color);
    lcd.fillRect(x, y, x + 5, y + 5);
}

void DrawUtils::eraseEntity(int16_t x, int16_t y, int16_t w, int16_t h) {
    lcd.setColor(0, 0, 0);
    lcd.fillRect(x, y, x + w, y + h);
}

void DrawUtils::drawTextBig(int16_t x, int16_t y, int16_t font_size, char *text,
                            uint16_t color) {
    lcd.setColor(color);
    lcd.setBackColor(VGA_TRANSPARENT);

    lcd.setFont(BigFont);
    lcd.print(text, x, y);
}

void DrawUtils::drawTextSmall(int16_t x, int16_t y, int16_t font_size,
                              char *text, uint16_t color) {
    lcd.setColor(color);
    lcd.setBackColor(VGA_TRANSPARENT);

    lcd.setFont(SmallFont);
    lcd.print(text, x, y);
}

void DrawUtils::drawTextSegs(int16_t x, int16_t y, int16_t font_size,
                             char *text, uint16_t color) {
    lcd.setColor(color);
    lcd.setBackColor(VGA_TRANSPARENT);

    lcd.setFont(SevenSegNumFont);
    lcd.print(text, x, y);
}

void DrawUtils::clearRect(int16_t x, int16_t y, int16_t w, int16_t h) {
    lcd.setColor(0, 0, 0);
    lcd.fillRect(x, y, x + w - 1, y + h - 1);
}
