#pragma once

#include "PlanetaryCore.h"
#include "warfactory/IDataNode.h"
#include "warfactory/ResourceRegistry.h"
#include <unordered_map>
#include <vector>

// Forward declaration for Region
namespace warfactory {
    class Region;
}

namespace warfactory {

/**
 * @brief Planetary differentiation process separating heavy metals from light materials
 *
 * Models gravitational separation of planetary core materials based on density differences.
 * Heavy metals (iron, nickel, etc.) sink toward core center while lighter materials
 * (silicates, volatiles) migrate toward mantle and crust layers.
 *
 * Process operates over 100M year cycles during early planetary formation when
 * core is still molten and gravitational sorting is active.
 */
class PlanetaryDifferentiationFunction {
private:
    float heavy_metal_threshold_density;           // g/cm³ - threshold for heavy metal classification
    float sinking_rate_per_cycle;                  // Fraction of heavy metals that sink per cycle
    float differentiation_efficiency;              // Overall process efficiency (0.0 to 1.0)

    // Density-based layers for realistic differentiation
    struct DensityLayer {
        float min_density;      // Minimum density for this layer (g/cm³)
        float max_density;      // Maximum density for this layer (g/cm³)
        float concentration_factor; // How much material concentrates in this layer
    };

    std::vector<DensityLayer> density_layers;

public:
    PlanetaryDifferentiationFunction();

    // ========================================
    // CONFIGURATION
    // ========================================

    /**
     * @brief Configure differentiation process from JSON parameters
     * @param config_node JSON configuration containing heavy_metal_sinking parameters
     * Expected structure:
     * {
     *   "heavy_metal_threshold_density": 5.0,
     *   "sinking_rate_per_cycle": 0.7,
     *   "differentiation_efficiency": 1.0
     * }
     */
    void configure(const IDataNode& config_node);

    /**
     * @brief Set density threshold for heavy metal classification
     * @param threshold_density Density in g/cm³ above which materials are considered heavy metals
     */
    void setHeavyMetalThreshold(float threshold_density) { heavy_metal_threshold_density = threshold_density; }

    /**
     * @brief Set sinking rate for heavy materials per geological cycle
     * @param rate Fraction of heavy metals that sink per cycle (0.0 to 1.0)
     */
    void setSinkingRate(float rate) { sinking_rate_per_cycle = rate; }

    /**
     * @brief Set overall differentiation efficiency
     * @param efficiency Process efficiency factor (0.0 to 1.0)
     */
    void setDifferentiationEfficiency(float efficiency) { differentiation_efficiency = efficiency; }

    // ========================================
    // DIFFERENTIATION PROCESS
    // ========================================

    /**
     * @brief Execute planetary differentiation for one geological cycle
     * Consumes heavy metals from surface regions and transfers them to planetary core
     * @param regions Vector of surface regions to extract from (MODIFIED - heavy metals consumed)
     * @param core Planetary core to deposit heavy metals into (MODIFIED - composition increases)
     * @param cycle_duration_years Duration of current cycle in years
     * @return Map of transferred materials by density classification
     */
    std::unordered_map<std::string, std::unordered_map<uint32_t, __uint128_t>>
    executeDifferentiation(std::vector<Region>& regions, PlanetaryCore& core, double cycle_duration_years);

    /**
     * @brief Simulate differentiation effects over multiple cycles
     * @param regions Vector of surface regions to process over time
     * @param core Planetary core to accumulate materials
     * @param num_cycles Number of geological cycles to simulate
     * @param cycle_duration_years Duration of each cycle in years
     * @return Final differentiation state by layer
     */
    std::unordered_map<std::string, std::unordered_map<uint32_t, __uint128_t>>
    simulateMultipleCycles(std::vector<Region>& regions, PlanetaryCore& core, int num_cycles, double cycle_duration_years);

    /**
     * @brief Calculate differentiation progress for current core state
     * @param core Planetary core to analyze
     * @return Differentiation completion ratio (0.0 = no separation, 1.0 = fully separated)
     */
    float calculateDifferentiationProgress(const PlanetaryCore& core) const;

    // ========================================
    // ANALYSIS AND UTILITIES
    // ========================================

    /**
     * @brief Classify resource by density into differentiation layer
     * @param resource_id Resource to classify
     * @return Layer name ("inner_core", "outer_core", "mantle", "crust")
     */
    std::string classifyResourceByDensity(uint32_t resource_id) const;

    /**
     * @brief Get all heavy metal resources above density threshold from regions
     * @param regions Vector of regions to scan for heavy metals
     * @return Vector of resource IDs classified as heavy metals
     */
    std::vector<uint32_t> getHeavyMetalResources(const std::vector<Region>& regions) const;

    /**
     * @brief Get all light material resources below density threshold from regions
     * @param regions Vector of regions to scan for light materials
     * @return Vector of resource IDs classified as light materials
     */
    std::vector<uint32_t> getLightMaterialResources(const std::vector<Region>& regions) const;

    /**
     * @brief Calculate total mass transfer from regions to core for this cycle
     * @param regions Vector of regions to analyze for transferable materials
     * @return Total mass of material that will migrate to core (tonnes)
     */
    __uint128_t calculateMassTransfer(const std::vector<Region>& regions) const;

    /**
     * @brief Check if differentiation process is still active
     * @param core Planetary core to check
     * @param core_temperature Current core temperature in Celsius
     * @return True if core is hot enough for active differentiation
     */
    bool isDifferentiationActive(const PlanetaryCore& core, float core_temperature) const;

    /**
     * @brief Get available density layers for material placement
     * @return Vector of density layer names and their properties
     */
    std::vector<std::pair<std::string, DensityLayer>> getDensityLayers() const;

private:
    /**
     * @brief Initialize standard planetary density layers
     * Sets up realistic Earth-like layer structure:
     * - Inner Core: 12-13 g/cm³ (solid iron-nickel)
     * - Outer Core: 10-12 g/cm³ (liquid iron-nickel)
     * - Mantle: 3-5 g/cm³ (silicates, olivine)
     * - Crust: 2-3 g/cm³ (light silicates, volatiles)
     */
    void initializeDensityLayers();

    /**
     * @brief Get resource density from ResourceRegistry
     * @param resource_id Resource to check
     * @return Density in g/cm³
     */
    float getResourceDensity(uint32_t resource_id) const;

    /**
     * @brief Calculate gravitational sinking velocity for resource
     * @param resource_id Resource undergoing differentiation
     * @param core_temperature Current core temperature affecting viscosity
     * @return Sinking rate factor for this resource
     */
    float calculateSinkingVelocity(uint32_t resource_id, float core_temperature) const;

    /**
     * @brief Apply temperature-dependent differentiation efficiency
     * @param core_temperature Current core temperature
     * @return Temperature efficiency factor (0.0 to 1.0)
     */
    float calculateTemperatureEfficiency(float core_temperature) const;

    /**
     * @brief Determine target layer for resource based on density
     * @param resource_density Resource density in g/cm³
     * @return Target layer name for this resource
     */
    std::string determineTargetLayer(float resource_density) const;

    /**
     * @brief Calculate actual migration amount considering sinking rate and efficiency
     * @param total_amount Total amount of resource available
     * @param sinking_factor Resource-specific sinking rate
     * @return Amount that actually migrates this cycle
     */
    __uint128_t calculateMigrationAmount(__uint128_t total_amount, float sinking_factor) const;
};

} // namespace warfactory