package com.livingworld.modules.resources;

import com.livingworld.data.serialization.PersistenceReader;
import com.livingworld.data.serialization.PersistenceWriter;
import com.livingworld.events.LivingWorldEvent;
import com.livingworld.modules.ModuleContext;
import com.livingworld.modules.ModuleMetadata;
import com.livingworld.modules.ModuleUpdateResult;
import com.livingworld.modules.RegionUpdateContext;
import com.livingworld.modules.ServerContext;
import com.livingworld.modules.SimulationModule;
import com.livingworld.regions.Region;
import java.util.List;

/**
 * Tracks how intensively each resource type has been harvested and models
 * natural regeneration, writing {@link com.livingworld.regions.RegionMetrics#getResourceDepletion()}.
 *
 * <p>Depletion events (mining, logging, farming) are normally recorded by the
 * NeoForge platform adapter when players interact with the world. This module
 * handles the autonomous decay (regeneration) side.
 *
 * <h3>Regeneration rates (per tick)</h3>
 * <ul>
 *   <li><b>mining</b>   – 0.01 % (geological timescale; very slow)
 *   <li><b>logging</b>  – 0.5 % base + bonus when vegetationPressure is high
 *   <li><b>farming</b>  – 0.3 % base + bonus when soilQuality is high
 * </ul>
 *
 * <h3>Ecosystem feedback</h3>
 * High logging depletion suppresses tree growth (read by VegetationModule via
 * {@link com.livingworld.regions.RegionMetrics#getResourceDepletion()}).
 */
public final class ResourceDepletionModule implements SimulationModule {

    public static final String MODULE_ID = "resources";

    private static final double MINING_REGEN_RATE      = 0.0001;
    private static final double LOGGING_BASE_REGEN     = 0.005;
    private static final double LOGGING_VEG_BONUS_RATE = 0.005;
    private static final double LOGGING_VEG_THRESHOLD  = 50.0;
    private static final double FARMING_BASE_REGEN     = 0.003;
    private static final double FARMING_SOIL_BONUS_RATE = 0.003;
    private static final double FARMING_SOIL_THRESHOLD = 50.0;
    private static final double CHANGE_THRESHOLD       = 0.01;

    private static final ModuleMetadata METADATA = new ModuleMetadata(
            MODULE_ID,
            "Resource Depletion",
            "1.0.0",
            "Tracks resource exhaustion and natural regeneration.",
            "1",
            List.of(),
            List.of("soil", "vegetation"),
            true,
            true,
            false);

    @Override
    public String getModuleId() { return MODULE_ID; }

    @Override
    public ModuleMetadata getMetadata() { return METADATA; }

    @Override
    public void initialize(ModuleContext context) {
        if (context == null) throw new IllegalArgumentException("context must not be null");
    }

    @Override
    public void onServerStarted(ServerContext context) {}

    @Override
    public void createDefaultRegionData(Region region) {
        if (region == null) throw new IllegalArgumentException("region must not be null");
        if (!region.getModuleData().contains(MODULE_ID)) {
            region.getModuleData().put(MODULE_ID, ResourceRegionData.defaults());
        }
    }

    @Override
    public ModuleUpdateResult updateRegion(RegionUpdateContext context) {
        if (context == null) throw new IllegalArgumentException("context must not be null");

        Region region = context.getRegion();
        ResourceRegionData data = region.getModuleData()
                .get(MODULE_ID, ResourceRegionData.class)
                .orElseGet(ResourceRegionData::defaults);

        double prevTotal = data.totalDepletion();

        // Mining regenerates extremely slowly (geological timescale).
        data.setMiningDepletion(data.getMiningDepletion() * (1.0 - MINING_REGEN_RATE));

        // Logging regenerates faster when vegetation is recovering.
        double loggingRegen = LOGGING_BASE_REGEN;
        if (region.getMetrics().getVegetationPressure() > LOGGING_VEG_THRESHOLD) {
            loggingRegen += (region.getMetrics().getVegetationPressure() - LOGGING_VEG_THRESHOLD)
                            * LOGGING_VEG_BONUS_RATE;
        }
        data.setLoggingDepletion(Math.max(0.0, data.getLoggingDepletion() - loggingRegen));

        // Farming depletion recovers faster with good soil quality.
        double farmingRegen = FARMING_BASE_REGEN;
        if (region.getMetrics().getSoilQuality() > FARMING_SOIL_THRESHOLD) {
            farmingRegen += (region.getMetrics().getSoilQuality() - FARMING_SOIL_THRESHOLD)
                            * FARMING_SOIL_BONUS_RATE;
        }
        data.setFarmingDepletion(Math.max(0.0, data.getFarmingDepletion() - farmingRegen));

        // Write summary metric.
        region.getMetrics().setResourceDepletion(data.totalDepletion());

        region.getModuleData().put(MODULE_ID, data);

        boolean changed = Math.abs(data.totalDepletion() - prevTotal) > CHANGE_THRESHOLD;
        return changed ? ModuleUpdateResult.changed() : ModuleUpdateResult.noChange();
    }

    @Override
    public void onLivingWorldEvent(LivingWorldEvent event) {}

    @Override
    public void saveModuleData(PersistenceWriter writer) {}

    @Override
    public void loadModuleData(PersistenceReader reader) {}

    @Override
    public void shutdown() {}
}
