#include "game/gameplay/stage.hpp"

#include <algorithm>  // Para max, min
#include <exception>  // Para exception
#include <fstream>    // Para basic_istream, basic_ifstream, ifstream, stringstream
#include <sstream>    // Para basic_stringstream
#include <utility>    // Para move

// Implementación de StageData
StageData::StageData(int power_to_complete, int min_menace, int max_menace, std::string name)
    : status_(StageStatus::LOCKED),
      name_(std::move(name)),
      power_to_complete_(power_to_complete),
      min_menace_(min_menace),
      max_menace_(max_menace) {}

// Implementación de StageManager
StageManager::StageManager()
    : power_change_callback_(nullptr),
      power_collection_state_(PowerCollectionState::ENABLED),
      current_stage_index_(0),
      current_power_(0),
      total_power_(0) { initialize(); }

void StageManager::initialize() {
    stages_.clear();
    createDefaultStages();
    reset();
}

void StageManager::initialize(const std::string& stages_file) {
    stages_.clear();

    // Intentar cargar desde archivo, si falla usar valores predeterminados
    if (!loadStagesFromFile(stages_file)) {
        createDefaultStages();
    }

    reset();
}

void StageManager::reset() {
    current_power_ = 0;
    total_power_ = 0;
    current_stage_index_ = 0;
    power_collection_state_ = PowerCollectionState::ENABLED;
    updateStageStatuses();
}

void StageManager::createDefaultStages() {
    // Crear las 10 fases predeterminadas con dificultad progresiva
    stages_.emplace_back(200, 7 + (4 * 1), 7 + (4 * 3), "Tutorial");
    stages_.emplace_back(300, 7 + (4 * 2), 7 + (4 * 4), "Primeros pasos");
    stages_.emplace_back(600, 7 + (4 * 3), 7 + (4 * 5), "Intensificación");
    stages_.emplace_back(600, 7 + (4 * 3), 7 + (4 * 5), "Persistencia");
    stages_.emplace_back(600, 7 + (4 * 4), 7 + (4 * 6), "Desafío medio");
    stages_.emplace_back(600, 7 + (4 * 4), 7 + (4 * 6), "Resistencia");
    stages_.emplace_back(650, 7 + (4 * 5), 7 + (4 * 7), "Aproximación final");
    stages_.emplace_back(750, 7 + (4 * 5), 7 + (4 * 7), "Penúltimo obstáculo");
    stages_.emplace_back(850, 7 + (4 * 6), 7 + (4 * 8), "Clímax");
    stages_.emplace_back(950, 7 + (4 * 7), 7 + (4 * 10), "Maestría");
}

auto StageManager::loadStagesFromFile(const std::string& filename) -> bool {
    std::ifstream file(filename);
    if (!file.is_open()) {
        return false;  // No se pudo abrir el archivo
    }

    std::string line;

    while (std::getline(file, line)) {
        // Ignorar líneas vacías y comentarios (líneas que empiezan con #)
        if (line.empty() || line[0] == '#') {
            continue;
        }

        // Parsear línea: power_to_complete,min_menace,max_menace,name
        std::stringstream ss(line);
        std::string token;
        std::vector<std::string> tokens;

        // Dividir por comas
        while (std::getline(ss, token, ',')) {
            // Eliminar espacios en blanco al inicio y final
            token.erase(0, token.find_first_not_of(" \t"));
            token.erase(token.find_last_not_of(" \t") + 1);
            tokens.push_back(token);
        }

        // Verificar que tenemos exactamente 4 campos
        if (tokens.size() != 4) {
            // Error de formato, continuar con la siguiente línea
            continue;
        }

        try {
            // Convertir a enteros los primeros tres campos
            int power_to_complete = std::stoi(tokens[0]);
            int min_menace = std::stoi(tokens[1]);
            int max_menace = std::stoi(tokens[2]);
            std::string name = tokens[3];

            // Validar valores
            if (power_to_complete <= 0 || min_menace < 0 || max_menace < min_menace) {
                continue;  // Valores inválidos, saltar línea
            }

            // Crear y añadir la fase
            stages_.emplace_back(power_to_complete, min_menace, max_menace, name);

        } catch (const std::exception&) {
            // Error de conversión, continuar con la siguiente línea
            continue;
        }
    }

    file.close();

    // Verificar que se cargó al menos una fase
    return !stages_.empty();
}

auto StageManager::advanceToNextStage() -> bool {
    if (!isCurrentStageCompleted() || current_stage_index_ >= stages_.size() - 1) {
        return false;
    }

    current_stage_index_++;
    current_power_ = 0;  // Reiniciar poder para la nueva fase
    updateStageStatuses();
    return true;
}

auto StageManager::jumpToStage(size_t target_stage_index) -> bool {
    if (!validateStageIndex(target_stage_index)) {
        return false;
    }

    // Calcular el poder acumulado hasta la fase objetivo
    int accumulated_power = 0;
    for (size_t i = 0; i < target_stage_index; ++i) {
        accumulated_power += stages_[i].getPowerToComplete();
    }

    // Actualizar estado
    current_stage_index_ = target_stage_index;
    current_power_ = 0;                // Comenzar la fase objetivo sin poder
    total_power_ = accumulated_power;  // Poder total como si se hubieran completado las anteriores

    updateStageStatuses();
    return true;
}

auto StageManager::setTotalPower(int target_total_power) -> bool {
    if (target_total_power < 0) {
        return false;
    }

    int total_power_needed = getTotalPowerNeededToCompleteGame();
    if (target_total_power > total_power_needed) {
        return false;
    }

    // Calcular en qué fase debería estar y cuánto poder de esa fase
    int accumulated_power = 0;
    size_t target_stage_index = 0;
    int target_current_power = 0;

    for (size_t i = 0; i < stages_.size(); ++i) {
        int stage_power = stages_[i].getPowerToComplete();

        if (accumulated_power + stage_power > target_total_power) {
            // El objetivo está dentro de esta fase
            target_stage_index = i;
            target_current_power = target_total_power - accumulated_power;
            break;
        }

        accumulated_power += stage_power;

        if (accumulated_power == target_total_power) {
            // El objetivo coincide exactamente con el final de esta fase
            // Mover a la siguiente fase (si existe) con power 0
            target_stage_index = (i + 1 < stages_.size()) ? i + 1 : i;
            target_current_power = (i + 1 < stages_.size()) ? 0 : stage_power;
            break;
        }
    }

    // Actualizar estado
    current_stage_index_ = target_stage_index;
    current_power_ = target_current_power;
    total_power_ = target_total_power;

    updateStageStatuses();
    return true;
}

auto StageManager::subtractPower(int amount) -> bool {
    if (amount <= 0 || current_power_ < amount) {
        return false;
    }

    current_power_ -= amount;
    updateStageStatuses();
    return true;
}

void StageManager::enablePowerCollection() {
    power_collection_state_ = PowerCollectionState::ENABLED;
}

void StageManager::disablePowerCollection() {
    power_collection_state_ = PowerCollectionState::DISABLED;
}

auto StageManager::getCurrentStage() const -> std::optional<StageData> {
    return getStage(current_stage_index_);
}

auto StageManager::getStage(size_t index) const -> std::optional<StageData> {
    if (!validateStageIndex(index)) {
        return std::nullopt;
    }
    return stages_[index];
}

auto StageManager::isCurrentStageCompleted() const -> bool {
    auto current_stage = getCurrentStage();
    if (!current_stage.has_value()) {
        return false;
    }

    return current_power_ >= current_stage->getPowerToComplete();
}

auto StageManager::isGameCompleted() const -> bool {
    return current_stage_index_ >= stages_.size() - 1 && isCurrentStageCompleted();
}

auto StageManager::getProgressPercentage() const -> double {
    if (stages_.empty()) {
        return 0.0;
    }

    int total_power_needed = getTotalPowerNeededToCompleteGame();
    if (total_power_needed == 0) {
        return 100.0;
    }

    return (static_cast<double>(total_power_) / total_power_needed) * 100.0;
}

auto StageManager::getCurrentStageProgressPercentage() const -> double {
    return getCurrentStageProgressFraction() * 100.0;
}

auto StageManager::getCurrentStageProgressFraction() const -> double {
    auto current_stage = getCurrentStage();
    if (!current_stage.has_value()) {
        return 0.0;
    }

    int power_needed = current_stage->getPowerToComplete();
    if (power_needed == 0) {
        return 1.0;
    }

    // Devuelve una fracción entre 0.0 y 1.0
    double fraction = static_cast<double>(current_power_) / power_needed;
    return std::min(fraction, 1.0);
}

auto StageManager::getPowerNeededForCurrentStage() const -> int {
    auto current_stage = getCurrentStage();
    if (!current_stage.has_value()) {
        return 0;
    }

    return std::max(0, current_stage->getPowerToComplete() - current_power_);
}

auto StageManager::getTotalPowerNeededToCompleteGame() const -> int {
    int total_power_needed = 0;
    for (const auto& stage : stages_) {
        total_power_needed += stage.getPowerToComplete();
    }
    return total_power_needed;
}

auto StageManager::getPowerNeededToReachStage(size_t target_stage_index) const -> int {
    if (!validateStageIndex(target_stage_index)) {
        return 0;
    }

    int power_needed = 0;
    for (size_t i = 0; i < target_stage_index; ++i) {
        power_needed += stages_[i].getPowerToComplete();
    }
    return power_needed;
}

// Implementación de la interfaz IStageInfo
auto StageManager::canCollectPower() const -> bool {
    return power_collection_state_ == PowerCollectionState::ENABLED;
}

void StageManager::addPower(int amount) {
    if (amount <= 0 || !canCollectPower()) {
        return;
    }

    current_power_ += amount;
    total_power_ += amount;

    // Ejecutar callback si está registrado
    if (power_change_callback_) {
        power_change_callback_(amount);
    }

    // Verificar si se completó la fase actual
    if (isCurrentStageCompleted()) {
        auto current_stage = getCurrentStage();
        if (current_stage.has_value()) {
            stages_[current_stage_index_].setStatus(StageStatus::COMPLETED);
        }
    }

    updateStageStatuses();
}

auto StageManager::getCurrentMenaceLevel() const -> int {
    auto current_stage = getCurrentStage();
    if (!current_stage.has_value()) {
        return 0;
    }

    return current_stage->getMinMenace();
}

// Gestión de callbacks
void StageManager::setPowerChangeCallback(PowerChangeCallback callback) {
    power_change_callback_ = std::move(callback);
}

void StageManager::removePowerChangeCallback() {
    power_change_callback_ = nullptr;
}

// Métodos privados
auto StageManager::validateStageIndex(size_t index) const -> bool {
    return index < stages_.size();
}

void StageManager::updateStageStatuses() {
    // Actualizar el estado de cada fase según su posición relativa a la actual
    for (size_t i = 0; i < stages_.size(); ++i) {
        if (i < current_stage_index_) {
            stages_[i].setStatus(StageStatus::COMPLETED);
        } else if (i == current_stage_index_) {
            stages_[i].setStatus(StageStatus::IN_PROGRESS);
        } else {
            stages_[i].setStatus(StageStatus::LOCKED);
        }
    }
}