#include "../include/MeteoriteImpact.h"
#include "map/GMap.h"
#include <cmath>
#include <algorithm>

namespace warfactory {

MeteoriteImpact::MeteoriteImpact(const Meteorite& meteorite, float size, float velocity, float angle, float x, float y)
    : meteorite_template(meteorite), impact_size(size), impact_velocity(velocity),
      impact_angle(angle), x_position(x), y_position(y) {
}

void MeteoriteImpact::applyImpactEffects(WorldData& world, PlanetaryCore& core) {
    // Apply all impact effects in sequence
    createCrater(world);
    generateHeat(world);

    // Note: depositMaterials requires RegionManager parameter
    // This would need to be called separately with proper context
}

void MeteoriteImpact::createCrater(WorldData& world) {
    const float crater_radius = calculateCraterRadius();
    const float crater_depth = calculateCraterDepth();

    // Apply crater formation to the world map
    // Assuming WorldData has a method to get the terrain map
    GMap* terrain_map = world.getTerrainMap();
    if (terrain_map) {
        // Create crater by modifying elevation
        const uint16_t depth_value = static_cast<uint16_t>(std::min(crater_depth, 1000.0f));
        const uint8_t crater_scale = static_cast<uint8_t>(std::min(impact_size * 10.0f, 255.0f));

        terrain_map->applyImpactToArea(x_position, y_position, crater_radius,
                                      0.0f, // No heat in crater creation step
                                      depth_value, crater_scale);
    }
}

void MeteoriteImpact::depositMaterials(PlanetaryCore& core, RegionManager& region_manager) {
    // Calculate material deposition based on meteorite composition
    (void)core; // TODO: Use core for determining available elements/heat effects
    const float impact_radius = calculateImpactRadius();
    const std::unordered_map<std::string, float>& meteorite_resources = meteorite_template.getResourceComposition();

    // Create resource deposits in the impact area
    for (const std::pair<const std::string, float>& resource_pair : meteorite_resources) {
        const std::string& resource_id = resource_pair.first;
        const float resource_quantity = resource_pair.second;
        const float deposit_mass = resource_quantity * impact_size;
        const float deposit_radius = impact_radius * 0.7f; // Deposits are smaller than full impact

        // Create a new region for this resource deposit
        const std::string region_type = resource_id + "_deposit";
        const int region_id = region_manager.createRegion(region_type, x_position, y_position,
                                                         deposit_mass, deposit_radius);

        // TODO: Set region properties based on resource characteristics
        // This would involve creating specific region implementations
    }
}

void MeteoriteImpact::generateHeat(WorldData& world) {
    const float heat_generation = calculateHeatGeneration();
    const float heat_radius = calculateImpactRadius();

    GMap* terrain_map = world.getTerrainMap();
    if (terrain_map) {
        terrain_map->applyVolcanicHeat(x_position, y_position, heat_generation, heat_radius);
    }
}

float MeteoriteImpact::calculateKineticEnergy() const {
    // E = 0.5 * m * v^2
    const float mass = meteorite_template.getMass() * impact_size;
    return 0.5f * mass * impact_velocity * impact_velocity;
}

float MeteoriteImpact::calculateImpactRadius() const {
    // Empirical formula for impact radius based on kinetic energy
    const float kinetic_energy = calculateKineticEnergy();
    const float base_radius = std::pow(kinetic_energy / 1000000.0f, 0.33f); // Cube root scaling

    // Adjust for impact angle (oblique impacts create larger disturbed areas)
    const float angle_factor = 1.0f + (1.0f - std::cos(impact_angle)) * 0.5f;

    return base_radius * angle_factor;
}

float MeteoriteImpact::calculateHeatGeneration() const {
    // Convert kinetic energy to heat (most energy becomes heat)
    const float kinetic_energy = calculateKineticEnergy();
    const float heat_efficiency = 0.8f; // 80% of kinetic energy becomes heat

    // Convert energy to temperature increase (simplified)
    // This is a rough approximation - actual calculation would involve
    // heat capacity, thermal conductivity, etc.
    const float heat_celsius = (kinetic_energy * heat_efficiency) / 1000.0f;

    return std::min(heat_celsius, 5000.0f); // Cap at reasonable geological temperature
}

float MeteoriteImpact::calculateCraterDepth() const {
    // Crater depth scales with impact energy and inversely with target strength
    const float kinetic_energy = calculateKineticEnergy();
    const float base_depth = std::pow(kinetic_energy / 500000.0f, 0.25f); // Fourth root scaling

    // Adjust for impact angle (shallow angles create shallower craters)
    const float angle_factor = std::sin(impact_angle);

    return base_depth * angle_factor * 100.0f; // Scale to meters
}

float MeteoriteImpact::calculateCraterRadius() const {
    // Crater radius is typically 10-20 times the projectile diameter
    const float projectile_radius = std::pow(meteorite_template.getMass() * impact_size, 0.33f);
    const float crater_multiplier = 15.0f; // Typical ratio for crater formation

    return projectile_radius * crater_multiplier;
}

} // namespace warfactory