#include "../include/PlanetaryCore.h"
#include <algorithm>
#include <cmath>

namespace warfactory {

PlanetaryCore::PlanetaryCore()
    : ASerializable("planetary_core"), core_temperature(6000.0f), core_pressure(360000.0f), core_composition(),
      mantle_temperature(3500.0f), volcanic_activity_level(0.5f), geological_age(4500.0f),
      last_impact_time(0.0f), total_impact_energy(0.0f) {

    // Initialize default core composition (simplified Earth-like)
    core_composition["iron"] = 80.0f;
    core_composition["nickel"] = 15.0f;
    core_composition["sulfur"] = 3.0f;
    core_composition["oxygen"] = 2.0f;
}

PlanetaryCore::PlanetaryCore(float temp, float pressure, const std::map<std::string, float>& composition)
    : ASerializable("planetary_core"), core_temperature(temp), core_pressure(pressure), core_composition(composition),
      mantle_temperature(temp * 0.6f), volcanic_activity_level(0.5f), geological_age(4500.0f),
      last_impact_time(0.0f), total_impact_energy(0.0f) {
}

// ========================================
// CORE PROPERTIES
// ========================================

void PlanetaryCore::setCoreTemperature(float temperature) {
    core_temperature = std::max(0.0f, temperature);

    // Update mantle temperature based on core temperature
    mantle_temperature = core_temperature * 0.58f; // Typical ratio

    // Update volcanic activity based on temperature
    updateVolcanicActivity();
}

void PlanetaryCore::addCoreComposition(const std::string& element, float percentage) {
    core_composition[element] = std::clamp(percentage, 0.0f, 100.0f);

    // Normalize composition to ensure total doesn't exceed 100%
    normalizeComposition();
}

float PlanetaryCore::getCoreComposition(const std::string& element) const {
    const std::map<std::string, float>::const_iterator it = core_composition.find(element);
    return (it != core_composition.end()) ? it->second : 0.0f;
}

// ========================================
// IMPACT EFFECTS
// ========================================

void PlanetaryCore::receiveImpactEnergy(float energy, float impact_time) {
    total_impact_energy += energy;
    last_impact_time = impact_time;

    // Large impacts affect core temperature
    const float temperature_increase = energy / 1000000.0f; // Simplified conversion
    setCoreTemperature(core_temperature + temperature_increase);

    // Impacts can trigger volcanic activity
    const float activity_increase = energy / 5000000.0f;
    volcanic_activity_level = std::min(1.0f, volcanic_activity_level + activity_increase);
}

void PlanetaryCore::processGeologicalCooling(float time_step_millions_years) {
    geological_age += time_step_millions_years;

    // Natural cooling of the planet over geological time
    const float cooling_rate = 50.0f; // Degrees per million years (simplified)
    const float temperature_loss = cooling_rate * time_step_millions_years;

    core_temperature = std::max(1000.0f, core_temperature - temperature_loss);
    mantle_temperature = std::max(800.0f, mantle_temperature - temperature_loss * 0.8f);

    // Volcanic activity decreases with cooling
    volcanic_activity_level = std::max(0.0f, volcanic_activity_level - time_step_millions_years * 0.01f);
}

float PlanetaryCore::calculateSurfaceHeatFlow() const {
    // Heat flow from core to surface (watts per square meter)
    const float base_heat_flow = 0.087f; // Earth average
    const float temperature_factor = core_temperature / 6000.0f; // Normalized to Earth core
    const float activity_factor = 1.0f + volcanic_activity_level;

    return base_heat_flow * temperature_factor * activity_factor;
}

// ========================================
// RESOURCE GENERATION
// ========================================

std::vector<std::string> PlanetaryCore::getAvailableResources() const {
    std::vector<std::string> available_resources;

    // Core composition determines available resources
    for (const std::pair<const std::string, float>& element : core_composition) {
        if (element.second > 1.0f) { // Only include elements with >1% composition
            available_resources.push_back(element.first);

            // Add derivative resources based on core elements
            if (element.first == "iron") {
                available_resources.push_back("iron_ore");
                if (core_temperature > 4000.0f) {
                    available_resources.push_back("rare_metals");
                }
            } else if (element.first == "sulfur") {
                available_resources.push_back("sulfur_deposits");
            } else if (element.first == "carbon") {
                available_resources.push_back("diamonds");
                if (geological_age > 3000.0f) {
                    available_resources.push_back("coal_deposits");
                }
            }
        }
    }

    return available_resources;
}

float PlanetaryCore::getResourceAbundance(const std::string& resource) const {
    // Base abundance from core composition
    float base_abundance = getCoreComposition(resource);

    // Adjust based on geological processes
    const float age_factor = std::min(2.0f, geological_age / 2000.0f);
    const float activity_factor = 1.0f + volcanic_activity_level * 0.5f;

    return base_abundance * age_factor * activity_factor;
}

// ========================================
// SERIALIZATION
// ========================================

json PlanetaryCore::serialize() const {
    json data;
    data["core_temperature"] = core_temperature;
    data["core_pressure"] = core_pressure;
    data["mantle_temperature"] = mantle_temperature;
    data["volcanic_activity_level"] = volcanic_activity_level;
    data["geological_age"] = geological_age;
    data["last_impact_time"] = last_impact_time;
    data["total_impact_energy"] = total_impact_energy;

    // Serialize core composition
    json composition_data = json::object();
    for (const std::pair<const std::string, float>& element : core_composition) {
        composition_data[element.first] = element.second;
    }
    data["core_composition"] = composition_data;

    return data;
}

void PlanetaryCore::deserialize(const json& data) {
    core_temperature = data.at("core_temperature").get<float>();
    core_pressure = data.at("core_pressure").get<float>();
    mantle_temperature = data.at("mantle_temperature").get<float>();
    volcanic_activity_level = data.at("volcanic_activity_level").get<float>();
    geological_age = data.at("geological_age").get<float>();
    last_impact_time = data.at("last_impact_time").get<float>();
    total_impact_energy = data.at("total_impact_energy").get<float>();

    // Deserialize core composition
    const json& composition_data = data.at("core_composition");
    core_composition.clear();
    for (json::const_iterator it = composition_data.begin(); it != composition_data.end(); ++it) {
        core_composition[it.key()] = it.value().get<float>();
    }
}

// ========================================
// PRIVATE METHODS
// ========================================

void PlanetaryCore::updateVolcanicActivity() {
    // Volcanic activity increases with core temperature
    const float temperature_factor = core_temperature / 6000.0f;
    const float base_activity = std::min(1.0f, temperature_factor - 0.3f);

    // Recent impacts increase volcanic activity
    const float impact_factor = (total_impact_energy > 0) ? 0.2f : 0.0f;

    volcanic_activity_level = std::max(0.0f, std::min(1.0f, base_activity + impact_factor));
}

void PlanetaryCore::normalizeComposition() {
    float total_percentage = 0.0f;

    // Calculate total percentage
    for (const std::pair<const std::string, float>& element : core_composition) {
        total_percentage += element.second;
    }

    // Normalize if over 100%
    if (total_percentage > 100.0f) {
        for (std::pair<const std::string, float>& element : core_composition) {
            element.second = (element.second / total_percentage) * 100.0f;
        }
    }
}

} // namespace warfactory