package eu.reply.lea.tenants.westwing.wm.entities;


import jakarta.persistence.ElementCollection;
import jakarta.persistence.Entity;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.FetchType;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.NamedQuery;
import jakarta.persistence.Table;
import jakarta.persistence.UniqueConstraint;
import jakarta.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import eu.reply.lea.tenants.westwing.wm.enums.ComparisonOperation;
import eu.reply.lea.tenants.westwing.wm.request.DropOffPointRequestHeader;
import eu.reply.sce.backend.core.entity.StandardEntity;


@Entity
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table(
    uniqueConstraints = {
        @UniqueConstraint(columnNames = {"sequence", "siteCode"})
    }
)
@NamedQuery(name = DropOffPoint.FIND_BY_SITE_CODE, query = DropOffPoint.BY_SITE_CODE_QUERY)
public class DropOffPoint extends StandardEntity {

    public static final String FIND_BY_SITE_CODE = "findBySiteCode";
    public static final String P_SITE_CODE = "siteCode";
    public static final String BY_SITE_CODE_QUERY = "select d from DropOffPoint d"
                                                    + " where d.enabled = true and d.siteCode = :"
                                                    + P_SITE_CODE;


    private static final long serialVersionUID = -4241558462200818070L;
    private static final Map<String, Integer> handlingTypeOrder = new HashMap<>();

    static {
        handlingTypeOrder.put("Small", 1);
        handlingTypeOrder.put("Bulky", 2);
        handlingTypeOrder.put("2MH", 3);
        handlingTypeOrder.put("Big", 4);
    }

    @ManyToOne(optional = false)
    private DropOffPointHeader dropOffPointHeader;

    @Builder.Default
    private boolean enabled = true;
    private int sequence;

    @NotNull
    private String name;

    @NotNull
    private String siteCode;
    private String description;
    private String orderType;

    @Builder.Default
    private Boolean consolidation = false;
    private String handlingType;

    private BigDecimal fragilityIndex;
    @Builder.Default
    @Enumerated(EnumType.STRING)
    private ComparisonOperation fragilityIndexOperation = ComparisonOperation.EQUAL;

    private BigDecimal minWeight;
    private BigDecimal maxWeight;
    @Builder.Default
    @Enumerated(EnumType.STRING)
    private ComparisonOperation weightOperation = ComparisonOperation.EQUAL;

    private BigDecimal minVolume;
    private BigDecimal maxVolume;
    @Builder.Default
    @Enumerated(EnumType.STRING)
    private ComparisonOperation volumeOperation = ComparisonOperation.EQUAL;

    private BigDecimal maxSize;
    @Builder.Default
    @Enumerated(EnumType.STRING)
    private ComparisonOperation maxSizeOperation = ComparisonOperation.EQUAL;

    private BigDecimal minSize;
    @Builder.Default
    @Enumerated(EnumType.STRING)
    private ComparisonOperation minSizeOperation = ComparisonOperation.EQUAL;

    private BigDecimal pickingListCount;
    @Builder.Default
    @Enumerated(EnumType.STRING)
    private ComparisonOperation pickingListCountOperation = ComparisonOperation.EQUAL;

    @ElementCollection(fetch = FetchType.EAGER)
    private Set<BigDecimal> fragilityIndexes;
    private BigDecimal fragilityIndexItemCount;
    @Builder.Default
    @Enumerated(EnumType.STRING)
    private ComparisonOperation fragilityIndexItemCountOperation = ComparisonOperation.EQUAL;


    private static int compareHandlingTypes(final String handlingType1, final String handlingType2) {
        return Integer.compare(
            handlingTypeOrder.getOrDefault(handlingType1, Integer.MAX_VALUE),
            handlingTypeOrder.getOrDefault(handlingType2, Integer.MAX_VALUE)
        );
    }

    public static List<DropOffPoint> findBySiteCode(final EntityManager em, final String siteCode) {
        return em.createNamedQuery(FIND_BY_SITE_CODE, DropOffPoint.class)
            .setParameter(P_SITE_CODE, siteCode)
            .getResultList();
    }

    public boolean matches(final DropOffPointRequestHeader request) {

        if (orderType != null && !orderType.equals(request.getOrderType())) {
            return false;
        }

        if (consolidation != null && !consolidation.equals(request.getConsolidation())) {
            return false;
        }

        if (handlingType != null && request.getMinHandlingType() != null && !handlingType.equals(request.getMinHandlingType())) {
            return false;
        }

        if (request.getFragilityIndexList() != null) {
            for (BigDecimal fragilityIndexValue : request.getFragilityIndexList()) {
                if (!compareValue(fragilityIndexValue, fragilityIndex, fragilityIndexOperation)) {
                    return false;
                }
            }
        }

        if (fragilityIndexes != null && request.getFragilityIndexList() != null && !fragilityIndexes.isEmpty()
            && !compareValue(
            BigDecimal.valueOf(request.getFragilityIndexList().stream().filter(fragilityIndexes::contains).count()),
            fragilityIndexItemCount, fragilityIndexItemCountOperation)) {
            return false;
        }

        if (pickingListCount != null && !compareValue(request.getPickingListCount(), pickingListCount,
                                                      pickingListCountOperation)) {
            return false;
        }

        if (!compareRange(request.getWeight(), minWeight, maxWeight, weightOperation)) {
            return false;
        }

        if (!compareRange(request.getVolume(), minVolume, maxVolume, volumeOperation)) {
            return false;
        }

        if (!compareValue(request.getMaxSize(), maxSize, maxSizeOperation)) {
            return false;
        }

        if (!compareValue(request.getMinSize(), minSize, minSizeOperation)) {
            return false;
        }

        return true;
    }

    private boolean compareValue(final BigDecimal requestValue, final BigDecimal criteriaValue,
                                 final ComparisonOperation operation) {
        if (criteriaValue == null || requestValue == null) {
            return true;
        }
        int comparison = requestValue.compareTo(criteriaValue);
        return switch (operation) {
            case LESS_THAN -> comparison < 0;
            case LESS_THAN_EQUAL -> comparison <= 0;
            case GREATER_THAN -> comparison > 0;
            case GREATER_THAN_EQUAL -> comparison >= 0;
            case EQUAL -> comparison == 0;
            default -> false;
        };
    }

    private boolean compareRange(final BigDecimal requestValue, final BigDecimal minValue, final BigDecimal maxValue,
                                 final ComparisonOperation operation) {
        if (requestValue == null) {
            return true;
        }
        boolean minValid = minValue == null || compareValue(requestValue, minValue, operation == ComparisonOperation.BETWEEN
                                                                                    ? ComparisonOperation.GREATER_THAN_EQUAL
                                                                                    : ComparisonOperation.GREATER_THAN);
        boolean maxValid = maxValue == null || compareValue(requestValue, maxValue, operation == ComparisonOperation.BETWEEN
                                                                                    ? ComparisonOperation.LESS_THAN_EQUAL
                                                                                    : ComparisonOperation.LESS_THAN);
        return minValid && maxValid;
    }


}
package eu.reply.lea.tenants.westwing.wm.entities;


import jakarta.persistence.CascadeType;
import jakarta.persistence.Entity;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
import jakarta.persistence.UniqueConstraint;
import java.util.HashSet;
import java.util.Set;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import eu.reply.sce.backend.core.entity.StandardEntity;


@Entity
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table(
    uniqueConstraints = {
        @UniqueConstraint(columnNames = {"name", "siteCode"})
    }
)
public class DropOffPointHeader extends StandardEntity {

    private static final long serialVersionUID = -5499697325844422439L;

    @OneToMany(mappedBy = "dropOffPointHeader", cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.DETACH},
        orphanRemoval = true)
    private Set<DropOffPoint> dropOffPoints = new HashSet<>();

    private String name;
    private String siteCode;


}


Considering the entity above, i want to create a fe page (similar to the one i have shown you, using YUI.
which has a button to insert a new dropoffpoint and a button to insert a new parameter in the dropoffpoint.
For esample to insert a new parameter for the dropoffpoint you would have a picker where you select "volume" then it would appear in the same row a form where you insert the min value , a form where you insert the max value and a form where you insert the operator