#include "core/rendering/fade.h"

#include <SDL3/SDL.h>
#include <stdlib.h>  // for rand

#include <iostream>  // for char_traits, basic_ostream, operator<<

#include "game/defaults.hpp"  // for GAMECANVAS_HEIGHT, GAMECANVAS_WIDTH

// Constructor
Fade::Fade(SDL_Renderer *renderer)
    : mRenderer(renderer) {
    mBackbuffer = SDL_CreateTexture(mRenderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, GAMECANVAS_WIDTH, GAMECANVAS_HEIGHT);
    if (mBackbuffer != nullptr) {
        SDL_SetTextureScaleMode(mBackbuffer, SDL_SCALEMODE_NEAREST);
    }
    if (mBackbuffer == nullptr) {
        std::cout << "Error: textTexture could not be created!\nSDL Error: " << SDL_GetError() << std::endl;
    }
}

// Destructor
Fade::~Fade() {
    SDL_DestroyTexture(mBackbuffer);
    mBackbuffer = nullptr;
}

// Inicializa las variables
void Fade::init(Uint8 r, Uint8 g, Uint8 b) {
    mFadeType = FADE_CENTER;
    mEnabled = false;
    mFinished = false;
    mCounter = 0;
    mR = r;
    mG = g;
    mB = b;
    mROriginal = r;
    mGOriginal = g;
    mBOriginal = b;
    mLastSquareTicks = 0;
    mSquaresDrawn = 0;
    mFullscreenDone = false;
}

// Pinta una transición en pantalla
void Fade::render() {
    if (mEnabled && !mFinished) {
        switch (mFadeType) {
            case FADE_FULLSCREEN: {
                if (!mFullscreenDone) {
                    SDL_FRect fRect1 = {0, 0, (float)GAMECANVAS_WIDTH, (float)GAMECANVAS_HEIGHT};

                    int alpha = mCounter * 4;
                    if (alpha >= 255) {
                        mFullscreenDone = true;

                        // Deja todos los buffers del mismo color
                        SDL_SetRenderTarget(mRenderer, mBackbuffer);
                        SDL_SetRenderDrawColor(mRenderer, mR, mG, mB, 255);
                        SDL_RenderClear(mRenderer);

                        SDL_SetRenderTarget(mRenderer, nullptr);
                        SDL_SetRenderDrawColor(mRenderer, mR, mG, mB, 255);
                        SDL_RenderClear(mRenderer);

                        mFinished = true;
                    } else {
                        // Dibujamos sobre el renderizador
                        SDL_SetRenderTarget(mRenderer, nullptr);

                        // Copia el backbuffer con la imagen que había al renderizador
                        SDL_RenderTexture(mRenderer, mBackbuffer, nullptr, nullptr);

                        SDL_SetRenderDrawColor(mRenderer, mR, mG, mB, alpha);
                        SDL_RenderFillRect(mRenderer, &fRect1);
                    }
                }
                break;
            }

            case FADE_CENTER: {
                SDL_FRect fR1 = {0, 0, (float)GAMECANVAS_WIDTH, 0};
                SDL_FRect fR2 = {0, 0, (float)GAMECANVAS_WIDTH, 0};

                SDL_SetRenderDrawColor(mRenderer, mR, mG, mB, 64);

                for (int i = 0; i < mCounter; i++) {
                    fR1.h = fR2.h = (float)(i * 4);
                    fR2.y = (float)(GAMECANVAS_HEIGHT - (i * 4));

                    SDL_RenderFillRect(mRenderer, &fR1);
                    SDL_RenderFillRect(mRenderer, &fR2);
                }

                if ((mCounter * 4) > GAMECANVAS_HEIGHT)
                    mFinished = true;
                break;
            }

            case FADE_RANDOM_SQUARE: {
                Uint32 now = SDL_GetTicks();
                if (mSquaresDrawn < 50 && now - mLastSquareTicks >= 100) {
                    mLastSquareTicks = now;

                    SDL_FRect fRs = {0, 0, 32, 32};

                    // Crea un color al azar
                    Uint8 r = 255 * (rand() % 2);
                    Uint8 g = 255 * (rand() % 2);
                    Uint8 b = 255 * (rand() % 2);
                    SDL_SetRenderDrawColor(mRenderer, r, g, b, 64);

                    // Dibujamos sobre el backbuffer
                    SDL_SetRenderTarget(mRenderer, mBackbuffer);

                    fRs.x = (float)(rand() % (GAMECANVAS_WIDTH - 32));
                    fRs.y = (float)(rand() % (GAMECANVAS_HEIGHT - 32));
                    SDL_RenderFillRect(mRenderer, &fRs);

                    // Volvemos a usar el renderizador de forma normal
                    SDL_SetRenderTarget(mRenderer, nullptr);

                    mSquaresDrawn++;
                }

                // Copiamos el backbuffer al renderizador
                SDL_RenderTexture(mRenderer, mBackbuffer, nullptr, nullptr);

                if (mSquaresDrawn >= 50) {
                    mFinished = true;
                }
                break;
            }

            default:
                break;
        }
    }

    if (mFinished) {
        SDL_SetRenderDrawColor(mRenderer, mR, mG, mB, 255);
        SDL_RenderClear(mRenderer);
    }
}

// Actualiza las variables internas
void Fade::update() {
    if (mEnabled)
        mCounter++;
}

// Activa el fade
void Fade::activateFade() {
    mEnabled = true;
    mFinished = false;
    mCounter = 0;
    mSquaresDrawn = 0;
    mLastSquareTicks = 0;
    mFullscreenDone = false;
    mR = mROriginal;
    mG = mGOriginal;
    mB = mBOriginal;
}

// Comprueba si está activo
bool Fade::isEnabled() {
    return mEnabled;
}

// Comprueba si ha terminado la transicion
bool Fade::hasEnded() {
    return mFinished;
}

// Establece el tipo de fade
void Fade::setFadeType(Uint8 fadeType) {
    mFadeType = fadeType;
}