#include "render.h"
#include "program.h"
#include "debug.h"
#include <SDL2/SDL_pixels.h>
#include <SDL2/SDL_render.h>

SDL_Renderer* g_renderer;
SDL_Texture* g_render_target;
SDL_Rect g_render_area;
IVector g_render_resolution;

void render_init(SDL_Window* window, const struct ProgramSettings* settings) {
    LOG_INFO("render_init");
    // create renderer, needs to be able to target textures, preferably hardware accelerated
    g_renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
    // create render target texture
    g_render_target = SDL_CreateTexture(
        g_renderer,
        SDL_PIXELFORMAT_ARGB32,
        SDL_TEXTUREACCESS_TARGET,
        settings->view_resolution.x, settings->view_resolution.y);

    // store the desired view resolution
    g_render_resolution = settings->view_resolution;

    // get the destination area for rendering the target onto the window
    render_calculate_render_area();

    // clear target black
    SDL_SetRenderTarget(g_renderer, g_render_target);
    SDL_SetRenderDrawColor(g_renderer, 0, 0, 0, 255);
    SDL_RenderClear(g_renderer);
}

void render_clean() {
    // clear up allocated SDL objects
    SDL_DestroyTexture(g_render_target);
    SDL_DestroyRenderer(g_renderer);
}

void render_present() {
    // clear window white
    SDL_SetRenderTarget(g_renderer, NULL);
    SDL_SetRenderDrawColor(g_renderer, 0, 0, 0, 255);
    SDL_RenderClear(g_renderer);
    // copy render target
    SDL_Rect source_rect = {0, 0, g_render_resolution.x, g_render_resolution.y};
    SDL_RenderCopy(g_renderer, g_render_target, &source_rect, &g_render_area);
    SDL_RenderPresent(g_renderer);
    // clear render target
    SDL_SetRenderTarget(g_renderer, g_render_target);
    SDL_SetRenderDrawColor(g_renderer, 0, 0, 0, 255);
    SDL_RenderClear(g_renderer);
}

void render_calculate_render_area() {
    // get aspect ratios of both the window and the rendertexture
    IVector window_resolution = render_get_window_size();
    float window_aspect = (float)window_resolution.x / (float)window_resolution.y;
    float target_aspect = (float)g_render_resolution.x / (float)g_render_resolution.y;

    // calculate the largest area that will fit the entire rendertexture into the window space
    g_render_area = (SDL_Rect) {0, 0, window_resolution.x, window_resolution.y};
    if(window_aspect <= target_aspect) {
        g_render_area.h = window_resolution.x / target_aspect;
        g_render_area.y = (window_resolution.y - g_render_area.h) / 2;
    } else {
        g_render_area.w = window_resolution.y * target_aspect;
        g_render_area.x += (window_resolution.x - g_render_area.w) / 2;
    }
}

IVector render_get_window_size() {
    // select window as target (store target to reset)
    SDL_Texture* target = SDL_GetRenderTarget(g_renderer);
    SDL_SetRenderTarget(g_renderer, NULL);
    // fetch output size (= window size) of renderer
    int window_width, window_height;
    SDL_GetRendererOutputSize(g_renderer, &window_width, &window_height);
    // reset render target
    SDL_SetRenderTarget(g_renderer, target);
    // construct IVector from fetched output size
    return (IVector){window_width, window_height};
}

void render_handle_resize() {
    render_calculate_render_area();
}
