package com.ibiz.util.feign.suport;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import com.ibiz.util.SearchContext;
import feign.RequestTemplate;
import feign.codec.EncodeException;
import feign.codec.Encoder;

public class SearchContextFeignEncode  implements Encoder {

	private final Encoder delegate;
	
	public SearchContextFeignEncode(Encoder delegate) {
		this.delegate = delegate;
	}
	
	@Override
	public void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException {
		if (supports(object)) {
			if (object instanceof SearchContext) {
				SearchContext searchContext = (SearchContext) object;

				if (searchContext.getPageable().isPaged()) {
					template.query("page", searchContext.getPageable().getPageNumber() + "");
					template.query("size", searchContext.getPageable().getPageSize() + "");
				}

				if (searchContext.getPageable().getSort() != null) {
					applySort(template, searchContext.getPageable().getSort());
				}
				delegate.encode(object, bodyType, template);
			}
		}
		else {
			if (delegate != null) {
				delegate.encode(object, bodyType, template);
			}
			else {
				throw new EncodeException(
						"PageableSpringEncoder does not support the given object "
								+ object.getClass()
								+ " and no delegate was provided for fallback!");
			}
		}
	}
	
	private void applySort(RequestTemplate template, Sort sort) {
		String sortParameter = "sort" ;
		Collection<String> existingSorts = template.queries().get("sort");
		List<String> sortQueries = existingSorts != null ? new ArrayList<>(existingSorts)
				: new ArrayList<>();
		if (!sortParameter.equals("sort")) {
			existingSorts = template.queries().get(sortParameter);
			if (existingSorts != null) {
				sortQueries.addAll(existingSorts);
			}
		}
		for (Sort.Order order : sort) {
			sortQueries.add(order.getProperty() + "," + order.getDirection());
		}
		if (!sortQueries.isEmpty()) {
			template.query(sortParameter, sortQueries);
		}
	}
	
	protected boolean supports(Object object) {
		return object instanceof SearchContext ;
	}

}
