#include "sim_display.h"
#include "graphics.h"
#include <conio.h>

#define    GET_BIT(x, bit)    ((x & (1 << bit)) >> bit)

uint32_t RGB565_to_ARGB8888(uint16_t rgb565, bool isBGR) {
    uint8_t r5 = (rgb565 >> 11) & 0x1F;
    uint8_t g6 = (rgb565 >> 5) & 0x3F;
    uint8_t b5 = rgb565 & 0x1F;

    uint8_t r8 = (r5 * 527 + 23) >> 6;
    uint8_t g8 = (g6 * 259 + 33) >> 6;
    uint8_t b8 = (b5 * 527 + 23) >> 6;

    if (isBGR) {
        return 0xFF000000 | (b8 << 16) | (g8 << 8) | r8;
    } else {
        return 0xFF000000 | (r8 << 16) | (g8 << 8) | b8;
    }
}
#ifndef USER_SDL3
static uint32_t pixelColor, backgroundColor;
static int scaleFactor, w, h;
uint8_t border;

void SIM_Display_INIT(int width, int height, uint32_t pixcolor, uint32_t backcolor, int scale, uint8_t b)
{
    w = width * scale;
    h = height * scale;
    pixelColor = pixcolor;
    backgroundColor = backcolor;
    scaleFactor = scale;
    border = b;
}

void SIM_Display_START()
{
    initgraph(w, h);
    setbkcolor(backgroundColor);
    setfillcolor(pixelColor);
    cleardevice();
}

void SIM_Display_STOP()
{
    closegraph();
}

void drawPixel(int oledX, int oledY)
{
    int startX = oledX * scaleFactor;
    int startY = oledY * scaleFactor;
    if (border) fillrectangle(startX + 1, startY + 1, startX + scaleFactor - 1, startY + scaleFactor - 1);
    else solidrectangle(startX, startY, startX + scaleFactor, startY + scaleFactor);
}


void SIM_OneColor_DrawFromBuffer(uint8_t* buf, uint16_t width, uint16_t height)
{
    BeginBatchDraw();
    cleardevice();
    for (int y = 0; y < height; y++)
    {
        for (int x = 0; x < width; x++)
        {
            uint8_t byteData = buf[y * width + x];
            for (int i = 0; i < 8; i++)
            {
                uint8_t bit = GET_BIT(byteData, i);
                if (bit)drawPixel(x, y * 8 + i);
            }
        }
    }
    EndBatchDraw();
}

void SIM_Color_DrawPiexl(uint32_t buf, uint16_t x, uint16_t y) {
    BeginBatchDraw();
//    cleardevice();
    setfillcolor(buf);
    drawPixel(x, y);
    EndBatchDraw();
}

void SIM_Color_DrawHLineBuffer(uint32_t *buf, uint16_t x, uint16_t y, uint16_t width) {
    BeginBatchDraw();
//    cleardevice();
    for (int x_ = 0; x_ < width; x_++) {
        setfillcolor(*buf);
        drawPixel(x + x_, y);
        buf++;
    }
    EndBatchDraw();
}

void SIM_Color_DrawFromBuffer(uint32_t* buf, uint16_t width, uint16_t height)
{
    BeginBatchDraw();
    cleardevice();
    for (int y = 0; y < height; y++)
    {
        for (int x = 0; x < width; x++)
        {
            setfillcolor(*buf);
            drawPixel(x, y);
            buf++;
        }
    }
    EndBatchDraw();
}

void SIM_Color_ImgFromBuffer(uint32_t* buf, uint16_t x, uint16_t y, uint16_t width, uint16_t height)
{
    BeginBatchDraw();
//    cleardevice();
    for (int y_i = 0; y_i < height; y_i++)
    {
        for (int x_i = 0; x_i < width; x_i++)
        {
            setfillcolor(*buf);
            drawPixel(x + x_i, y + y_i);
            buf++;
        }
    }
    EndBatchDraw();
}

void SIM_Color_FillFromBuffer(uint32_t* buf, uint16_t xs, uint16_t ys, uint16_t xe, uint16_t ye)
{
    BeginBatchDraw();
//    cleardevice();
    for (int y_i = ys; y_i < ye; y_i++)
    {
        for (int x_i = xs; x_i < xe; x_i++)
        {
            setfillcolor(*buf);
            drawPixel(x_i, y_i);
            buf++;
        }
    }
    EndBatchDraw();
}
#else

bool SIM_Display_Init(char *name, int width, int height, uint32_t pixcolor, uint32_t backcolor, int scale,
                      SIM_Display_t *display) {
    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
        SDL_Log("SDL_Init failed: %s", SDL_GetError());
        return false;
    }
    display->scale = scale;
    display->pixelcolor.full = pixcolor;
    display->backcolor.full = backcolor;
    display->window = SDL_CreateWindow(name, width * scale, height * scale, SDL_WINDOW_RESIZABLE);
    if (!display->window) {
        SDL_Log("Could not create a window: %s", SDL_GetError());
        return false;
    }
    SDL_SetWindowPosition(display->window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
    display->renderer = SDL_CreateRenderer(display->window, nullptr);
    if (!display->renderer) {
        SDL_Log("Create renderer failed: %s", SDL_GetError());
        return false;
    }
    SDL_SetRenderDrawColor(display->renderer, 0, 0, 0, 0);
    SDL_RenderClear(display->renderer);
    return true;
}

void SIM_Color_DrawPiexl(SIM_Display_t *display, SIM_Color_t color, uint16_t x, uint16_t y) {
    SDL_SetRenderDrawColor(display->renderer, color.ch.red, color.ch.green, color.ch.blue, color.ch.alpha);
    SDL_FRect rect1 = {(x * display->scale) * 1.0f, (y * display->scale) * 1.0f, display->scale * 1.0f,
                       display->scale * 1.0f};
    SDL_RenderFillRect(display->renderer, &rect1);
//    for (int y_ = y * display->scale; y_ < (y * display->scale) + display->scale; ++y_) {
//        for (int x_ = x * display->scale; x_ < (x * display->scale) + display->scale; ++x_) {
//            SDL_RenderPoint(display->renderer, x_, y_);
//        }
//    }
}

void SIM_OneColor_DrawFromBuffer(SIM_Display_t *display, uint8_t *buf, uint16_t width, uint16_t height) {
    SIM_Color_t color;
    for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
            uint8_t byteData = buf[y * width + x];
            for (int i = 0; i < 8; i++) {
                uint8_t bit = GET_BIT(byteData, i);
                if (bit)color = display->pixelcolor;
                else color = display->backcolor;
                SIM_Color_DrawPiexl(display, color, x, y * 8 + i);
            }
        }
    }
    SDL_RenderPresent(display->renderer);
}


void SIM_Color_ImgFromBuffer(SIM_Display_t *display, uint32_t *buf, uint16_t x, uint16_t y, uint16_t width,
                             uint16_t height) {
    SIM_Color_t color;
    for (int y_i = 0; y_i < height; y_i++) {
        for (int x_i = 0; x_i < width; x_i++) {
            color.full = *buf;
            SIM_Color_DrawPiexl(display, color, x + x_i, y + y_i);
            buf++;
        }
    }
    SDL_RenderPresent(display->renderer);
}

void
SIM_Color_FillFromBuffer(SIM_Display_t *display, uint32_t *buf, uint16_t xs, uint16_t ys, uint16_t xe, uint16_t ye) {
    SIM_Color_t color;
    for (int y_i = ys; y_i <= ye; y_i++) {
        for (int x_i = xs; x_i <= xe; x_i++) {
            color.full = *buf;
            SIM_Color_DrawPiexl(display, color, x_i, y_i);
            buf++;
        }
    }
    SDL_RenderPresent(display->renderer);
}

void SIM_Display_Refresh(SIM_Display_t *display) {
    SDL_RenderPresent(display->renderer);
}

void SIM_Display_STOP(SIM_Display_t *display) {
    SDL_DestroyRenderer(display->renderer);
    SDL_DestroyWindow(display->window);
    SDL_Quit();
}

#endif
