// stage_manager.cpp - Implementació del gestor de stages
// © 2026 JailDesigner

#include "stage_manager.hpp"

#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <iostream>

#include "core/audio/audio.hpp"
#include "core/defaults.hpp"
#include "core/locale/locale.hpp"
#include "stage_config.hpp"

namespace StageSystem {

    StageManager::StageManager(const StageSystemConfig* config)
        : config_(config) {
        if (config_ == nullptr) {
            std::cerr << "[StageManager] Error: config es null" << '\n';
        }
    }

    void StageManager::init() {
        stage_actual_ = 1;
        loadStage(stage_actual_);
        changeState(EstatStage::INIT_HUD);

        std::cout << "[StageManager] Inicialitzat a stage " << static_cast<int>(stage_actual_)
                  << '\n';
    }

    void StageManager::initDemo(uint8_t stage_id) {
        if (config_ == nullptr) {
            std::cerr << "[StageManager] Error: config es null, no es pot iniciar la demo\n";
            return;
        }
        // Clamp al rang vàlid: si l'escenari demana un stage inexistent, cau a 1.
        if (config_->findStage(stage_id) == nullptr) {
            stage_id = 1;
        }
        stage_actual_ = stage_id;
        loadStage(stage_actual_);
        changeState(EstatStage::PLAYING);

        std::cout << "[StageManager] Demo inicialitzada a stage "
                  << static_cast<int>(stage_actual_) << '\n';
    }

    void StageManager::update(float delta_time, bool pause_spawn) {
        switch (estat_) {
            case EstatStage::INIT_HUD:
                processInitHud(delta_time);
                break;

            case EstatStage::LEVEL_START:
                processLevelStart(delta_time);
                break;

            case EstatStage::PLAYING:
                processPlaying(delta_time, pause_spawn);
                break;

            case EstatStage::LEVEL_COMPLETED:
                processLevelCompleted(delta_time);
                break;
        }
    }

    void StageManager::markStageCompleted() {
        std::cout << "[StageManager] Stage " << static_cast<int>(stage_actual_) << " completat!"
                  << '\n';
        changeState(EstatStage::LEVEL_COMPLETED);
    }

    auto StageManager::isGameComplete() const -> bool {
        return stage_actual_ >= config_->metadata.total_stages &&
            estat_ == EstatStage::LEVEL_COMPLETED &&
            timer_transicio_ <= 0.0F;
    }

    auto StageManager::getCurrentConfig() const -> const StageConfig* {
        return config_->findStage(stage_actual_);
    }

    void StageManager::changeState(EstatStage nou_estat) {
        estat_ = nou_estat;

        // Set timer based on state type
        if (nou_estat == EstatStage::INIT_HUD) {
            timer_transicio_ = Defaults::Game::INIT_HUD_DURATION;
        } else if (nou_estat == EstatStage::LEVEL_START) {
            timer_transicio_ = Defaults::Game::LEVEL_START_DURATION;
        } else if (nou_estat == EstatStage::LEVEL_COMPLETED) {
            timer_transicio_ = Defaults::Game::LEVEL_COMPLETED_DURATION;
        }

        // Select random message when entering LEVEL_START
        if (nou_estat == EstatStage::LEVEL_START) {
            const std::size_t POOL = Locale::get().count("stage.start");
            const std::size_t INDEX = (POOL == 0) ? 0 : static_cast<std::size_t>(std::rand()) % POOL;
            missatge_level_start_actual_ = Locale::get().text("stage.start." + std::to_string(INDEX));

            // [NOU] Iniciar música al entrar en LEVEL_START (después de INIT_HUD)
            // Solo si no está sonant ya (per evitar reset en loops posteriors)
            if (Audio::getMusicState() != Audio::MusicState::PLAYING) {
                Audio::get()->playMusic("game.ogg");
            }
        }

        std::cout << "[StageManager] Canvi de state: ";
        switch (nou_estat) {
            case EstatStage::INIT_HUD:
                std::cout << "INIT_HUD";
                break;
            case EstatStage::LEVEL_START:
                std::cout << "LEVEL_START";
                break;
            case EstatStage::PLAYING:
                std::cout << "PLAYING";
                break;
            case EstatStage::LEVEL_COMPLETED:
                std::cout << "LEVEL_COMPLETED";
                break;
        }
        std::cout << '\n';
    }

    void StageManager::processInitHud(float delta_time) {
        timer_transicio_ -= delta_time;

        if (timer_transicio_ <= 0.0F) {
            changeState(EstatStage::LEVEL_START);
        }
    }

    void StageManager::processLevelStart(float delta_time) {
        timer_transicio_ -= delta_time;

        if (timer_transicio_ <= 0.0F) {
            changeState(EstatStage::PLAYING);
        }
    }

    void StageManager::processPlaying(float delta_time, bool pause_spawn) {
        // No-op: el WaveRunner s'actualitza des de GameScene::runStagePlaying,
        // no des d'ací. La signatura es manté per simetria amb les altres process*.
        (void)delta_time;
        (void)pause_spawn;
    }

    void StageManager::processLevelCompleted(float delta_time) {
        timer_transicio_ -= delta_time;

        if (timer_transicio_ <= 0.0F) {
            // Advance to next stage
            stage_actual_++;

            // Loop back to stage 1 after final stage
            if (stage_actual_ > config_->metadata.total_stages) {
                stage_actual_ = 1;
                std::cout << "[StageManager] Todas las stages completades! Tornant a stage 1"
                          << '\n';
            }

            // Load next stage
            loadStage(stage_actual_);
            changeState(EstatStage::LEVEL_START);
        }
    }

    void StageManager::loadStage(uint8_t stage_id) {
        const StageConfig* stage_config = config_->findStage(stage_id);
        if (stage_config == nullptr) {
            std::cerr << "[StageManager] Error: no es pot trobar stage " << static_cast<int>(stage_id)
                      << '\n';
            return;
        }

        wave_runner_.configure(stage_config);
        wave_runner_.start();

        std::cout << "[StageManager] Carregat stage " << static_cast<int>(stage_id) << ": "
                  << stage_config->waves.size() << " onades" << '\n';
    }

}  // namespace StageSystem
