#include "draw.h"
#include <SDL3/SDL.h>
#include "gif.h"
#include "jdebug.h"
#include <stdio.h>
#include <stdlib.h>

// Funcions de pintat

namespace draw
{
    SDL_Window *sdl_window;
    SDL_Renderer *sdl_renderer;
    SDL_Texture *sdl_texture;

    Uint32 *palette;
    Uint8 screen[320*240];
    float depth_buffer[320*240];

    void init()
    {
        SDL_Init(SDL_INIT_VIDEO);
        sdl_window = SDL_CreateWindow("WOLF", 640, 480, 0);
        SDL_SetWindowPosition(sdl_window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
        sdl_renderer = SDL_CreateRenderer(sdl_window, NULL);
        sdl_texture = SDL_CreateTexture(sdl_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, 320, 240);
        SDL_SetTextureScaleMode(sdl_texture, SDL_SCALEMODE_NEAREST);
        debug::init(sdl_renderer);
    }

    void cls()
    {
        memset(screen, 0, 320*240);
    }

    surface_t *newsurf(int w, int h)
    {
        surface_t *surf = (surface_t*)malloc(sizeof(surface_t));
        surf->w = w;
        surf->h = h;
        surf->pixels = (uint8_t*)malloc(w*h);
        return surf;
    }

    surface_t *loadgif(const char* filename)
    {
        FILE *f = fopen(filename, "rb");
        fseek(f, 0, SEEK_END);
        int filesize = ftell(f);
        fseek(f, 0, SEEK_SET);
        Uint8 *buffer = (Uint8*)malloc(filesize);
        fread(buffer, filesize, 1, f);
        fclose(f);
        surface_t *surf = (surface_t*)malloc(sizeof(surface_t));
        surf->pixels = LoadGif(buffer, &surf->w, &surf->h);
        free(buffer);
        return surf;
    }

    Uint32 *loadpal(const char* filename)
    {
        FILE *f = fopen(filename, "rb");
        fseek(f, 0, SEEK_END);
        int filesize = ftell(f);
        fseek(f, 0, SEEK_SET);
        Uint8 *buffer = (Uint8*)malloc(filesize);
        fread(buffer, filesize, 1, f);
        fclose(f);
        Uint32 *pal = LoadPalette(buffer);
        free(buffer);
        return pal;
    }

    void setpal(Uint32* pal)
    {
        palette = pal;
    }

    void putp(int x, int y, Uint8 color)
    {
        if (x<0 || y<0 || x>=320 || y>=240) return;
        screen[x+y*320]=color;
    }

    void putpd(int x, int y, Uint8 color, float depth)
    {
        if (x<0 || y<0 || x>=320 || y>=240) return;
        screen[x+y*320]=color;
        depth_buffer[x+y*320]=depth;
    }

    void putps(int x, int y, Uint8 color, float depth)
    {
        if (x<0 || y<0 || x>=320 || y>=240 || color==0) return;
        if (depth_buffer[x+y*320]>=depth)
        {
            screen[x+y*320]=color;
            depth_buffer[x+y*320]=depth;
        }
    }

    Uint8 getp(surface_t *surf, int x, int y)
    {
        return surf->pixels[x+y*surf->w];
    }

    void putpsurf(surface_t *dest, int x, int y, uint8_t color)
    {
        if (x<0 || y<0 || x>=dest->w || y>=dest->h) return;
        dest->pixels[x+y*dest->w] = color;
    }

    void drawsurf(int x, int y, surface_t *src, surface_t *dst)
    {
        int sw = src->w; int dx = x; int sx = 0;
        if (x < 0) { sw = sw+x; sx=-x; dx=0; }
        if (dx+sw > dst->w) sw = dst->w-dx;

        int sh = src->h; int dy = y; int sy = 0;
        if (y < 0) { sh = sh+y; sy=-y; dy=0; }
        if (dy+sh > dst->h) sh = dst->h-dy;

        for (int py=0;py<sh;++py)
            for (int px=0;px<sw;++px)
                dst->pixels[(px+dx)+(py+dy)*dst->w] = src->pixels[(sx+px)+(sy+py)*src->w];
    }

    void line(int x1, int y1, int x2, int y2, Uint8 color)
    {
        float dx = float(x2-x1);
        float dy = float(y2-y1);
        float steps = SDL_max(SDL_fabsf(dx), SDL_fabsf(dy));

        if (steps==0) { putp(x1,y1,color); return; }

        float incx = dx / steps;
        float incy = dy / steps;

        float x = (float)x1;
        float y = (float)y1;

        for (int i=0; i<=int(steps); ++i)
        {
            putp(int(x+0.5f),int(y+0.5f),color);
            x += incx;
            y += incy;
        }

    }

    void render()
    {
        // Send to texture and render
        Uint32 *pixels;
        int pitch;
        SDL_LockTexture(sdl_texture, NULL, (void**)&pixels, &pitch);
        for (int i=0; i<(320*240); ++i)
        {
            pixels[i] = 0xFF000000 | palette[screen[i]];

            // [DEBUG] Visualització del depth buffer
            //pixels[i] = 0xFF000000 | palette[SDL_min(int(depth_buffer[i]),255)];
        }
        SDL_UnlockTexture(sdl_texture);
        SDL_RenderTexture(sdl_renderer, sdl_texture, NULL, NULL);
    }

    void flip()
    {
        SDL_RenderPresent(sdl_renderer);
    }

    namespace map
    {
        float zoom = 8;
        void putp(int x, int y, Uint8 color)
        {
            draw::putp(160+(x/zoom), 120+(y/zoom), color);
        }

        void line(int x1, int y1, int x2, int y2, Uint8 color, int ox, int oy)
        {
            draw::line(160+(x1/zoom)-ox/zoom, 120+(-y1/zoom)+oy/zoom, 160+(x2/zoom)-ox/zoom, 120+(-y2/zoom)+oy/zoom, color);
        }
    }
}