#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 <string>				// for basic_string, string
#include "utils.h"				// for Color
#include <memory>
class Asset;
class Input;
class Notify;

enum class ScreenFilter
{
	NEAREST = 0,
	LINEAL = 1,
};

enum class ScreenVideoMode
{
	WINDOW = 0,
	FULLSCREEN = 1,
};

class Screen
{
private:
	// [SINGLETON] Objeto screen privado para Don Melitón
	static Screen *screen;

	// Objetos y punteros
	SDL_Window *window;				// Ventana de la aplicación
	SDL_Renderer *renderer;			// El renderizador de la ventana
	Asset *asset;					// Objeto con el listado de recursos
	Input *input;					// Objeto para leer las entradas de teclado o mando
	std::unique_ptr<Notify> notify; // Pinta notificaciones en pantalla
	SDL_Texture *gameCanvas;		// Textura donde se dibuja todo antes de volcarse al renderizador
	SDL_Texture *shaderCanvas;		// Textura para pasarle al shader desde gameCanvas

	// Variables
	SDL_Rect srcrect;			// Coordenadas de donde va a pillar la textura del juego para dibujarla
	SDL_Rect dstrect;			// Coordenadas donde se va a dibujar la textura del juego sobre la pantalla o ventana
	Color borderColor;			// Color del borde añadido a la textura de juego para rellenar la pantalla
	bool attenuateEffect;		// Indica si la pantalla ha de estar atenuada
	Uint32 fpsTicks;			// Ticks para contar los frames por segundo
	int fpsCounter;				// Contador de frames por segundo
	int fps;					// Frames calculados en el último segundo
	bool showInfo;				// Indica si ha de mostrar/ocultar la información de la pantalla
	std::string infoResolution; // Texto con la informacion de la pantalla

	struct effect_t
	{
		bool enabled; // Indica si el efecto está activo
		int counter;  // Contador para el efecto
		int lenght;	  // Duración del efecto
		Color color;  // Color del efecto
	};

	// Variables - Efectos
	effect_t flashEffect; // Variable para gestionar el efecto de flash

	struct shake_t
	{
		int desp;		   // Pixels de desplazamiento para agitar la pantalla en el eje x
		int delay;		   // Retraso entre cada desplazamiento de la pantalla al agitarse
		int counter;	   // Contador para el retraso
		int lenght;		   // Cantidad de desplazamientos a realizar
		int remaining;	   // Cantidad de desplazamientos pendientes a realizar
		int originalPos;   // Posición inicial de la pantalla para dejarla igual tras el desplazamiento
		int originalWidth; // Anchura inicial de la pantalla para dejarla igual tras el desplazamiento
		bool enabled;	   // Indica si el efecto está activo
	} shakeEffect;

	// Actualiza la logica para agitar la pantalla
	void updateShake();

	// Actualiza y dibuja el efecto de flash en la pantalla
	void doFlash();

	// Atenua la pantalla
	void doAttenuate();

	// Calcula los frames por segundo
	void updateFPS();

	// Muestra información por pantalla
	void displayInfo();

	// [SINGLETON] Ahora el constructor y el destructor son privados, para no poder crear objetos screen desde fuera

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

	// Destructor
	~Screen();

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

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

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

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

	// Comprueba las entradas
	void checkInput();

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

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

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

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

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

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

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

	// Aumenta el tamaño de la ventana
	void incWindowSize();

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

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

	// Agita la pantalla
	void shake();

	// Pone la pantalla de color
	void flash(Color color, int lenght);

	// Activa/desactiva los shaders
	void switchShaders();

	// Atenua la pantalla
	void attenuate(bool value);

	// Muestra una notificación de texto por pantalla;
	void showNotification(std::string text1 = "", std::string text2 = "", int icon = -1);

	// Indica si hay alguna notificación activa en pantalla
	bool notificationsAreActive();

	// Obtiene el puntero al renderizador
	SDL_Renderer *getRenderer();
};