// wave_runner.cpp - Implementació de l'executor d'onades
// © 2026 JailDesigner

#include "wave_runner.hpp"

#include <algorithm>
#include <array>
#include <cstdint>
#include <iostream>

#include "core/types.hpp"
#include "game/entities/enemy.hpp"
#include "stage_config.hpp"

namespace StageSystem {

    void WaveRunner::configure(const StageConfig* config) {
        config_ = config;
    }

    void WaveRunner::start() {
        reset();
        if ((config_ == nullptr) || config_->waves.empty()) {
            std::cerr << "[WaveRunner] Error: config null o sense onades" << '\n';
            all_waves_emitted_ = true;
            return;
        }
        std::cout << "[WaveRunner] Stage " << static_cast<int>(config_->stage_id)
                  << ": " << config_->waves.size() << " onades" << '\n';
    }

    void WaveRunner::reset() {
        wave_index_ = 0;
        wave_elapsed_ = 0.0F;
        spawns_emitted_ = 0;
        all_waves_emitted_ = false;
    }

    void WaveRunner::update(float delta_time, std::array<Enemy, 15>& orni_array, bool pausar) {
        if (pausar || config_ == nullptr || all_waves_emitted_) {
            // Si ja s'han emès totes, encara hem de poder avaluar stageComplete.
            return;
        }

        const WaveConfig* wave = currentWave();
        if (wave == nullptr) {
            all_waves_emitted_ = true;
            return;
        }

        wave_elapsed_ += delta_time;

        emitPendingSpawns(orni_array);

        if (shouldAdvance(orni_array)) {
            advanceWave();
        }
    }

    auto WaveRunner::stageComplete(const std::array<Enemy, 15>& orni_array) const -> bool {
        return all_waves_emitted_ && getAliveEnemyCount(orni_array) == 0;
    }

    auto WaveRunner::getAliveEnemyCount(const std::array<Enemy, 15>& orni_array) -> uint8_t {
        uint8_t count = 0;
        for (const auto& enemy : orni_array) {
            if (enemy.isActive()) {
                count++;
            }
        }
        return count;
    }

    auto WaveRunner::currentWave() const -> const WaveConfig* {
        if (config_ == nullptr || wave_index_ >= config_->waves.size()) {
            return nullptr;
        }
        return &config_->waves[wave_index_];
    }

    void WaveRunner::emitPendingSpawns(std::array<Enemy, 15>& orni_array) {
        const WaveConfig* wave = currentWave();
        if (wave == nullptr) {
            return;
        }

        // Spawn[i] toca a t = i * spawn_interval (i=0 → t=0).
        while (spawns_emitted_ < wave->spawn.size()) {
            const float SPAWN_T = static_cast<float>(spawns_emitted_) * wave->spawn_interval;
            if (wave_elapsed_ < SPAWN_T) {
                break;
            }

            // Busca un slot lliure a l'arena. Si no n'hi ha, ho intentem el següent frame.
            bool emitted = false;
            for (auto& enemy : orni_array) {
                if (!enemy.isActive()) {
                    spawnEnemy(enemy, wave->spawn[spawns_emitted_]);
                    emitted = true;
                    break;
                }
            }
            if (!emitted) {
                break;
            }
            spawns_emitted_++;
        }
    }

    void WaveRunner::spawnEnemy(Enemy& enemy, EnemyType type) {
        enemy.init(type, ship_position_);
        applyMultipliers(enemy);
    }

    void WaveRunner::applyMultipliers(Enemy& enemy) const {
        if (config_ == nullptr) {
            return;
        }
        enemy.setVelocity(enemy.getBaseVelocity() * config_->multiplicadors.velocity);
        enemy.setRotation(enemy.getBaseRotation() * config_->multiplicadors.rotation);
        enemy.setTrackingStrength(config_->multiplicadors.tracking_strength);
    }

    auto WaveRunner::shouldAdvance(const std::array<Enemy, 15>& orni_array) const -> bool {
        const WaveConfig* wave = currentWave();
        if (wave == nullptr) {
            return false;
        }

        // Una wave només pot avançar després d'haver emès tots els seus spawns.
        const bool ALL_SPAWNED = spawns_emitted_ >= wave->spawn.size();

        if (wave->next.has_timeout && wave_elapsed_ >= wave->next.timeout) {
            // El timeout NO requereix all_spawned: si la wave triga més que el seu
            // propi timeout (cas patològic amb spawn_interval massa gran), forcem
            // avançar igualment per no encallar-nos.
            return true;
        }

        if (wave->next.on_all_dead) {
            return ALL_SPAWNED && getAliveEnemyCount(orni_array) == 0;
        }

        return false;
    }

    void WaveRunner::advanceWave() {
        wave_index_++;
        wave_elapsed_ = 0.0F;
        spawns_emitted_ = 0;

        if (config_ == nullptr || wave_index_ >= config_->waves.size()) {
            all_waves_emitted_ = true;
            std::cout << "[WaveRunner] Totes les onades emeses" << '\n';
            return;
        }
        std::cout << "[WaveRunner] Avança a onada " << static_cast<int>(wave_index_ + 1)
                  << "/" << config_->waves.size() << '\n';
    }

}  // namespace StageSystem
