#include "game_over.h"
#include <SDL2/SDL_events.h> // for SDL_PollEvent, SDL_Event
#include <SDL2/SDL_timer.h>  // for SDL_GetTicks
#include <algorithm>         // for min, max
#include <string>            // for basic_string, operator+, to_string, cha...
#include "animated_sprite.h" // for AnimatedSprite
#include "asset.h"           // for Asset
#include "defines.h"         // for GAMECANVAS_CENTER_X
#include "global_events.h"   // for check
#include "global_inputs.h"   // for check
#include "input.h"           // for Input
#include "jail_audio.h"      // for JA_PlayMusic
#include "options.h"         // for Options, options, OptionsStats, Section...
#include "resource.h"        // for Resource
#include "screen.h"          // for Screen
#include "text.h"            // for TEXT_CENTER, TEXT_COLOR, Text
#include "texture.h"         // for Texture

// Constructor
GameOver::GameOver()
    : player_sprite_(std::make_shared<AnimatedSprite>(Resource::get()->getTexture("player_game_over.png"), Resource::get()->getAnimations("player_game_over.ani"))),
      tv_sprite_(std::make_shared<AnimatedSprite>(Resource::get()->getTexture("tv.png"), Resource::get()->getAnimations("tv.ani"))),
      pre_counter_(0),
      counter_(0),
      ticks_(0)
{
    options.section.section = Section::GAME_OVER;
    options.section.subsection = Subsection::NONE;
    
    player_sprite_->setPosX(GAMECANVAS_CENTER_X + 10);
    player_sprite_->setPosY(30);
    tv_sprite_->setPosX(GAMECANVAS_CENTER_X - tv_sprite_->getWidth() - 10);
    tv_sprite_->setPosY(30);

    // Inicializa el vector de colores
    const std::vector<std::string> COLORS = {"white", "yellow", "cyan", "green", "magenta", "red", "blue", "black"};
    for (const auto &color : COLORS)
    {
        colors_.push_back(stringToColor(options.video.palette, color));
    }
    color_ = colors_.back();
}

// Actualiza el objeto
void GameOver::update()
{
    // Comprueba que la diferencia de ticks sea mayor a la velocidad del juego
    if (SDL_GetTicks() - ticks_ > GAME_SPEED)
    {
        // Actualiza el contador de ticks
        ticks_ = SDL_GetTicks();

        // Comprueba las entradas
        checkInput();

        // Actualiza el color usado para renderizar los textos e imagenes
        updateColor();

        // Actualiza los contadores
        updateCounters();

        // Actualiza los dos sprites
        player_sprite_->update();
        tv_sprite_->update();

        Screen::get()->update();
    }
}

// Dibuja el final en pantalla
void GameOver::render()
{
    constexpr int Y = 32;

    Screen::get()->start();
    Screen::get()->clean();

    auto text = Resource::get()->getText("smb2");

    // Escribe el texto de GAME OVER
    text->writeDX(TEXT_CENTER | TEXT_COLOR, GAMECANVAS_CENTER_X, Y, "G A M E   O V E R", 1, color_);

    // Dibuja los sprites
    player_sprite_->setPosY(Y + 30);
    tv_sprite_->setPosY(Y + 30);
    renderSprites();

    // Escribe el texto con las habitaciones y los items
    const std::string itemsTxt = std::to_string(options.stats.items / 100) + std::to_string((options.stats.items % 100) / 10) + std::to_string(options.stats.items % 10);
    const std::string roomsTxt = std::to_string(options.stats.rooms / 100) + std::to_string((options.stats.rooms % 100) / 10) + std::to_string(options.stats.rooms % 10);
    text->writeDX(TEXT_CENTER | TEXT_COLOR, GAMECANVAS_CENTER_X, Y + 80, "ITEMS: " + itemsTxt, 1, color_);
    text->writeDX(TEXT_CENTER | TEXT_COLOR, GAMECANVAS_CENTER_X, Y + 90, "ROOMS: " + roomsTxt, 1, color_);

    // Escribe el texto con "Tu peor pesadilla"
    text->writeDX(TEXT_CENTER | TEXT_COLOR, GAMECANVAS_CENTER_X, Y + 110, "YOUR WORST NIGHTMARE IS", 1, color_);
    text->writeDX(TEXT_CENTER | TEXT_COLOR, GAMECANVAS_CENTER_X, Y + 120, options.stats.worst_nightmare, 1, color_);

    // Vuelca el contenido del renderizador en pantalla
    Screen::get()->render();
}

// Comprueba el manejador de eventos
void GameOver::checkEvents()
{
    SDL_Event event;
    while (SDL_PollEvent(&event))
    {
        globalEvents::check(event);
    }
}

// Comprueba las entradas
void GameOver::checkInput()
{
    globalInputs::check();
}

// Bucle principal
void GameOver::run()
{
    while (options.section.section == Section::GAME_OVER)
    {
        update();
        checkEvents();
        render();
    }
}

// Actualiza el color usado para renderizar los textos e imagenes
void GameOver::updateColor()
{
    const int half = COUNTER_SECTION_END_ / 2;

    if (counter_ < half)
    {
        const float step = std::min(counter_, COUNTER_FADE_LENGHT_) / (float)COUNTER_FADE_LENGHT_;
        const int index = (colors_.size() - 1) - int((colors_.size() - 1) * step);
        color_ = colors_[index];
    }
    else
    {
        const float step = std::min(std::max(counter_, COUNTER_INIT_FADE_) - COUNTER_INIT_FADE_, COUNTER_FADE_LENGHT_) / (float)COUNTER_FADE_LENGHT_;
        const int index = (colors_.size() - 1) * step;
        color_ = colors_[index];
    }
}

// Dibuja los sprites
void GameOver::renderSprites()
{
    player_sprite_->getTexture()->setColor(color_.r, color_.g, color_.b);
    player_sprite_->render();

    tv_sprite_->getTexture()->setColor(color_.r, color_.g, color_.b);
    tv_sprite_->render();
}

// Actualiza los contadores
void GameOver::updateCounters()
{
    // Actualiza el contador
    if (pre_counter_ < 50)
    {
        pre_counter_++;
    }
    else
    {
        counter_++;
    }

    // Hace sonar la música
    if (counter_ == 1)
    {
        JA_PlayMusic(Resource::get()->getMusic("game_over.ogg"), 0);
    }

    // Comprueba si ha terminado la sección
    else if (counter_ == COUNTER_SECTION_END_)
    {
        options.section.section = Section::LOGO;
        options.section.subsection = Subsection::LOGO_TO_TITLE;
    }
}