#include "game/gameplay/enter_name.hpp"

#include <array>        // Para array
#include <cstdlib>      // Para rand
#include <string_view>  // Para basic_string_view, string_view

// Constructor
EnterName::EnterName() = default;

// Inicializa el objeto
void EnterName::init(const std::string& name) {
    name_ = sanitizeName(name);
    selected_index_ = 0;

    // Si el nombre está completo, cambia el caracter seleccionado a el caracter de finalizar
    if (!nameIsEmpty()) {
        forceEndCharSelected();
    }
}

// Incrementa el índice del carácter seleccionado
void EnterName::incIndex() {
    ++selected_index_;
    if (selected_index_ >= character_list_.size()) {
        selected_index_ = 0;
    }
}

// Decrementa el índice del carácter seleccionado
void EnterName::decIndex() {
    if (selected_index_ == 0) {
        selected_index_ = character_list_.size() - 1;
    } else {
        --selected_index_;
    }
}

// Añade el carácter seleccionado al nombre
void EnterName::addCharacter() {
    // Si no es el ultimo caracter, lo añade
    if (name_.length() < MAX_NAME_SIZE) {
        name_.push_back(character_list_[selected_index_]);
    }

    // Si el nombre está completo, cambia el caracter seleccionado a el caracter de finalizar
    if (nameIsFull()) {
        forceEndCharSelected();
    }
}

// Elimina el último carácter del nombre
void EnterName::removeLastCharacter() {
    if (!name_.empty()) {
        name_.pop_back();
    }
}

// Devuelve el carácter seleccionado con offset relativo como string
auto EnterName::getSelectedCharacter(int offset) const -> std::string {
    // Calcular el índice con offset, con wrap-around circular
    int size = static_cast<int>(character_list_.size());
    int index = (selected_index_ + offset) % size;

    // Manejar índices negativos (hacer wrap-around hacia atrás)
    if (index < 0) {
        index += size;
    }

    return {1, character_list_[index]};
}

// Devuelve el carrusel completo de caracteres centrado en el seleccionado
auto EnterName::getCarousel(int size) const -> std::string {
    // Asegurar que el tamaño sea impar para tener un centro claro
    if (size % 2 == 0) {
        ++size;
    }

    std::string carousel;
    carousel.reserve(size);  // Optimización: reservar memoria de antemano

    int half = size / 2;

    // Construir desde -half hasta +half (inclusive)
    for (int offset = -half; offset <= half; ++offset) {
        carousel += getSelectedCharacter(offset);
    }

    return carousel;
}

// Valida y limpia el nombre: solo caracteres legales y longitud máxima
auto EnterName::sanitizeName(const std::string& name) const -> std::string {
    std::string sanitized;

    for (size_t i = 0; i < name.length() && sanitized.length() < MAX_NAME_SIZE; ++i) {
        // Verifica si el carácter está en la lista permitida
        if (character_list_.find(name[i]) != std::string::npos) {
            sanitized.push_back(name[i]);
        }
    }

    return sanitized;
}

// Devuelve un nombre al azar
auto EnterName::getRandomName() -> std::string {
    static constexpr std::array<std::string_view, 8> NAMES = {
        "BAL1",
        "TABE",
        "DOC",
        "MON",
        "SAM1",
        "JORDI",
        "JDES",
        "PEPE"};
    return std::string(NAMES[rand() % NAMES.size()]);
}

// Obtiene el nombre final introducido
auto EnterName::getFinalName() -> std::string {
    if (name_.empty()) {
        name_ = getRandomName();
    }
    return name_;
}
