package com.livingworld.regions;

/**
 * Metrics that describe the health and state of an ecosystem within a region.
 *
 * <p>All values are clamped between 0 and 100 to represent percentages or
 * normalized scores. This class provides methods for normalizing, copying,
 * and creating default instances.</p>
 */
public class RegionMetrics {

    private double ecosystemHealth;
    private double pollutionScore;
    private double soilQuality;
    private double waterQuality;
    private double vegetationPressure;
    private double resourceDepletion;
    private double recoveryPressure;

    // ------------------------------------------------------------------
    // Constants
    // ------------------------------------------------------------------

    /** Minimum allowed value for all metrics. */
    public static final double MIN_VALUE = 0;

    /** Maximum allowed value for all metrics. */
    public static final double MAX_VALUE = 100;

    // ------------------------------------------------------------------
    // Default values
    // ------------------------------------------------------------------

    /** Default ecosystem health score. */
    private static final double DEFAULT_ECOSYSTEM_HEALTH = 60;

    /** Default pollution score. */
    private static final double DEFAULT_POLLUTION_SCORE = 0;

    /** Default soil quality score. */
    private static final double DEFAULT_SOIL_QUALITY = 60;

    /** Default water quality score. */
    private static final double DEFAULT_WATER_QUALITY = 60;

    /** Default vegetation pressure score. */
    private static final double DEFAULT_VEGETATION_PRESSURE = 50;

    /** Default resource depletion score. */
    private static final double DEFAULT_RESOURCE_DEPLETION = 0;

    /** Default recovery pressure score. */
    private static final double DEFAULT_RECOVERY_PRESSURE = 50;

    // ------------------------------------------------------------------
    // Constructor
    // ------------------------------------------------------------------

    /**
     * Default constructor. All fields are initialized to 0.
     */
    public RegionMetrics() {
        // all fields default to 0.0
    }

    // ------------------------------------------------------------------
    // Getters and Setters
    // ------------------------------------------------------------------

    /**
     * Returns the ecosystem health score (0-100).
     *
     * <p>Higher values indicate a healthier, more balanced ecosystem.</p>
     */
    public double getEcosystemHealth() {
        return ecosystemHealth;
    }

    /**
     * Sets the ecosystem health score.
     *
     * <p>The value is clamped between 0 and 100.</p>
     */
    public void setEcosystemHealth(double ecosystemHealth) {
        this.ecosystemHealth = clamp(ecosystemHealth);
    }

    /**
     * Returns the pollution score (0-100).
     *
     * <p>Higher values indicate more severe pollution.</p>
     */
    public double getPollutionScore() {
        return pollutionScore;
    }

    /**
     * Sets the pollution score.
     *
     * <p>The value is clamped between 0 and 100.</p>
     */
    public void setPollutionScore(double pollutionScore) {
        this.pollutionScore = clamp(pollutionScore);
    }

    /**
     * Returns the soil quality score (0-100).
     *
     * <p>Higher values indicate better soil health.</p>
     */
    public double getSoilQuality() {
        return soilQuality;
    }

    /**
     * Sets the soil quality score.
     *
     * <p>The value is clamped between 0 and 100.</p>
     */
    public void setSoilQuality(double soilQuality) {
        this.soilQuality = clamp(soilQuality);
    }

    /**
     * Returns the water quality score (0-100).
     *
     * <p>Higher values indicate cleaner, more abundant water.</p>
     */
    public double getWaterQuality() {
        return waterQuality;
    }

    /**
     * Sets the water quality score.
     *
     * <p>The value is clamped between 0 and 100.</p>
     */
    public void setWaterQuality(double waterQuality) {
        this.waterQuality = clamp(waterQuality);
    }

    /**
     * Returns the vegetation pressure score (0-100).
     *
     * <p>Higher values indicate higher stress on vegetation resources.</p>
     */
    public double getVegetationPressure() {
        return vegetationPressure;
    }

    /**
     * Sets the vegetation pressure score.
     *
     * <p>The value is clamped between 0 and 100.</p>
     */
    public void setVegetationPressure(double vegetationPressure) {
        this.vegetationPressure = clamp(vegetationPressure);
    }

    /**
     * Returns the resource depletion score (0-100).
     *
     * <p>Higher values indicate more severe resource exhaustion.</p>
     */
    public double getResourceDepletion() {
        return resourceDepletion;
    }

    /**
     * Sets the resource depletion score.
     *
     * <p>The value is clamped between 0 and 100.</p>
     */
    public void setResourceDepletion(double resourceDepletion) {
        this.resourceDepletion = clamp(resourceDepletion);
    }

    /**
     * Returns the recovery pressure score (0-100).
     *
     * <p>Higher values indicate greater need for ecosystem recovery efforts.</p>
     */
    public double getRecoveryPressure() {
        return recoveryPressure;
    }

    /**
     * Sets the recovery pressure score.
     *
     * <p>The value is clamped between 0 and 100.</p>
     */
    public void setRecoveryPressure(double recoveryPressure) {
        this.recoveryPressure = clamp(recoveryPressure);
    }

    // ------------------------------------------------------------------
    // Copy and Static Factory Methods
    // ------------------------------------------------------------------

    /**
     * Returns a new {@link RegionMetrics} instance with identical field values.
     *
     * <p>The returned instance is independent; modifying it will not affect
     * the original metrics.</p>
     */
    public RegionMetrics copy() {
        RegionMetrics copy = new RegionMetrics();
        copy.ecosystemHealth = this.ecosystemHealth;
        copy.pollutionScore = this.pollutionScore;
        copy.soilQuality = this.soilQuality;
        copy.waterQuality = this.waterQuality;
        copy.vegetationPressure = this.vegetationPressure;
        copy.resourceDepletion = this.resourceDepletion;
        copy.recoveryPressure = this.recoveryPressure;
        return copy;
    }

    /**
     * Returns a new {@link RegionMetrics} instance with default values.
     *
     * <p>Default values:
     *   ecosystemHealth=60, pollutionScore=0, soilQuality=60,
     *   waterQuality=60, vegetationPressure=50, resourceDepletion=0,
     *   recoveryPressure=50</p>
     */
    public static RegionMetrics defaults() {
        RegionMetrics metrics = new RegionMetrics();
        metrics.ecosystemHealth = DEFAULT_ECOSYSTEM_HEALTH;
        metrics.pollutionScore = DEFAULT_POLLUTION_SCORE;
        metrics.soilQuality = DEFAULT_SOIL_QUALITY;
        metrics.waterQuality = DEFAULT_WATER_QUALITY;
        metrics.vegetationPressure = DEFAULT_VEGETATION_PRESSURE;
        metrics.resourceDepletion = DEFAULT_RESOURCE_DEPLETION;
        metrics.recoveryPressure = DEFAULT_RECOVERY_PRESSURE;
        return metrics;
    }

    // ------------------------------------------------------------------
    // Delta Application Methods
    // ------------------------------------------------------------------

    /**
     * Applies deltas to all metric fields and returns this instance for chaining.
     *
     * <p>Each field is modified by its corresponding delta value, then clamped
     * between 0 and 100.</p>
     *
     * @param ecosystemHealthDelta    the change to apply to ecosystem health
     * @param pollutionScoreDelta     the change to apply to pollution score
     * @param soilQualityDelta        the change to apply to soil quality
     * @param waterQualityDelta       the change to apply to water quality
     * @param vegetationPressureDelta the change to apply to vegetation pressure
     * @param resourceDepletionDelta  the change to apply to resource depletion
     * @param recoveryPressureDelta   the change to apply to recovery pressure
     * @return this metrics instance for method chaining
     */
    public RegionMetrics applyDelta(
            double ecosystemHealthDelta,
            double pollutionScoreDelta,
            double soilQualityDelta,
            double waterQualityDelta,
            double vegetationPressureDelta,
            double resourceDepletionDelta,
            double recoveryPressureDelta) {

        this.ecosystemHealth = clamp(this.ecosystemHealth + ecosystemHealthDelta);
        this.pollutionScore = clamp(this.pollutionScore + pollutionScoreDelta);
        this.soilQuality = clamp(this.soilQuality + soilQualityDelta);
        this.waterQuality = clamp(this.waterQuality + waterQualityDelta);
        this.vegetationPressure = clamp(this.vegetationPressure + vegetationPressureDelta);
        this.resourceDepletion = clamp(this.resourceDepletion + resourceDepletionDelta);
        this.recoveryPressure = clamp(this.recoveryPressure + recoveryPressureDelta);

        return this;
    }

    /**
     * Applies a delta to the ecosystem health score and returns this instance.
     */
    public RegionMetrics applyEcosystemHealthDelta(double delta) {
        this.ecosystemHealth = clamp(this.ecosystemHealth + delta);
        return this;
    }

    /**
     * Applies a delta to the pollution score and returns this instance.
     */
    public RegionMetrics applyPollutionScoreDelta(double delta) {
        this.pollutionScore = clamp(this.pollutionScore + delta);
        return this;
    }

    /**
     * Applies a delta to the soil quality score and returns this instance.
     */
    public RegionMetrics applySoilQualityDelta(double delta) {
        this.soilQuality = clamp(this.soilQuality + delta);
        return this;
    }

    /**
     * Applies a delta to the water quality score and returns this instance.
     */
    public RegionMetrics applyWaterQualityDelta(double delta) {
        this.waterQuality = clamp(this.waterQuality + delta);
        return this;
    }

    /**
     * Applies a delta to the vegetation pressure score and returns this instance.
     */
    public RegionMetrics applyVegetationPressureDelta(double delta) {
        this.vegetationPressure = clamp(this.vegetationPressure + delta);
        return this;
    }

    /**
     * Applies a delta to the resource depletion score and returns this instance.
     */
    public RegionMetrics applyResourceDepletionDelta(double delta) {
        this.resourceDepletion = clamp(this.resourceDepletion + delta);
        return this;
    }

    /**
     * Applies a delta to the recovery pressure score and returns this instance.
     */
    public RegionMetrics applyRecoveryPressureDelta(double delta) {
        this.recoveryPressure = clamp(this.recoveryPressure + delta);
        return this;
    }

    // ------------------------------------------------------------------
    // Normalization
    // ------------------------------------------------------------------

    /**
     * Clamps all metric values between 0 and 100.
     *
     * <p>This method modifies the current instance in place and returns it
     * for method chaining.</p>
     */
    public RegionMetrics normalize() {
        this.ecosystemHealth = clamp(this.ecosystemHealth);
        this.pollutionScore = clamp(this.pollutionScore);
        this.soilQuality = clamp(this.soilQuality);
        this.waterQuality = clamp(this.waterQuality);
        this.vegetationPressure = clamp(this.vegetationPressure);
        this.resourceDepletion = clamp(this.resourceDepletion);
        this.recoveryPressure = clamp(this.recoveryPressure);
        return this;
    }

    // ------------------------------------------------------------------
    // Utility Methods
    // ------------------------------------------------------------------

    /**
     * Clamps a value between 0 and 100.
     */
    private static double clamp(double value) {
        if (value < MIN_VALUE) {
            return MIN_VALUE;
        }
        if (value > MAX_VALUE) {
            return MAX_VALUE;
        }
        return value;
    }

    // ------------------------------------------------------------------
    // Standard Overrides
    // ------------------------------------------------------------------

    @Override
    public String toString() {
        return "RegionMetrics{"
                + "ecosystemHealth=" + ecosystemHealth
                + ", pollutionScore=" + pollutionScore
                + ", soilQuality=" + soilQuality
                + ", waterQuality=" + waterQuality
                + ", vegetationPressure=" + vegetationPressure
                + ", resourceDepletion=" + resourceDepletion
                + ", recoveryPressure=" + recoveryPressure
                + "}";
    }
}