package com.izouma.immall.web;

import com.izouma.immall.annotations.Searchable;
import com.izouma.immall.dto.PageQuery;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;

import javax.persistence.criteria.Predicate;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

public class BaseController {
    public PageRequest toPageRequest(PageQuery pageQuery) {
        PageRequest pageRequest;
        if (StringUtils.isNotEmpty(pageQuery.getSort())) {
            List<Sort.Order> orders = new ArrayList<>();
            for (String sortStr : pageQuery.getSort().split(";")) {
                String direction = "asc";
                String prop = sortStr;
                if (sortStr.contains(",asc") || sortStr.contains(",desc")) {
                    prop = sortStr.split(",")[0];
                    direction = sortStr.split(",")[1];
                }
                orders.add("asc".equals(direction) ? Sort.Order.asc(prop) : Sort.Order.desc(prop));
            }
            pageRequest = PageRequest.of(pageQuery.getPage(), pageQuery.getSize(), Sort.by(orders));
        } else {
            pageRequest = PageRequest.of(pageQuery.getPage(), pageQuery.getSize());
        }
        return pageRequest;
    }

    public <T> Specification<T> toSpecification(PageQuery pageQuery, Class queryClass) {
        return (Specification<T>) (root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> and = new ArrayList<>();
            pageQuery.getQuery().forEach((property, value) -> {
                if (value == null) {
                    return;
                }
                if (String.class.equals(value.getClass())) {
                    if (StringUtils.isEmpty((String) value)) {
                        return;
                    }
                }
                and.add(criteriaBuilder.and(criteriaBuilder.equal(root.get(property), value)));
            });
            if (StringUtils.isNotEmpty(pageQuery.getSearch())) {
                Field[] fields = queryClass.getDeclaredFields();
                List<Predicate> or = new ArrayList<>();
                try {

                    or.add(criteriaBuilder.equal(root.get("id"), pageQuery.getSearch()));
                } catch (Exception e) {
                }
                for (Field field : fields) {
                    Searchable annotation = field.getAnnotation(Searchable.class);
                    if (annotation == null) {
                        continue;
                    }
                    if (!annotation.value()) {
                        continue;
                    }
                    or.add(criteriaBuilder.like(root.get(field.getName()), "%" + pageQuery.getSearch() + "%"));
                }
                and.add(criteriaBuilder.or(or.stream().toArray(Predicate[]::new)));
            }
            return criteriaBuilder.and(and.stream().toArray(Predicate[]::new));
        };
    }
}
