package de.avatic.lcc.model.calculation;

import de.avatic.lcc.dto.generic.ContainerType;
import de.avatic.lcc.model.db.packaging.PackagingDimension;
import de.avatic.lcc.model.db.utils.DimensionUnit;
import de.avatic.lcc.model.db.utils.WeightUnit;

/**
 * Represents the result of a container calculation process, including details
 * about the utilized packaging dimensions, container type, and various metrics
 * such as layer count, structural arrangement, and utilization.
 * <p>
 * This class provides methods to retrieve metrics related to container
 * utilization, such as the total number of handling units and whether the
 * allowed weight limit has been exceeded.
 */
public class ContainerCalculationResult {


    private Integer maxContainerWeight;

    /**
     * The dimensions of the handling unit (HU), including weight,
     * height, width, and length specifications. Includes a tolerance according 
     * to system property
     */
    private PackagingDimension hu;

    /**
     * The number of layers in the container calculation result,
     * representing the vertical stacking level.
     */
    private int layer;

    /**
     * The structural arrangement of the handling units within
     * the container, represented as a descriptive string.
     */
    private String structure;

    /**
     * Total count of handling units (HU) that are recognized
     * based on the calculation.
     */
    private int huUnitCount;

    /**
     * Indicates whether the calculated weight of the container exceeds
     * the permitted limit for the container type.
     */
    private boolean weightExceeded;

    /**
     * Type of container used in the calculation, e.g., TEU/FEU.
     */
    private ContainerType containerType;

    /**
     * Constructs a new ContainerCalculationResult with the provided parameters.
     *
     * @param huUnitCount    The total number of handling units.
     * @param layers         The total number of layers to stack.
     * @param structure      A textual description of the container's arrangement.
     * @param weightExceeded Boolean indicating if the allowed weight is exceeded.
     * @param containerType  The type of container being used in the process.
     * @param hu             The packaging dimensions of the handling unit (incl. tolerance).
     */
    public ContainerCalculationResult(int huUnitCount, int layers, String structure, boolean weightExceeded, ContainerType containerType, PackagingDimension hu, Integer maxContainerWeight) {
        this.huUnitCount = huUnitCount;
        this.layer = layers;
        this.structure = structure;
        this.weightExceeded = weightExceeded;
        this.containerType = containerType;
        this.maxContainerWeight = maxContainerWeight;
        this.hu = hu;
    }

    public Integer getMaxContainerWeight() {
        return maxContainerWeight;
    }

    public void setMaxContainerWeight(Integer maxContainerWeight) {
        this.maxContainerWeight = maxContainerWeight;
    }

    /**
     * Sets the PackagingDimension object representing the handling unit attributes.
     *
     * @param hu A PackagingDimension object containing weight and size information of the handling unit.
     */
    public void setHu(PackagingDimension hu) {
        this.hu = hu;
    }

    /**
     * Retrieves the PackagingDimension object representing the handling unit attributes.
     *
     * @return A PackagingDimension object containing weight and size information of the handling unit.
     */
    public PackagingDimension getHu() {
        return hu;
    }

    /**
     * Default constructor for ContainerCalculationResult.
     * Initializes an empty object with no predefined values.
     */
    public ContainerCalculationResult() {
    }

    /**
     * Gets the type of container used in this calculation.
     *
     * @return The container type (e.g., TEU, FEU).
     */
    public ContainerType getContainerType() {
        return containerType;
    }

    /**
     * Sets the type of container used in this calculation.
     *
     * @param containerType The container type (e.g., TEU, FEU).
     */
    public void setContainerType(ContainerType containerType) {
        this.containerType = containerType;
    }

    /**
     * Checks if the weight limit is exceeded for the container.
     *
     * @return True if the weight limit is exceeded, false otherwise.
     */
    public boolean isWeightExceeded() {
        return weightExceeded;
    }

    /**
     * Sets the status of whether the weight limit is exceeded.
     *
     * @param weightExceeded A boolean indicating if the weight limit is exceeded.
     */
    public void setWeightExceeded(boolean weightExceeded) {
        this.weightExceeded = weightExceeded;
    }

    /**
     * Gets the number of layers in the container.
     *
     * @return The number of layers.
     */
    public int getLayer() {
        return layer;
    }

    /**
     * Sets the number of layers in the container.
     *
     * @param layer The number of layers to set.
     */
    public void setLayer(int layer) {
        this.layer = layer;
    }

    /**
     * Gets the structural arrangement of handling units in the container.
     *
     * @return A string specifying the arrangement structure.
     */
    public String getStructure() {
        return structure;
    }

    /**
     * Sets the structural arrangement of handling units in the container.
     *
     * @param structure A string specifying the arrangement structure.
     */
    public void setStructure(String structure) {
        this.structure = structure;
    }

    /**
     * Gets the total number of handling units in the container calculation result.
     *
     * @return The total count of handling units.
     */
    public int getHuUnitCount() {
        return huUnitCount;
    }

    /**
     * Sets the total number of handling units in the container calculation result.
     *
     * @param huUnitCount The total count of handling units to set.
     */
    public void setHuUnitCount(int huUnitCount) {
        this.huUnitCount = huUnitCount;
    }

    /**
     * Determines the total utilization of the container based on either
     * weight or volume, depending on whether the weight limit is exceeded.
     *
     * @return Total container utilization as a percentage.
     */
    public double getTotalUtilization() {
        return weightExceeded ? getTotalUtilizationByWeight() : getTotalUtilizationByVolume();
    }

    /**
     * Calculates the total utilization of the container,
     * factoring in the HU utilization and count.
     *
     * @return The total utilization value for the container.
     */
    public double getTotalUtilizationByVolume() {
        return getHuUtilizationByVolume() * huUnitCount * layer;
    }

    /**
     * Calculates the utilization of a single handling unit (HU)
     * as a proportion of the container volume.
     *
     * @return The volume utilization ratio of one HU to container volume.
     */
    public double getHuUtilizationByVolume() {
        if (containerType.getVolume() <= 0.0) {
            return 0.0;
        }
        return hu.getVolume(DimensionUnit.M) / containerType.getVolume();
    }

    /**
     * Calculates the total utilization of the container based on weight,
     * factoring in the handling unit utilization and count.
     *
     * @return Total weight utilization of the container as a percentage.
     */
    public double getTotalUtilizationByWeight() {
        return getHuUtilizationByWeight() * huUnitCount;
    }

    /**
     * Calculates the utilization of a single handling unit (HU) as a proportion
     * of the container weight capacity.
     *
     * @return Weight utilization ratio of one HU to the container's maximum weight.
     */
    public double getHuUtilizationByWeight() {
        if (maxContainerWeight == null || maxContainerWeight <= 0) {
            return 0;
        }
        return WeightUnit.KG.convertFromG(hu.getWeight()) / maxContainerWeight;
    }

}
