#include "game/scenes/intro.h"

#include <SDL3/SDL.h>

#include <string>  // for basic_string

#include "core/audio/audio.hpp"          // for Audio::get, Audio::update
#include "core/input/global_inputs.hpp"  // for GlobalInputs::handle
#include "core/input/input.h"            // for Input, REPEAT_FALSE, InputAction
#include "core/locale/lang.h"            // for Lang
#include "core/rendering/screen.h"       // for Screen
#include "core/rendering/smartsprite.h"  // for SmartSprite
#include "core/rendering/writer.h"       // for Writer
#include "core/resources/resource.h"
#include "game/defaults.hpp"  // for GAMECANVAS_CENTER_X, GAMECANVAS_FIRST_QU...
#include "utils/utils.h"      // for Section, Color

// Constructor
Intro::Intro(SDL_Renderer *renderer, Section *section) {
    // Copia los punteros
    this->renderer_ = renderer;
    this->section_ = section;

    // Reserva memoria para los objetos
    event_handler_ = new SDL_Event();
    texture_ = Resource::get()->getTexture("intro.png");
    text_ = Resource::get()->getText("nokia");
    music_ = Resource::get()->getMusic("intro.ogg");

    // Inicializa variables
    section->name = SECTION_PROG_INTRO;
    section->subsection = 0;
    ticks_ = 0;
    ticks_speed_ = 15;
    scene_ = 1;

    // Inicializa los bitmaps de la intro
    const int TOTAL_BITMAPS = 6;
    for (int i = 0; i < TOTAL_BITMAPS; ++i) {
        auto *ss = new SmartSprite(texture_, renderer);
        ss->setWidth(128);
        ss->setHeight(96);
        ss->setEnabledCounter(20);
        ss->setDestX(GAMECANVAS_CENTER_X - 64);
        ss->setDestY(GAMECANVAS_FIRST_QUARTER_Y - 24);
        bitmaps_.push_back(ss);
    }

    bitmaps_[0]->setPosX(-128);
    bitmaps_[0]->setPosY(GAMECANVAS_FIRST_QUARTER_Y - 24);
    bitmaps_[0]->setVelX(0.0F);
    bitmaps_[0]->setVelY(0.0F);
    bitmaps_[0]->setAccelX(0.6F);
    bitmaps_[0]->setAccelY(0.0F);
    bitmaps_[0]->setSpriteClip(0, 0, 128, 96);

    bitmaps_[1]->setPosX(GAMECANVAS_WIDTH);
    bitmaps_[1]->setPosY(GAMECANVAS_FIRST_QUARTER_Y - 24);
    bitmaps_[1]->setVelX(-1.0F);
    bitmaps_[1]->setVelY(0.0F);
    bitmaps_[1]->setAccelX(-0.3F);
    bitmaps_[1]->setAccelY(0.0F);
    bitmaps_[1]->setSpriteClip(128, 0, 128, 96);

    bitmaps_[2]->setPosX(GAMECANVAS_CENTER_X - 64);
    bitmaps_[2]->setPosY(-96);
    bitmaps_[2]->setVelX(0.0F);
    bitmaps_[2]->setVelY(3.0F);
    bitmaps_[2]->setAccelX(0.1F);
    bitmaps_[2]->setAccelY(0.3F);
    bitmaps_[2]->setSpriteClip(0, 96, 128, 96);
    bitmaps_[2]->setEnabledCounter(250);

    bitmaps_[3]->setPosX(GAMECANVAS_CENTER_X - 64);
    bitmaps_[3]->setPosY(GAMECANVAS_HEIGHT);
    bitmaps_[3]->setVelX(0.0F);
    bitmaps_[3]->setVelY(-0.7F);
    bitmaps_[3]->setAccelX(0.0F);
    bitmaps_[3]->setAccelY(0.0F);
    bitmaps_[3]->setSpriteClip(128, 96, 128, 96);

    bitmaps_[4]->setPosX(GAMECANVAS_CENTER_X - 64);
    bitmaps_[4]->setPosY(-96);
    bitmaps_[4]->setVelX(0.0F);
    bitmaps_[4]->setVelY(3.0F);
    bitmaps_[4]->setAccelX(0.1F);
    bitmaps_[4]->setAccelY(0.3F);
    bitmaps_[4]->setSpriteClip(0, 192, 128, 96);

    bitmaps_[5]->setPosX(GAMECANVAS_WIDTH);
    bitmaps_[5]->setPosY(GAMECANVAS_FIRST_QUARTER_Y - 24);
    bitmaps_[5]->setVelX(-0.7F);
    bitmaps_[5]->setVelY(0.0F);
    bitmaps_[5]->setAccelX(0.0F);
    bitmaps_[5]->setAccelY(0.0F);
    bitmaps_[5]->setSpriteClip(128, 192, 128, 96);

    // Inicializa los textos de la intro
    const int TOTAL_TEXTS = 9;
    for (int i = 0; i < TOTAL_TEXTS; ++i) {
        auto *w = new Writer(text_);
        w->setPosX(BLOCK * 0);
        w->setPosY(GAMECANVAS_HEIGHT - (BLOCK * 6));
        w->setKerning(-1);
        w->setEnabled(false);
        w->setEnabledCounter(180);
        texts_.push_back(w);
    }

    // Un dia qualsevol de l'any 2000
    texts_[0]->setCaption(Lang::get()->getText(27));
    texts_[0]->setSpeed(8);

    // Tot esta tranquil a la UPV
    texts_[1]->setCaption(Lang::get()->getText(28));
    texts_[1]->setSpeed(8);

    // Fins que un desaprensiu...
    texts_[2]->setCaption(Lang::get()->getText(29));
    texts_[2]->setSpeed(12);

    // HEY! ME ANE A FERME UN CORTAET...
    texts_[3]->setCaption(Lang::get()->getText(30));
    texts_[3]->setSpeed(8);

    // UAAAAAAAAAAAAA!!!
    texts_[4]->setCaption(Lang::get()->getText(31));
    texts_[4]->setSpeed(1);

    // Espera un moment...
    texts_[5]->setCaption(Lang::get()->getText(32));
    texts_[5]->setSpeed(16);

    // Si resulta que no tinc solt!
    texts_[6]->setCaption(Lang::get()->getText(33));
    texts_[6]->setSpeed(2);

    // MERDA DE MAQUINA!
    texts_[7]->setCaption(Lang::get()->getText(34));
    texts_[7]->setSpeed(3);

    // Blop... blop... blop...
    texts_[8]->setCaption(Lang::get()->getText(35));
    texts_[8]->setSpeed(16);

    for (auto *t : texts_) {
        t->center(GAMECANVAS_CENTER_X);
    }

    Audio::get()->playMusic(music_, 0);
}

// Destructor
Intro::~Intro() {
    delete event_handler_;

    // texture, text, music son propiedad de Resource — no liberar aquí.
    for (auto *bitmap : bitmaps_) {
        delete bitmap;
    }

    for (auto *t : texts_) {
        delete t;
    }
}

// Comprueba las entradas
void Intro::checkInput() {
#ifndef __EMSCRIPTEN__
    if (Input::get()->checkInput(EXIT, REPEAT_FALSE)) {
        section_->name = SECTION_PROG_QUIT;
        return;
    }
#endif
    if (GlobalInputs::handle()) { return; }

    if (Input::get()->checkInput(PAUSE, REPEAT_FALSE) || Input::get()->checkInput(ACCEPT, REPEAT_FALSE) || Input::get()->checkInput(FIRE_LEFT, REPEAT_FALSE) || Input::get()->checkInput(FIRE_CENTER, REPEAT_FALSE) || Input::get()->checkInput(FIRE_RIGHT, REPEAT_FALSE)) {
        Audio::get()->stopMusic();
        section_->name = SECTION_PROG_TITLE;
        section_->subsection = SUBSECTION_TITLE_1;
    }
}

// Actualiza las escenas de la intro
void Intro::updateScenes() {
    switch (scene_) {
        case 1:
            updateScene1();
            break;
        case 2:
            updateScene2();
            break;
        case 3:
            updateScene3();
            break;
        case 4:
            updateScene4();
            break;
        case 5:
            updateScene5();
            break;
        case 6:
            updateScene6();
            break;
        default:
            break;
    }
}

// Primera escena - UPV
void Intro::updateScene1() {
    // Primera imagen - UPV
    if (!bitmaps_[0]->hasFinished()) {
        bitmaps_[0]->setEnabled(true);
    }

    // Primer texto de la primera imagen
    if (bitmaps_[0]->hasFinished() && !texts_[0]->hasFinished()) {
        texts_[0]->setEnabled(true);
    }

    // Segundo texto de la primera imagen
    if (texts_[0]->hasFinished() && !texts_[1]->hasFinished()) {
        texts_[0]->setEnabled(false);
        texts_[1]->setEnabled(true);
    }

    // Tercer texto de la primera imagen
    if (texts_[1]->hasFinished() && !texts_[2]->hasFinished()) {
        texts_[1]->setEnabled(false);
        texts_[2]->setEnabled(true);
    }

    // Fin de la primera escena
    if (texts_[2]->hasFinished()) {
        bitmaps_[0]->setEnabled(false);
        texts_[2]->setEnabled(false);
        scene_++;
    }
}

// Segunda escena - Máquina
void Intro::updateScene2() {
    // Segunda imagen - Máquina
    if (!bitmaps_[1]->hasFinished()) {
        bitmaps_[1]->setEnabled(true);
    }

    // Primer texto de la segunda imagen
    if (bitmaps_[1]->hasFinished() && !texts_[3]->hasFinished()) {
        texts_[3]->setEnabled(true);
    }

    // Fin de la segunda escena
    if (texts_[3]->hasFinished()) {
        bitmaps_[1]->setEnabled(false);
        texts_[3]->setEnabled(false);
        scene_++;
    }
}

// Tercera escena - GRITO
void Intro::updateScene3() {
    // Tercera imagen junto con primer texto - GRITO
    if (!bitmaps_[2]->hasFinished() && !texts_[4]->hasFinished()) {
        bitmaps_[2]->setEnabled(true);
        texts_[4]->setEnabled(true);
    }

    // Fin de la tercera escena
    if (bitmaps_[2]->hasFinished() && texts_[4]->hasFinished()) {
        bitmaps_[2]->setEnabled(false);
        texts_[4]->setEnabled(false);
        scene_++;
    }
}

// Cuarta escena - Reflexión
void Intro::updateScene4() {
    // Cuarta imagen junto con primer texto - Reflexión
    if (!bitmaps_[3]->hasFinished() && !texts_[5]->hasFinished()) {
        bitmaps_[3]->setEnabled(true);
        texts_[5]->setEnabled(true);
    }

    // Segundo texto de la cuarta imagen
    if (texts_[5]->hasFinished() && !texts_[6]->hasFinished()) {
        texts_[5]->setEnabled(false);
        texts_[6]->setEnabled(true);
    }

    // Fin de la cuarta escena
    if (bitmaps_[3]->hasFinished() && texts_[6]->hasFinished()) {
        bitmaps_[3]->setEnabled(false);
        texts_[6]->setEnabled(false);
        scene_++;
    }
}

// Quinta escena - Patada
void Intro::updateScene5() {
    // Quinta imagen - Patada
    if (!bitmaps_[4]->hasFinished()) {
        bitmaps_[4]->setEnabled(true);
    }

    // Primer texto de la quinta imagen
    if (bitmaps_[4]->hasFinished() && !texts_[7]->hasFinished()) {
        texts_[7]->setEnabled(true);
    }

    // Fin de la quinta escena
    if (bitmaps_[4]->hasFinished() && texts_[7]->hasFinished()) {
        bitmaps_[4]->setEnabled(false);
        texts_[7]->setEnabled(false);
        scene_++;
    }
}

// Sexta escena - Globos de café
void Intro::updateScene6() {
    // Sexta imagen junto con texto - Globos de café
    if (!bitmaps_[5]->hasFinished() && !texts_[8]->hasFinished()) {
        bitmaps_[5]->setEnabled(true);
        texts_[8]->setEnabled(true);
    }

    // Acaba el último texto
    if (bitmaps_[5]->hasFinished() && texts_[8]->hasFinished()) {
        bitmaps_[5]->setEnabled(false);
        texts_[8]->setEnabled(false);
        Audio::get()->stopMusic();
        section_->name = SECTION_PROG_TITLE;
        section_->subsection = SUBSECTION_TITLE_1;
    }
}

// Actualiza las variables del objeto
void Intro::update() {
    Audio::update();
    checkInput();

    if (SDL_GetTicks() - ticks_ > ticks_speed_) {
        // Actualiza el contador de ticks
        ticks_ = SDL_GetTicks();

        // Actualiza los objetos
        for (auto *bitmap : bitmaps_) {
            bitmap->update();
        }

        for (auto *t : texts_) {
            t->update();
        }

        // Actualiza las escenas de la intro
        updateScenes();
    }
}

// Dibuja el objeto en pantalla
void Intro::render() {
    // Prepara para empezar a dibujar en la textura de juego
    Screen::get()->start();

    // Limpia la pantalla
    Screen::get()->clean(bgColor);

    // Dibuja los objetos
    for (auto *bitmap : bitmaps_) {
        bitmap->render();
    }

    for (auto *t : texts_) {
        t->render();
    }

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

// Bucle principal
void Intro::run() {
    Audio::get()->playMusic(music_, 0);

    while (section_->name == SECTION_PROG_INTRO) {
        iterate();
    }
}

// Ejecuta un frame
void Intro::iterate() {
    update();
    render();
}

// Procesa un evento individual
void Intro::handleEvent(const SDL_Event *event) {
    // SDL_EVENT_QUIT ya lo maneja Director
}
