#pragma once

#include <SDL2/SDL_blendmode.h> // for SDL_BlendMode
#include <SDL2/SDL_rect.h>		// for SDL_Rect
#include <SDL2/SDL_render.h>	// for SDL_Renderer, SDL_Texture
#include <SDL2/SDL_stdinc.h>	// for Uint32
#include <SDL2/SDL_video.h>		// for SDL_Window
#include <vector>				// for vector
#include <memory>				// for shared_ptr
#include "utils.h"				// for Color
//#include "surface.h"

// Tipos de filtro
enum class ScreenFilter : Uint32
{
	NEAREST = 0,
	LINEAR = 1,
};

class Screen
{
private:
	// Constantes
	static constexpr int WINDOWS_DECORATIONS_ = 35;

	// [SINGLETON] Objeto privado
	static Screen *screen_;

	// Objetos y punteros
	SDL_Window *window_;			   // Ventana de la aplicación
	SDL_Renderer *renderer_;		   // El renderizador de la ventana
	SDL_Texture *surface_texture_;	   // Textura donde se dibuja el juego
	SDL_Texture *game_texture_;		   // Textura donde se dibuja el juego
	SDL_Texture *border_texture_;	   // Textura donde se dibuja el borde del juego
	//std::shared_ptr<Surface> surface_; // Objeto para trabajar con surfaces

	// Variables
	int window_width_;			 // Ancho de la pantalla o ventana
	int window_height_;			 // Alto de la pantalla o ventana
	SDL_Rect game_texture_rect_; // Coordenadas donde se va a dibujar la textura del juego sobre la pantalla o ventana
	Color border_color_;		 // Color del borde añadido a la textura de juego para rellenar la pantalla

	// Dibuja las notificaciones
	void renderNotifications();

	// Copia el gameCanvas en el borderCanvas
	void gameCanvasToBorderCanvas();

	// Muestra el contenido de Screen por pantalla
	void renderPresent();

	// Calcula el tamaño de la ventana
	void adjustWindowSize();

	// Ajusta game_canvas_rect_
	void adjustGameCanvasRect();

	// Ajusta el tamaño lógico del renderizador
	void adjustRenderLogicalSize();

	// Constructor
	Screen(SDL_Window *window, SDL_Renderer *renderer);

	// Destructor
	~Screen();

public:
	// [SINGLETON] Crearemos el objeto con esta función estática
	static void init(SDL_Window *window, SDL_Renderer *renderer);

	// [SINGLETON] Destruiremos el objeto con esta función estática
	static void destroy();

	// [SINGLETON] Con este método obtenemos el objeto y podemos trabajar con él
	static Screen *get();

	// Limpia la pantalla
	void clean(Color color = {0x00, 0x00, 0x00});

	// Prepara para empezar a dibujar en la textura de juego
	void start();

	// Prepara para empezar a dibujar en la textura del borde
	void startDrawOnBorder();

	// Vuelca el contenido del renderizador en pantalla
	void render();
	void renderWithoutNotifier();

	// Actualiza la lógica de la clase
	void update();

	// Establece el modo de video
	void setVideoMode(int videoMode);

	// Camibia entre pantalla completa y ventana
	void toggleVideoMode();

	// Reduce el tamaño de la ventana
	bool decWindowZoom();

	// Aumenta el tamaño de la ventana
	bool incWindowZoom();

	// Cambia el color del borde
	void setBorderColor(Color color);

	// Cambia el tipo de mezcla
	void setBlendMode(SDL_BlendMode blendMode);

	// Establece el tamaño del borde
	void setBorderWidth(int s);
	void setBorderHeight(int s);

	// Establece si se ha de ver el borde en el modo ventana
	void setBorderEnabled(bool value);

	// Cambia entre borde visible y no visible
	void toggleBorder();

	// Cambia el estado de los shaders
	void toggleShaders();

	// Muestra la ventana
	void show();

	// Oculta la ventana
	void hide();

	// Obtiene el tamaño máximo de zoom posible para la ventana
	int getMaxZoom();

	// Getters
	SDL_Renderer *getRenderer() { return renderer_; }
	//std::shared_ptr<SurfaceData> getSurface() { return surface_->getSurface(); }
	SDL_Texture *getGameTexture() { return game_texture_; };
	SDL_Texture *getBorderTexture() { return border_texture_; }
};