// stage_loader.cpp - Implementació del carregador de configuració YAML
// © 2025 Orni Attack

#include "stage_loader.hpp"

#include <fstream>
#include <iostream>
#include <sstream>

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

namespace StageSystem {

std::unique_ptr<ConfigSistemaStages> StageLoader::carregar(const std::string& path) {
    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 carregar " << normalized << std::endl;
            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<ConfigSistemaStages>();

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

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

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

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

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

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

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

bool StageLoader::parse_metadata(const fkyaml::node& yaml, MetadataStages& meta) {
    try {
        if (!yaml.contains("version") || !yaml.contains("total_stages")) {
            std::cerr << "[StageLoader] Error: metadata incompleta" << std::endl;
            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() << std::endl;
        return false;
    }
}

bool StageLoader::parse_stage(const fkyaml::node& yaml, ConfigStage& stage) {
    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" << std::endl;
            return false;
        }

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

        if (!parse_spawn_config(yaml["spawn_config"], stage.config_spawn)) {
            return false;
        }
        if (!parse_distribution(yaml["enemy_distribution"], stage.distribucio)) {
            return false;
        }
        if (!parse_multipliers(yaml["difficulty_multipliers"], stage.multiplicadors)) {
            return false;
        }

        if (!stage.es_valid()) {
            std::cerr << "[StageLoader] Error: stage " << static_cast<int>(stage.stage_id)
                      << " no és vàlid" << std::endl;
            return false;
        }

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

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

        auto mode_str = yaml["mode"].get_value<std::string>();
        config.mode = parse_spawn_mode(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() << std::endl;
        return false;
    }
}

bool StageLoader::parse_distribution(const fkyaml::node& yaml, DistribucioEnemics& dist) {
    try {
        if (!yaml.contains("pentagon") || !yaml.contains("quadrat") ||
            !yaml.contains("molinillo")) {
            std::cerr << "[StageLoader] Error: enemy_distribution incompleta" << std::endl;
            return false;
        }

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

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

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

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

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

        // Validar rangs raonables
        if (mult.velocitat < 0.1F || mult.velocitat > 5.0F) {
            std::cerr << "[StageLoader] Warning: speed_multiplier fora de rang (0.1-5.0)" << std::endl;
        }
        if (mult.rotacio < 0.1F || mult.rotacio > 5.0F) {
            std::cerr << "[StageLoader] Warning: rotation_multiplier fora de rang (0.1-5.0)" << std::endl;
        }
        if (mult.tracking_strength < 0.0F || mult.tracking_strength > 2.0F) {
            std::cerr << "[StageLoader] Warning: tracking_strength fora de rang (0.0-2.0)" << std::endl;
        }

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

ModeSpawn StageLoader::parse_spawn_mode(const std::string& mode_str) {
    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" << std::endl;
    return ModeSpawn::PROGRESSIVE;
}

bool StageLoader::validar_config(const ConfigSistemaStages& config) {
    if (config.stages.empty()) {
        std::cerr << "[StageLoader] Error: cap stage carregat" << std::endl;
        return false;
    }

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

    // 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)
                      << ")" << std::endl;
            return false;
        }
    }

    return true;
}

}  // namespace StageSystem
