package com.ecep.contract;

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

import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.domain.Sort.NullHandling;
import org.springframework.data.domain.Sort.Order;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
public class PageArgument {

    private boolean paged = false;
    private int pageNumber = 0;
    private int pageSize = 0;
    private long offset = 0;
    private List<OrderArgument> orders;

    public static PageArgument of(Pageable pageable) {
        PageArgument page = new PageArgument();
        page.setPaged(pageable.isPaged());
        if (page.isPaged()) {
            page.setPageNumber(pageable.getPageNumber());
            page.setPageSize(pageable.getPageSize());
            page.setOffset(pageable.getOffset());
        }

        Sort sort = pageable.getSort();
        if (sort != null && sort.isSorted()) {
            page.setOrders(sort.stream().map(OrderArgument::of).collect(Collectors.toList()));
        }
        return page;
    }

    public Pageable toPageable() {
        Sort sort = null;
        if (orders != null && !orders.isEmpty()) {
            sort = Sort.by(orders.stream().map(order -> new Order(order.getDirection(), order.getProperty(),
                    order.isIgnoreCase(), order.getNullHandling()))
                    .collect(Collectors.toList()));
        } else {
            sort = Sort.unsorted();
        }
        if (isPaged()) {
            return PageRequest.of(pageNumber, pageSize, sort);
        }
        return Pageable.unpaged(sort);
    }

    public boolean isUnpaged() {
        return !isPaged();
    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class OrderArgument {
        private Direction direction;
        private String property;
        private boolean ignoreCase;
        private NullHandling nullHandling;

        public static OrderArgument of(Order order) {
            return new OrderArgument(order.getDirection(), order.getProperty(), order.isIgnoreCase(),
                    order.getNullHandling());
        }
    }

}
