#include "pch.h"
#include "Gif.h"

#include "engine/Camera.h"
#include "engine/Engine.h"
#include "gl/ShaderProgram.h"
// #include "engine/Gif.h"
// #include "engine/audio/AudioMixer.h"
#include "gl/Framebuffer.h"
// #include "gl/Shader.h"
// #include "gl/ShaderManager.h"
// #include "gl/WGL.h"

WGif::WGif(std::string_view path) {
	if(WEngine->giflib_instance == nullptr) {
		WEngine->giflib_instance = LoadLibrary("D:\\Programming\\Video Game\\Levwrightian-G-lsd\\out\\x64\\gif.dll");
		
		if (WEngine->giflib_instance == nullptr) {
			std::cerr << "Error loading giflib.dll" << std::endl;
			// TODO: error
			// return 1;
		}
	}
	// this->time = WEngine->time;
		
	int Error;
	GifFileType* gif = DGifOpenFileName(&path[0],&Error);
	Error=DGifSlurp(gif);

	this->width = gif->SWidth;
	this->height = gif->SHeight;
		
	this->interlace = gif->Image.Interlace;
	this->frame_cnt = gif->ImageCount;
		
		
	int indices_byte_len = this->height * this->width * 2 * this->frame_cnt;
	int buff_cols_byte_len = 257 * 4*4;
		
	float* colours_array = new float[buff_cols_byte_len];
	uint8_t* indices_array = new uint8_t[indices_byte_len];
		
	colours_array[0] = (float)this->width;
	colours_array[1] = (float)this->height;
		
	int col_cnt = gif->SColorMap->ColorCount;
	// int col_cnt = gif->Image.ColorMap->ColorCount;
	// int bpp = gif->Image.ColorMap->BitsPerPixel;
	int bpp = gif->SColorMap->BitsPerPixel;
	// float col_div = float(1 << bpp);
	float col_div = 256;
	for(int i = 0; i < 256; i++) {
		GifColorType col = gif->SColorMap->Colors[i];
		// GifColorType col = gif->Image.ColorMap->Colors[i];
			
		colours_array[i*4 + 4] = float(col.Red)/col_div;
		colours_array[i*4 + 1 + 4] = float(col.Green)/col_div;
		colours_array[i*4 + 2 + 4] = float(col.Blue)/col_div;
		colours_array[i*4 + 3 + 4] = float(1);
	}
	// for(int i = 0; i < gif->ExtensionBlocks->ByteCount; i++) {
	// 	int ext = (int)gif->ExtensionBlocks->Bytes[i];
	// 	wlog_info("{}", ext);
	// }
		

	for(int frame = 0; frame < this->frame_cnt; frame++) {
		SavedImage image = gif->SavedImages[frame];
		// image.ImageDesc
			
		int offs = this->width * this->height * frame;
		if(image.ImageDesc.Left != 0 || image.ImageDesc.Top != 0) {
			int amog = 4;
		}
		for(int i = 0; i < this->width * this->height; i++) {
			indices_array[i + offs] = 0;
		}
		for(int x = 0; x < image.ImageDesc.Width; x++) {
			for(int y = 0; y < image.ImageDesc.Height; y++) {
				// glm::ivec2 img_pos = glm::ivec2(x,y);
				int img_idx = x + y * image.ImageDesc.Width;
				GifByteType raster_bit = image.RasterBits[img_idx];

				int rem = this->width - image.ImageDesc.Width;
				// glm::ivec2 splat_pos = glm::ivec2(x + y * rem ,y);
				glm::ivec2 splat_pos = glm::ivec2(0,0);
				splat_pos += glm::ivec2(x,y);
					
				int splat_idx = splat_pos.x + this->height * splat_pos.y;
				indices_array[splat_idx + offs] = (uint8_t)raster_bit;
				// splat_pos.x += image.ImageDesc.Left;
				// splat_pos.y += image.ImageDesc.Top;
				// int offs = this->width * this->height * frame;
				// indices_array[i + offs] = (int)raster_bit;
				
			}
		}
		for(int i = 0; i < image.ImageDesc.Width * image.ImageDesc.Height; i++) {
			GifByteType raster_bit = image.RasterBits[i];
			int offs = this->width * this->height * frame;
			indices_array[i + offs] = (int)raster_bit;
		}
	}

	GifWord bg_col = gif->SBackGroundColor;

	this->buff_cols = new Buffer(BuffDesc{
		.byte_len = buff_cols_byte_len,
		.upload_data = &colours_array[0],
		.subdata_disabled = false ,
		.read_from_shader = true,
		.name = &path[0]
	});
	this->buff_cols->upload_sub_data(&colours_array[0], buff_cols_byte_len);
		
	this->buff_indices = new Buffer(BuffDesc{
		.byte_len = indices_byte_len, .upload_data = &indices_array[0], .subdata_disabled = false ,.read_from_shader = true
	});
	this->buff_indices->upload_sub_data(&indices_array[0], indices_byte_len);
	// gif->SavedImages
	// if (gif == nullptr) {
	// 	std::cerr << "Error opening GIF file" << std::endl;
	// 	return 1;
	// }

	std::string name = "gif";
	name += path;
	this->fb = new Framebuffer(FBDesc{
		.textures = {
			WEngine->alloc_textures.push(TextureDesc{
				.resx = uint32_t(this->width), .resy = uint32_t(this->height), .resz = 1,
				.internal_format = InternalFormat::SRGB8, .tex_access = TexAccess::RW
			}).ptr
		},
		.name = name
	});
	this->tex = this->fb->textures[0];
		
	delete[] colours_array;
	delete[] indices_array;
}

void WGif::render() {
	time += WEngine->delta_time * this->speed;
	float total_len_secs = float(this->frame_cnt) / float(this->fps);
	float curr_time_secs = float(this->frame) / float(this->fps);
		
	time = glm::mod((float)time, total_len_secs);

	frame = int(time * float(this->fps));
	// if(time > time) {
	// 	time = 
	// }
	// if(time)
	frame = frame % frame_cnt;
		
		
	this->fb->bind();
	WEngine->prog_gif->use();
	WEngine->prog_gif->setUniform("gif_buff", this->buff_cols);
	WEngine->prog_gif->setUniform("uindices", this->buff_indices);
	WEngine->prog_gif->setUniform("frame", this->frame);
	glDrawArrays(GL_TRIANGLES, 0, 6);
}
