package io.delphiplatform.api.v3.rdb.service.specification;

import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;

import io.delphiplatform.api.util.CollectionUtils;
import io.delphiplatform.api.util.JpaUtils;

public class MultiTextIgnoreCaseValuePropertySpecification<T> extends OperationOnPropertySpecification<T> {

    private final List<String> propertyPath;
    private final Collection<String> searchValue;

    public MultiTextIgnoreCaseValuePropertySpecification(List<String> propertyPath, Collection<String> searchValue, List<String> joins,
        boolean doDistinct) {
        super(joins, doDistinct);
        this.propertyPath = propertyPath;
        this.searchValue = searchValue;
    }

    @Override
    protected boolean canProducePredicate() {
        return !CollectionUtils.isEmpty(searchValue);
    }

    @Override
    protected Predicate doOperation(CriteriaBuilder cb, Path<T> path) {
        @SuppressWarnings("unchecked")
        Expression<String> pathToTextField = (Expression<String>) JpaUtils.getPath(path, propertyPath);

        if (!pathToTextField.getJavaType().equals(String.class)) {
            throw new IllegalArgumentException(String.format("This specification is only for text fields. "
                + "Property path must point to text field, not '%s'", pathToTextField.getJavaType()));
        }

        return cb.isTrue(
            cb.upper(pathToTextField).in(
                searchValue.stream()
                    .map(String::toUpperCase)
                    .collect(Collectors.toSet())
            )
        );
    }
}
