package de.avatic.lcc.model.db.utils;


import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import de.avatic.lcc.util.exception.badrequest.InvalidArgumentException;

/**
 * An enumeration representing the units of dimension measurement.
 *
 * This enum is used to specify the dimension unit for various entities
 * such as packaging dimensions and related calculations.
 *
 * The supported dimension units are:
 * - M: Meters
 * - CM: Centimeters
 * - MM: Millimeters
 */
public enum DimensionUnit {
    M("m", 1000.0),
    CM("cm", 10.0),
    MM("mm", 1.0);

    private final String displayedName;
    private final double baseFactor;

    DimensionUnit(String displayedName, double baseFactor) {
        this.displayedName = displayedName;
        this.baseFactor = baseFactor;
    }

    /**
     * Custom deserializer that handles case-insensitive matching
     */
    @JsonCreator
    public static DimensionUnit fromString(String value) {
        if (value == null) {
            return null;
        }

        for (DimensionUnit unit : DimensionUnit.values()) {
            if (unit.displayedName.equalsIgnoreCase(value)) {
                return unit;
            }
        }

        throw new IllegalArgumentException("Unknown DimensionUnit: " + value +
                ". Valid values are: mm, cm, m (case insensitive)");
    }


    @JsonValue
    public String getDisplayedName() {
        return displayedName;
    }

    public Integer convertToMM(Number value) {
        return Math.toIntExact(Math.round(DimensionUnit.MM.convertFrom(value, this)));
    }

    /**
     * Converts a value from one dimension unit to this unit.
     *
     * @param value the value to convert
     * @param fromUnit the source unit
     * @return the converted value
     * @throws IllegalArgumentException if value or fromUnit is null
     */
    public Double convertFrom(Number value, DimensionUnit fromUnit) {
        if (value == null || fromUnit == null) {
            throw new InvalidArgumentException("Value and fromUnit must not be null");
        }

        // Convert to base unit (millimeters)
        double valueInBaseUnit = value.doubleValue() * fromUnit.baseFactor;

        // Convert from base unit to target unit
        return valueInBaseUnit / this.baseFactor;
    }

    /**
     * Converts a given value from millimeters (MM) to the unit represented by this instance.
     *
     * @param value the value in millimeters to convert
     * @return the converted value in the target unit
     * @throws IllegalArgumentException if the provided value is null
     */
    public Double convertFromMM(Number value) {
        return convertFrom(value, MM);
    }
}
