package com.livingworld.modules.water;

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 com.livingworld.regions.RegionMetrics;
import java.util.List;

/**
 * Refines {@link RegionMetrics#getWaterQuality()} after the pollution module has
 * applied its raw damage, adding vegetation-driven purification and soil-driven
 * contamination leaching.
 *
 * <p>This module runs <em>after</em>
 * {@link com.livingworld.modules.pollution.PollutionModule} and
 * {@link com.livingworld.modules.soil.SoilModule} in the update pipeline so
 * it reads current-tick values for both pollutionScore and soilQuality.
 *
 * <h3>Per-tick rules</h3>
 * <ol>
 *   <li>Purification capacity is derived from current vegetation pressure
 *       (plants filter water).
 *   <li>Low soil quality allows contamination to leach into groundwater,
 *       reducing water quality.
 *   <li>Purification capacity partially restores water quality each tick.
 *   <li>Water availability drifts toward a baseline unless stressed by
 *       drought or flood conditions (V1 placeholder).
 * </ol>
 */
public final class WaterModule implements SimulationModule {

    public static final String MODULE_ID = "water";

    /** Vegetation pressure drives this fraction of purification capacity. */
    private static final double VEG_TO_PURIFICATION_FACTOR    = 0.50;
    /** Each point of soil quality below 40 leaches this much water quality per tick. */
    private static final double SOIL_LEACH_RATE                = 0.005;
    /** Soil quality threshold below which contamination leaches into water. */
    private static final double SOIL_LEACH_THRESHOLD           = 40.0;
    /** Fraction of purification capacity applied to water quality per tick. */
    private static final double PURIFICATION_RATE              = 0.01;
    private static final double CHANGE_THRESHOLD               = 0.01;

    private static final ModuleMetadata METADATA = new ModuleMetadata(
            MODULE_ID,
            "Water Quality",
            "1.0.0",
            "Refines water quality with vegetation purification and soil contamination leaching.",
            "1",
            List.of("pollution", "soil"),
            List.of("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, WaterRegionData.defaults());
        }
    }

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

        Region region = context.getRegion();
        WaterRegionData data = region.getModuleData()
                .get(MODULE_ID, WaterRegionData.class)
                .orElseGet(WaterRegionData::defaults);
        RegionMetrics metrics = region.getMetrics();

        double prevWaterQuality = metrics.getWaterQuality();

        // Purification capacity is driven by vegetation cover.
        double purification = metrics.getVegetationPressure() * VEG_TO_PURIFICATION_FACTOR;
        data.setPurificationCapacity(purification);

        // Low soil quality allows contamination to leach into groundwater.
        if (metrics.getSoilQuality() < SOIL_LEACH_THRESHOLD) {
            double leach = (SOIL_LEACH_THRESHOLD - metrics.getSoilQuality()) * SOIL_LEACH_RATE;
            metrics.setWaterQuality(Math.max(0.0, metrics.getWaterQuality() - leach));
        }

        // Vegetation purification partially restores water quality.
        double recovery = purification * PURIFICATION_RATE;
        metrics.setWaterQuality(Math.min(100.0, metrics.getWaterQuality() + recovery));

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

        boolean changed = Math.abs(metrics.getWaterQuality() - prevWaterQuality) > 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() {}
}
