// stage_loader.cpp - Implementació del carregador de configuración YAML
// © 2026 JailDesigner

#include "stage_loader.hpp"

#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <exception>
#include <iostream>
#include <memory>
#include <sstream>
#include <string>
#include <vector>

#include "core/resources/resource_helper.hpp"
#include "external/fkyaml_node.hpp"
#include "stage_config.hpp"

namespace StageSystem {

auto StageLoader::load(const std::string& path) -> std::unique_ptr<StageSystemConfig> {
    try {
        // Normalize path: "data/stages/stages.yaml" → "stages/stages.yaml"
        std::string normalized = path;
        if (normalized.starts_with("data/")) {
            normalized = normalized.substr(5);
        }

        // Load from resource system
        std::vector<uint8_t> data = Resource::Helper::loadFile(normalized);
        if (data.empty()) {
            std::cerr << "[StageLoader] Error: no es pot load " << normalized << '\n';
            return nullptr;
        }

        // Convert to string
        std::string yaml_content(data.begin(), data.end());
        std::stringstream stream(yaml_content);

        // Parse YAML
        fkyaml::node yaml = fkyaml::node::deserialize(stream);
        auto config = std::make_unique<StageSystemConfig>();

        // Parse metadata
        if (!yaml.contains("metadata")) {
            std::cerr << "[StageLoader] Error: falta camp 'metadata'" << '\n';
            return nullptr;
        }
        if (!parseMetadata(yaml["metadata"], config->metadata)) {
            return nullptr;
        }

        // Parse stages
        if (!yaml.contains("stages")) {
            std::cerr << "[StageLoader] Error: falta camp 'stages'" << '\n';
            return nullptr;
        }

        if (!yaml["stages"].is_sequence()) {
            std::cerr << "[StageLoader] Error: 'stages' ha de ser una list" << '\n';
            return nullptr;
        }

        for (const auto& stage_yaml : yaml["stages"]) {
            StageConfig stage;
            if (!parseStage(stage_yaml, stage)) {
                return nullptr;
            }
            config->stages.push_back(stage);
        }

        // Validar configuración
        if (!validateConfig(*config)) {
            return nullptr;
        }

        std::cout << "[StageLoader] Carregats " << config->stages.size()
                  << " stages correctament" << '\n';
        return config;

    } catch (const std::exception& e) {
        std::cerr << "[StageLoader] Excepció: " << e.what() << '\n';
        return nullptr;
    }
}

auto StageLoader::parseMetadata(const fkyaml::node& yaml, MetadataStages& meta) -> bool {
    try {
        if (!yaml.contains("version") || !yaml.contains("total_stages")) {
            std::cerr << "[StageLoader] Error: metadata incompleta" << '\n';
            return false;
        }

        meta.version = yaml["version"].get_value<std::string>();
        meta.total_stages = yaml["total_stages"].get_value<uint8_t>();
        meta.descripcio = yaml.contains("description")
            ? yaml["description"].get_value<std::string>()
            : "";

        return true;
    } catch (const std::exception& e) {
        std::cerr << "[StageLoader] Error parsing metadata: " << e.what() << '\n';
        return false;
    }
}

auto StageLoader::parseStage(const fkyaml::node& yaml, StageConfig& stage) -> bool {
    try {
        if (!yaml.contains("stage_id") || !yaml.contains("total_enemies") ||
            !yaml.contains("spawn_config") || !yaml.contains("enemy_distribution") ||
            !yaml.contains("difficulty_multipliers")) {
            std::cerr << "[StageLoader] Error: stage incompleta" << '\n';
            return false;
        }

        stage.stage_id = yaml["stage_id"].get_value<uint8_t>();
        stage.total_enemies = yaml["total_enemies"].get_value<uint8_t>();

        if (!parseSpawnConfig(yaml["spawn_config"], stage.config_spawn)) {
            return false;
        }
        if (!parseDistribution(yaml["enemy_distribution"], stage.distribucio)) {
            return false;
        }
        if (!parseMultipliers(yaml["difficulty_multipliers"], stage.multiplicadors)) {
            return false;
        }

        if (!stage.isValid()) {
            std::cerr << "[StageLoader] Error: stage " << static_cast<int>(stage.stage_id)
                      << " no es vàlid" << '\n';
            return false;
        }

        return true;
    } catch (const std::exception& e) {
        std::cerr << "[StageLoader] Error parsing stage: " << e.what() << '\n';
        return false;
    }
}

auto StageLoader::parseSpawnConfig(const fkyaml::node& yaml, ConfigSpawn& config) -> bool {
    try {
        if (!yaml.contains("mode") || !yaml.contains("initial_delay") ||
            !yaml.contains("spawn_interval")) {
            std::cerr << "[StageLoader] Error: spawn_config incompleta" << '\n';
            return false;
        }

        auto mode_str = yaml["mode"].get_value<std::string>();
        config.mode = parseSpawnMode(mode_str);
        config.delay_inicial = yaml["initial_delay"].get_value<float>();
        config.interval_spawn = yaml["spawn_interval"].get_value<float>();

        return true;
    } catch (const std::exception& e) {
        std::cerr << "[StageLoader] Error parsing spawn_config: " << e.what() << '\n';
        return false;
    }
}

auto StageLoader::parseDistribution(const fkyaml::node& yaml, DistribucioEnemics& dist) -> bool {
    try {
        if (!yaml.contains("pentagon") || !yaml.contains("cuadrado") ||
            !yaml.contains("molinillo")) {
            std::cerr << "[StageLoader] Error: enemy_distribution incompleta" << '\n';
            return false;
        }

        dist.pentagon = yaml["pentagon"].get_value<uint8_t>();
        dist.cuadrado = yaml["cuadrado"].get_value<uint8_t>();
        dist.molinillo = yaml["molinillo"].get_value<uint8_t>();

        // Validar que suma 100
        int sum = dist.pentagon + dist.cuadrado + dist.molinillo;
        if (sum != 100) {
            std::cerr << "[StageLoader] Error: distribució no suma 100 (suma=" << sum << ")" << '\n';
            return false;
        }

        return true;
    } catch (const std::exception& e) {
        std::cerr << "[StageLoader] Error parsing distribution: " << e.what() << '\n';
        return false;
    }
}

auto StageLoader::parseMultipliers(const fkyaml::node& yaml, MultiplicadorsDificultat& mult) -> bool {
    try {
        if (!yaml.contains("speed_multiplier") || !yaml.contains("rotation_multiplier") ||
            !yaml.contains("tracking_strength")) {
            std::cerr << "[StageLoader] Error: difficulty_multipliers incompleta" << '\n';
            return false;
        }

        mult.velocity = yaml["speed_multiplier"].get_value<float>();
        mult.rotation = yaml["rotation_multiplier"].get_value<float>();
        mult.tracking_strength = yaml["tracking_strength"].get_value<float>();

        // Validar rangs raonables
        if (mult.velocity < 0.1F || mult.velocity > 5.0F) {
            std::cerr << "[StageLoader] Warning: speed_multiplier fuera de rang (0.1-5.0)" << '\n';
        }
        if (mult.rotation < 0.1F || mult.rotation > 5.0F) {
            std::cerr << "[StageLoader] Warning: rotation_multiplier fuera de rang (0.1-5.0)" << '\n';
        }
        if (mult.tracking_strength < 0.0F || mult.tracking_strength > 2.0F) {
            std::cerr << "[StageLoader] Warning: tracking_strength fuera de rang (0.0-2.0)" << '\n';
        }

        return true;
    } catch (const std::exception& e) {
        std::cerr << "[StageLoader] Error parsing multipliers: " << e.what() << '\n';
        return false;
    }
}

auto StageLoader::parseSpawnMode(const std::string& mode_str) -> ModeSpawn {
    if (mode_str == "progressive") {
        return ModeSpawn::PROGRESSIVE;
    }
    if (mode_str == "immediate") {
        return ModeSpawn::IMMEDIATE;
    }
    if (mode_str == "wave") {
        return ModeSpawn::WAVE;
    }
    std::cerr << "[StageLoader] Warning: mode de spawn desconegut '" << mode_str
              << "', usant PROGRESSIVE" << '\n';
    return ModeSpawn::PROGRESSIVE;
}

auto StageLoader::validateConfig(const StageSystemConfig& config) -> bool {
    if (config.stages.empty()) {
        std::cerr << "[StageLoader] Error: sin stage carregat" << '\n';
        return false;
    }

    if (config.stages.size() != config.metadata.total_stages) {
        std::cerr << "[StageLoader] Warning: nombre de stages (" << config.stages.size()
                  << ") no coincideix con metadata.total_stages ("
                  << static_cast<int>(config.metadata.total_stages) << ")" << '\n';
    }

    // Validar stage_id consecutius
    for (size_t i = 0; i < config.stages.size(); i++) {
        if (config.stages[i].stage_id != i + 1) {
            std::cerr << "[StageLoader] Error: stage_id no consecutius (esperat "
                      << i + 1 << ", trobat " << static_cast<int>(config.stages[i].stage_id)
                      << ")" << '\n';
            return false;
        }
    }

    return true;
}

}  // namespace StageSystem
