//
// Created by bruno on 8.2.2025.
//

#include <SDL2/SDL_render.h>
#include "cpustatusui.h"
#include "font.h"

void renderVals(CPU *cpu, BitmapFont *titleFont, BitmapFont *valueFont,
                SDL_Renderer *renderer, SDL_Texture **out) {

    CPUStatusPart *stats = NULL;
    int statsCount = 0;


    getStats(cpu, &stats, &statsCount);

    const int padding = 4;
    const int oneFieldW = (titleFont->size + 1) * (sizeof(stats[0].value)) + padding - 1;
    const int oneFieldH = (titleFont->size + 1) * 2 + (valueFont->size + 1);
    if (!*out) {
        *out = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET,
                                 oneFieldW * statsCount, oneFieldH);
    }

    SDL_SetRenderTarget(renderer, *out);
    SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
    SDL_RenderClear(renderer);

    for (int i = 0; i < statsCount; i++) {
        int x = i * oneFieldW;
        SDL_Rect rect = {x, 0, oneFieldW, oneFieldH};
        SDL_SetRenderDrawColor(renderer, 50, 50, 50, 255);
        SDL_RenderFillRect(renderer, &rect);
        SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
        SDL_RenderDrawRect(renderer, &rect);

        // Render the title
        int textX = x + padding;
        int textY = padding;
        for (int j = 0; j < 6 && stats[i].name[j] != '\0'; j++) {
            SDL_Texture *charTex = titleFont->texture[(uint8_t) stats[i].name[j]];
            if (charTex) {
                SDL_Rect dstRect = {textX, textY, titleFont->size, titleFont->size};
                SDL_RenderCopy(renderer, charTex, NULL, &dstRect);
                textX += titleFont->size;
            }
        }

        // Render the value
        char valueStr[12];
        snprintf(valueStr, sizeof(valueStr), "%u", stats[i].value);
        textX = x + padding;
        textY += titleFont->size + padding;
        for (int j = 0; valueStr[j] != '\0'; j++) {
            SDL_Texture *charTex = valueFont->texture[(uint8_t) valueStr[j]];
            if (charTex) {
                SDL_Rect dstRect = {textX, textY, valueFont->size, valueFont->size};
                SDL_RenderCopy(renderer, charTex, NULL, &dstRect);
                textX += valueFont->size;
            }
        }
    }

    SDL_SetRenderTarget(renderer, NULL);
    free(stats);
}

void getStats(CPU *cpu, CPUStatusPart **cpuStatus, int *cpuStatusCount) {
    if (!cpu || !cpuStatus || !cpuStatusCount) return;

    int count = 5 + REG_COUNT; // PC, SP, FLAGS, MODE, CYCLE + registers

    // Free existing memory if allocated
    if (*cpuStatus) {
        free(*cpuStatus);
        *cpuStatus = NULL;
    }

    // Allocate the required memory
    *cpuStatus = (CPUStatusPart *) malloc(count * sizeof(CPUStatusPart));
    if (!*cpuStatus) return; // Memory allocation failed

    int index = 0;

    strncpy((*cpuStatus)[index].name, "PCNT", sizeof((*cpuStatus)[index].name));
    (*cpuStatus)[index].value = cpu->pc;
    index++;

    strncpy((*cpuStatus)[index].name, "SPTR", sizeof((*cpuStatus)[index].name));
    (*cpuStatus)[index].value = cpu->stack_ptr;
    index++;

    strncpy((*cpuStatus)[index].name, "FLAG", sizeof((*cpuStatus)[index].name));
    (*cpuStatus)[index].value = cpu->flags;
    index++;

    strncpy((*cpuStatus)[index].name, "MODE", sizeof((*cpuStatus)[index].name));
    (*cpuStatus)[index].value = cpu->mode;
    index++;

    strncpy((*cpuStatus)[index].name, "CYCL", sizeof((*cpuStatus)[index].name));
    (*cpuStatus)[index].value = cpu->cycle;
    index++;

    for (int i = 0; i < 18; i++) {
        snprintf((*cpuStatus)[index].name, sizeof((*cpuStatus)[index].name), "R%d", i);
        (*cpuStatus)[index].value = cpu->regs[i];
        index++;
    }

    *cpuStatusCount = index; // Store the actual number of status parts
}

void renderState(CPU *cpu, BitmapFont *titleFont, SDL_Renderer *renderer, SDL_Texture **out) {

    // Render the value
    char valueStr[20] = "";
    if (cpu->mode & CPU_MODE_ERROR) {
        strcat(valueStr, "ERR ");
    } else if (cpu->mode & CPU_MODE_HALTED) {
        strcat(valueStr, "HLT ");
    } else if (cpu->mode & CPU_MODE_PAUSED) {
        strcat(valueStr, "PS ");
    } else {
        strcat(valueStr, "RUN ");
    }

    if (cpu->mode & CPU_MODE_LOOP) {
        strcat(valueStr, "LOOP ");
    } else {
        strcat(valueStr, "ONCE ");
    }

    if (cpu->mode & CPU_MODE_STEP) {
        strcat(valueStr, "STP");
    } else if (cpu->mode & CPU_MODE_SECOND) {
        strcat(valueStr, "SEC");
    } else if (cpu->mode & CPU_MODE_FRAME) {
        strcat(valueStr, "FRM");
    } else {
        strcat(valueStr, "BRR");
    }

    const int oneFieldW = (titleFont->size + 1);
    const int allFieldW = oneFieldW * strlen(valueStr);
    const int oneFieldH = (titleFont->size + 1);
    if (!*out) {
        *out = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET,
                                 allFieldW, oneFieldH);
    }

    SDL_SetRenderTarget(renderer, *out);
    SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
    SDL_RenderClear(renderer);

    SDL_Rect rect = {0, 0, allFieldW, oneFieldH};
    SDL_SetRenderDrawColor(renderer, 50, 50, 50, 255);
    SDL_RenderFillRect(renderer, &rect);


    int x = 0;
    for (int j = 0; valueStr[j] != '\0'; j++) {
        SDL_Texture *charTex = titleFont->texture[(uint8_t) valueStr[j]];
        if (charTex) {
            SDL_Rect dstRect = {x, 0, titleFont->size, titleFont->size};
            x += titleFont->size + 1;
            SDL_RenderCopy(renderer, charTex, NULL, &dstRect);
        }
    }

    SDL_SetRenderTarget(renderer, NULL);
}