#pragma once

#include <SDL2/SDL_blendmode.h> // Para SDL_BlendMode
#include <SDL2/SDL_rect.h>		// Para SDL_Rect
#include <SDL2/SDL_render.h>	// Para SDL_Renderer, SDL_Texture
#include <SDL2/SDL_video.h>		// Para SDL_Window
#include <string>				// Para basic_string, string
#include <vector>				// Para vector
#include "utils.h"				// Para color_t
class Asset;
class Notifier;

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

class Screen
{
private:
	// [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 *game_canvas_;	 // Textura donde se dibuja el juego
	SDL_Texture *border_canvas_; // Textura donde se dibuja el borde del juego

	// Variables
	int window_width_;				  // Ancho de la pantalla o ventana
	int window_height_;				  // Alto de la pantalla o ventana
	int game_canvas_width_;			  // Resolución interna del juego. Es el ancho de la textura donde se dibuja el juego
	int game_canvas_height_;		  // Resolución interna del juego. Es el alto de la textura donde se dibuja el juego
	SDL_Rect dest_;					  // 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
	int notification_logical_width_;  // Ancho lógico de las notificaciones en relación al tamaño de pantalla
	int notification_logical_height_; // Alto lógico de las notificaciones en relación al tamaño de pantalla

	// Variables - Efectos
	bool fade_;							// Indica si esta activo el efecto de fade
	int fade_counter_;					// Temporizador para el efecto de fade
	int fade_lenght_;					// Duración del fade
	bool spectrum_fade_;				// Indica si esta activo el efecto de fade spectrum
	int spectrum_fade_counter_;			// Temporizador para el efecto de fade spectrum
	int spectrum_fade_lenght_;			// Duración del fade spectrum
	std::vector<Color> spectrum_color_; // Colores para el fade spectrum

	// Inicializa las variables para el fade
	void iniFade();

	// Actualiza el fade
	void updateFade();

	// Dibuja el fade
	void renderFade();

	// Inicializa las variables para el fade spectrum
	void iniSpectrumFade();

	// Actualiza el spectrum fade
	void updateSpectrumFade();

	// Dibuja el spectrum fade
	void renderSpectrumFade();

	// Dibuja las notificaciones
	void renderNotifications();

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

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

	// 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();

	// 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();

	// Cambia el tamaño de la ventana
	void setWindowZoom(int size);

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

	// Aumenta el tamaño de la ventana
	void 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();

	// Activa el fade
	void setFade();

	// Comprueba si ha terminado el fade
	bool fadeEnded();

	// Activa el spectrum fade
	void setspectrumFade();

	// Comprueba si ha terminado el spectrum fade
	bool spectrumFadeEnded();

	// Actualiza los efectos
	void updateFX();

	// Dibuja los efectos
	void renderFX();

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

	// Getters
	SDL_Renderer *getRenderer() { return renderer_; }
};