#include "game/scenes/title.hpp"

#include <SDL3/SDL.h>

#include <algorithm>  // Para clamp

#include "core/input/global_inputs.hpp"       // Para check
#include "core/input/input.hpp"               // Para Input, InputAction, INPUT_DO_NOT_ALLOW_REPEAT, REP...
#include "core/rendering/screen.hpp"          // Para Screen
#include "core/rendering/surface.hpp"         // Para Surface
#include "core/rendering/surface_sprite.hpp"  // Para SSprite
#include "core/rendering/text.hpp"            // Para Text, TEXT_CENTER, TEXT_COLOR
#include "core/resources/resource.hpp"        // Para Resource
#include "game/gameplay/cheevos.hpp"          // Para Cheevos, Achievement
#include "game/options.hpp"                   // Para Options, options, SectionState, Section
#include "game/scene_manager.hpp"             // Para SceneManager
#include "utils/defines.hpp"                  // Para PLAY_AREA_CENTER_X, GAMECANVAS_WIDTH
#include "core/system/global_events.hpp"      // Para check
#include "utils/utils.hpp"                    // Para stringToColor, PaletteColor, playMusic

// Constructor
Title::Title()
    : title_logo_surface_(Resource::get()->getSurface("title_logo.gif")),
      title_logo_sprite_(std::make_shared<SurfaceSprite>(title_logo_surface_, 29, 9, title_logo_surface_->getWidth(), title_logo_surface_->getHeight())),
      loading_screen_surface_(Resource::get()->getSurface("loading_screen_color.gif")),
      loading_screen_sprite_(std::make_shared<SurfaceSprite>(loading_screen_surface_, 0, 0, loading_screen_surface_->getWidth(), loading_screen_surface_->getHeight())),
      bg_surface_(std::make_shared<Surface>(Options::game.width, Options::game.height)),
      delta_timer_(std::make_unique<DeltaTimer>()),
      marquee_text_(Resource::get()->getText("gauntlet")),
      first_active_letter_(0),
      last_active_letter_(0),
      state_time_(0.0F),
      fade_accumulator_(0.0F),
      current_delta_(0.0F) {
    // Inicializa variables
    state_ = SceneManager::options == SceneManager::Options::TITLE_WITH_LOADING_SCREEN ? TitleState::SHOW_LOADING_SCREEN : TitleState::SHOW_MENU;
    SceneManager::current = SceneManager::Scene::TITLE;
    SceneManager::options = SceneManager::Options::NONE;
    initMarquee();

    // Crea y rellena la textura para mostrar los logros
    createCheevosTexture();

    // Cambia el color del borde
    Screen::get()->setBorderColor(static_cast<Uint8>(PaletteColor::BLACK));

    // Rellena la textura de fondo con todos los gráficos
    fillSurface();

    // Inicia la musica
    playMusic("title.ogg");
}

// Inicializa la marquesina
void Title::initMarquee() {
    letters_.clear();
    long_text_ = "HEY JAILERS!! IT'S 2022 AND WE'RE STILL ROCKING LIKE IT'S 1998!!! HAVE YOU HEARD IT? JAILGAMES ARE BACK!! YEEESSS BACK!! MORE THAN 10 TITLES ON JAILDOC'S KITCHEN!! THATS A LOOOOOOT OF JAILGAMES, BUT WHICH ONE WILL STRIKE FIRST? THERE IS ALSO A NEW DEVICE TO COME THAT WILL BLOW YOUR MIND WITH JAILGAMES ON THE GO: P.A.C.O. BUT WAIT! WHAT'S THAT BEAUTY I'M SEEING RIGHT OVER THERE?? OOOH THAT TINY MINIASCII IS PURE LOVE!! I WANT TO LICK EVERY BYTE OF IT!! OH SHIT! AND DON'T FORGET TO BRING BACK THOSE OLD AND FAT MS-DOS JAILGAMES TO GITHUB TO KEEP THEM ALIVE!! WHAT WILL BE THE NEXT JAILDOC RELEASE? WHAT WILL BE THE NEXT PROJECT TO COME ALIVE?? OH BABY WE DON'T KNOW BUT HERE YOU CAN FIND THE ANSWER, YOU JUST HAVE TO COMPLETE JAILDOCTOR'S DILEMMA ... COULD YOU?";

    // Pre-calcular anchos de caracteres para eficiencia
    for (size_t i = 0; i < long_text_.length(); ++i) {
        TitleLetter l;
        l.letter = long_text_[i];                                             // char directo, no substring
        l.x = MARQUEE_START_X;                                                // Usar constante
        l.width = marquee_text_->lenght(std::string(1, long_text_[i]));      // Pre-calcular ancho
        l.enabled = false;
        letters_.push_back(l);
    }

    letters_[0].enabled = true;
    first_active_letter_ = 0;
    last_active_letter_ = 0;
}

// Comprueba el manejador de eventos
void Title::checkEvents() {
    SDL_Event event;
    while (SDL_PollEvent(&event)) {
        GlobalEvents::check(event);

        // Solo se comprueban estas teclas si no está activo el menu de logros
        if (event.type == SDL_EVENT_KEY_DOWN) {
            if (!show_cheevos_) {
                switch (event.key.key) {
                    case SDLK_1:
                        SceneManager::current = SceneManager::Scene::GAME;
                        SceneManager::options = SceneManager::Options::NONE;
                        break;

                    case SDLK_2:
                        show_cheevos_ = true;
                        break;

                    default:
                        break;
                }
            }
        }
    }
}

// Comprueba las entradas
void Title::checkInput() {
    if (show_cheevos_) {
        if (Input::get()->checkInput(InputAction::DOWN, INPUT_ALLOW_REPEAT)) {
            moveCheevosList(1, current_delta_);
        } else if (Input::get()->checkInput(InputAction::UP, INPUT_ALLOW_REPEAT)) {
            moveCheevosList(0, current_delta_);
        } else if (Input::get()->checkInput(InputAction::ACCEPT, INPUT_DO_NOT_ALLOW_REPEAT)) {
            hideCheevosList();
        }
    }

    if (Input::get()->checkInput(InputAction::ACCEPT, INPUT_DO_NOT_ALLOW_REPEAT)) {
        if (state_ == TitleState::SHOW_LOADING_SCREEN) {
            transitionToState(TitleState::FADE_LOADING_SCREEN);
        }
    }

    GlobalInputs::check();
}

// Actualiza la marquesina
void Title::updateMarquee(float delta_time) {
    const float DISPLACEMENT = MARQUEE_SPEED * delta_time;

    // Solo procesar letras en rango activo + 1 para poder activar la siguiente
    for (int i = first_active_letter_; i <= last_active_letter_ + 1 && i < (int)letters_.size(); ++i) {
        auto& letter = letters_[i];

        if (letter.enabled) {
            letter.x -= DISPLACEMENT;

            // Desactivar si sale de pantalla
            if (letter.x < MARQUEE_EXIT_X) {
                letter.enabled = false;
                if (i == first_active_letter_) {
                    first_active_letter_++;  // Avanzar inicio del rango
                }
            }
        } else if (i > 0 && letters_[i - 1].x < MARQUEE_START_X && letters_[i - 1].enabled) {
            // Activar siguiente letra usando ancho pre-calculado
            letter.enabled = true;
            letter.x = letters_[i - 1].x + letters_[i - 1].width + MARQUEE_LETTER_SPACING;
            last_active_letter_ = i;  // Expandir fin del rango
        }
    }

    // Comprueba si ha terminado la marquesina y la reinicia
    if (letters_[letters_.size() - 1].x < MARQUEE_EXIT_X) {
        initMarquee();
    }
}

// Dibuja la marquesina
void Title::renderMarquee() {
    // Solo renderizar letras activas (optimización: usa cache y rangos)
    for (int i = first_active_letter_; i <= last_active_letter_ + 1 && i < (int)letters_.size(); ++i) {
        const auto& letter = letters_[i];
        if (letter.enabled) {
            marquee_text_->writeColored(
                static_cast<int>(letter.x),                       // Conversión explícita float→int
                static_cast<int>(MARQUEE_Y),                      // Usar constante
                std::string(1, letter.letter),                    // Convertir char a string
                static_cast<Uint8>(PaletteColor::BRIGHT_RED)
            );
        }
    }
}

// Actualiza las variables
void Title::update() {
    // Obtener delta time
    current_delta_ = delta_timer_->tick();

    // Comprueba las entradas
    checkInput();

    // Actualiza la pantalla
    Screen::get()->update(current_delta_);

    // Actualiza el estado actual
    updateState(current_delta_);
}

// Actualiza el estado actual
void Title::updateState(float delta_time) {
    state_time_ += delta_time;

    switch (state_) {
        case TitleState::SHOW_LOADING_SCREEN:
            if (state_time_ >= SHOW_LOADING_DURATION) {
                transitionToState(TitleState::FADE_LOADING_SCREEN);
            }
            break;

        case TitleState::FADE_LOADING_SCREEN:
            fade_accumulator_ += delta_time;
            if (fade_accumulator_ >= FADE_STEP_INTERVAL) {
                fade_accumulator_ = 0.0F;
                if (loading_screen_surface_->fadeSubPalette()) {
                    transitionToState(TitleState::SHOW_MENU);
                }
            }
            break;

        case TitleState::SHOW_MENU:
            // Actualiza la marquesina
            updateMarquee(delta_time);

            // Si el tiempo alcanza el timeout, va a créditos
            if (state_time_ >= AUTO_CREDITS_TIMEOUT && !show_cheevos_) {
                SceneManager::current = SceneManager::Scene::CREDITS;
                SceneManager::options = SceneManager::Options::NONE;
            }
            break;

        default:
            break;
    }
}

// Transiciona a un nuevo estado
void Title::transitionToState(TitleState new_state) {
    state_ = new_state;
    state_time_ = 0.0F;
    fade_accumulator_ = 0.0F;
}

// Dibuja en pantalla
void Title::render() {
    // Prepara para empezar a dibujar en la textura de juego
    Screen::get()->start();
    Screen::get()->clearSurface(static_cast<Uint8>(PaletteColor::BLACK));

    switch (state_) {
        case TitleState::SHOW_MENU:
            // Dibuja la textura de fondo
            bg_surface_->render(0, 0);

            // Dibuja la marquesina
            renderMarquee();

            // Dibuja la información de logros
            if (show_cheevos_) {
                cheevos_sprite_->render();
            }
            break;

        case TitleState::SHOW_LOADING_SCREEN:
        case TitleState::FADE_LOADING_SCREEN:
            loading_screen_sprite_->render();
            title_logo_sprite_->render();
            break;

        default:
            break;
    }

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

// Bucle para el logo del juego
void Title::run() {
    while (SceneManager::current == SceneManager::Scene::TITLE) {
        update();
        checkEvents();
        render();
    }
}

// Desplaza la lista de logros
void Title::moveCheevosList(int direction, float delta_time) {
    // Calcula el desplazamiento basado en tiempo
    const float DISPLACEMENT = CHEEVOS_SCROLL_SPEED * delta_time;

    // Modifica la posición de la ventana de vista
    cheevos_surface_view_.y = direction == 0
        ? cheevos_surface_view_.y - DISPLACEMENT
        : cheevos_surface_view_.y + DISPLACEMENT;

    // Ajusta los limites
    const float BOTTOM = cheevos_surface_->getHeight() - cheevos_surface_view_.h;
    cheevos_surface_view_.y = std::clamp(cheevos_surface_view_.y, 0.0F, BOTTOM);

    cheevos_sprite_->setClip(cheevos_surface_view_);
}

// Rellena la textura de fondo con todos los gráficos
void Title::fillSurface() {
    // Coloca el puntero del renderizador sobre la textura
    auto previuos_renderer = Screen::get()->getRendererSurface();
    Screen::get()->setRendererSurface(bg_surface_);

    // Rellena la textura de color
    bg_surface_->clear(static_cast<Uint8>(PaletteColor::BLACK));

    // Pinta el gráfico del titulo a partir del sprite
    title_logo_sprite_->render();

    // Escribe el texto en la textura
    auto text = Resource::get()->getText("smb2");
    const Uint8 COLOR = stringToColor("green");
    const int TEXT_SIZE = text->getCharacterSize();
    text->writeDX(TEXT_CENTER | TEXT_COLOR, PLAY_AREA_CENTER_X, 11 * TEXT_SIZE, "1.PLAY", 1, COLOR);
    text->writeDX(TEXT_CENTER | TEXT_COLOR, PLAY_AREA_CENTER_X, 13 * TEXT_SIZE, "2.ACHIEVEMENTS", 1, COLOR);
    text->writeDX(TEXT_CENTER | TEXT_COLOR, PLAY_AREA_CENTER_X, 15 * TEXT_SIZE, "3.REDEFINE KEYS", 1, COLOR);

    // Devuelve el puntero del renderizador a su sitio
    Screen::get()->setRendererSurface(previuos_renderer);
}

// Crea y rellena la textura para mostrar los logros
void Title::createCheevosTexture() {
    // Crea la textura con el listado de logros
    const auto CHEEVOS_LIST = Cheevos::get()->list();
    const auto TEXT = Resource::get()->getText("subatomic");
    constexpr int CHEEVOS_TEXTURE_WIDTH = 200;
    constexpr int CHEEVOS_TEXTURE_VIEW_HEIGHT = 110 - 8;
    constexpr int CHEEVOS_TEXTURE_POS_Y = 73;
    constexpr int CHEEVOS_PADDING = 10;
    const int CHEEVO_HEIGHT = CHEEVOS_PADDING + (TEXT->getCharacterSize() * 2) + 1;
    const int CHEEVOS_TEXTURE_HEIGHT = (CHEEVO_HEIGHT * CHEEVOS_LIST.size()) + 2 + TEXT->getCharacterSize() + 8;
    cheevos_surface_ = std::make_shared<Surface>(CHEEVOS_TEXTURE_WIDTH, CHEEVOS_TEXTURE_HEIGHT);

    // Prepara para dibujar sobre la textura
    auto previuos_renderer = Screen::get()->getRendererSurface();
    Screen::get()->setRendererSurface(cheevos_surface_);

    // Rellena la textura con color sólido
    const auto CHEEVOS_BG_COLOR = static_cast<Uint8>(PaletteColor::BLACK);
    cheevos_surface_->clear(CHEEVOS_BG_COLOR);

    // Escribe la lista de logros en la textura
    const std::string CHEEVOS_OWNER = "ACHIEVEMENTS";
    const std::string CHEEVOS_LIST_CAPTION = CHEEVOS_OWNER + " (" + std::to_string(Cheevos::get()->getTotalUnlockedAchievements()) + " / " + std::to_string(Cheevos::get()->size()) + ")";
    int pos = 2;
    TEXT->writeDX(TEXT_CENTER | TEXT_COLOR, cheevos_surface_->getWidth() / 2, pos, CHEEVOS_LIST_CAPTION, 1, stringToColor("bright_green"));
    pos += TEXT->getCharacterSize();
    const Uint8 CHEEVO_LOCKED_COLOR = stringToColor("white");
    const Uint8 CHEEVO_UNLOCKED_COLOR = stringToColor("bright_green");
    constexpr int LINE_X1 = (CHEEVOS_TEXTURE_WIDTH / 7) * 3;
    constexpr int LINE_X2 = LINE_X1 + ((CHEEVOS_TEXTURE_WIDTH / 7) * 1);

    for (const auto& cheevo : CHEEVOS_LIST) {
        const Uint8 CHEEVO_COLOR = cheevo.completed ? CHEEVO_UNLOCKED_COLOR : CHEEVO_LOCKED_COLOR;
        pos += CHEEVOS_PADDING;
        constexpr int HALF = CHEEVOS_PADDING / 2;
        cheevos_surface_->drawLine(LINE_X1, pos - HALF - 1, LINE_X2, pos - HALF - 1, CHEEVO_COLOR);
        TEXT->writeDX(TEXT_CENTER | TEXT_COLOR, CHEEVOS_TEXTURE_WIDTH / 2, pos, cheevo.caption, 1, CHEEVO_COLOR);
        pos += TEXT->getCharacterSize() + 1;
        TEXT->writeDX(TEXT_CENTER | TEXT_COLOR, CHEEVOS_TEXTURE_WIDTH / 2, pos, cheevo.description, 1, CHEEVO_COLOR);
        pos += TEXT->getCharacterSize();
    }

    // Restablece el RenderSurface
    Screen::get()->setRendererSurface(previuos_renderer);

    // Crea el sprite para el listado de logros
    cheevos_sprite_ = std::make_shared<SurfaceSprite>(cheevos_surface_, (GAMECANVAS_WIDTH - cheevos_surface_->getWidth()) / 2, CHEEVOS_TEXTURE_POS_Y, cheevos_surface_->getWidth(), cheevos_surface_->getHeight());
    cheevos_surface_view_ = {.x = 0, .y = 0, .w = cheevos_surface_->getWidth(), .h = CHEEVOS_TEXTURE_VIEW_HEIGHT};
    cheevos_sprite_->setClip(cheevos_surface_view_);
}

// Oculta la lista de logros
void Title::hideCheevosList() {
    show_cheevos_ = false;
    cheevos_surface_view_.y = 0;
    cheevos_sprite_->setClip(cheevos_surface_view_);
}