package com.sandjelkovic.dispatchd.api;

import com.sandjelkovic.dispatchd.api.resources.PageMetadataResource;
import com.sandjelkovic.dispatchd.data.EmptyCollections;
import org.springframework.data.domain.Sort;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.mvc.ControllerLinkBuilder;
import org.springframework.util.Assert;
import org.springframework.web.util.UriComponentsBuilder;

import java.util.Map;
import java.util.Optional;

public class PageLinksAssembler {

	private final PageMetadataResource pageMetadata;
	private final ControllerLinkBuilder baseLink;
	private final Optional<Sort> sort;
	private String pageSize;

	public PageLinksAssembler(PageMetadataResource pageMetadata, ControllerLinkBuilder baseLink) {
		Assert.notNull(pageMetadata);
		Assert.notNull(baseLink);
		this.pageMetadata = pageMetadata;
		this.baseLink = baseLink;
		this.pageSize = String.valueOf(pageMetadata.getSize());
		sort = Optional.ofNullable(pageMetadata.getSort());
	}

	public Link getTemplatedBaseLink() {
		return new Link(prepareHref(getFullyTemplatedUriBuilder()));
	}

	private Link getBaseLinkWithTemplatedParameters() {
		return new Link(prepareHref(getBaseTemplatedUriBuilder()));
	}

	public Optional<Link> getCurrentLink() {
		String pageNumber = String.valueOf(pageMetadata.getNumber());
		Link expandedLink = getBaseLinkWithTemplatedParameters().expand(getParamsForExpansion(pageNumber));
		return Optional.of(expandedLink.withRel(Link.REL_SELF));
	}

	public Optional<Link> getNextLink() {
		if (pageMetadata.hasNext()) {
			String pageNumber = String.valueOf(pageMetadata.nextPageable().getPageNumber());
			Link expandedLink = getBaseLinkWithTemplatedParameters().expand(getParamsForExpansion(pageNumber));
			return Optional.of(expandedLink.withRel(Link.REL_NEXT));
		}
		return Optional.empty();
	}

	public Optional<Link> getPreviousLink() {
		if (pageMetadata.hasPrevious()) {
			String pageNumber = String.valueOf(pageMetadata.getNumber() - 1);
			Link expandedLink = getBaseLinkWithTemplatedParameters().expand(getParamsForExpansion(pageNumber));
			return Optional.of(expandedLink.withRel(Link.REL_PREVIOUS));
		}
		return Optional.empty();
	}

	public Optional<Link> getFirstLink() {
		String pageNumber = String.valueOf(0L);
		Link expandedLink = getBaseLinkWithTemplatedParameters().expand(getParamsForExpansion(pageNumber));
		return Optional.of(expandedLink.withRel(Link.REL_FIRST));
	}

	public Optional<Link> getLastLink() {
		String pageNumber = String.valueOf(pageMetadata.getTotalPages());
		Link expandedLink = getBaseLinkWithTemplatedParameters().expand(getParamsForExpansion(pageNumber));
		return Optional.of(expandedLink.withRel(Link.REL_LAST));
	}

	private Map<String, String> getParamsForExpansion(String pageNumber) {
		Map<String, String> params = EmptyCollections.map();
		params.put("page", pageNumber);
		if (pageSize != null) {
			params.put("size", pageSize);
		}
		sort.ifPresent(s -> params.put("sort", s.toString()));
		return params;
	}

	private String prepareHref(UriComponentsBuilder componentsBuilder) {
		return componentsBuilder.build().toString();
	}

	private UriComponentsBuilder getBaseTemplatedUriBuilder() {
		UriComponentsBuilder uri = baseLink.toUriComponentsBuilder()
				.query("page={page}")
				.query("size={size}");
		sort.ifPresent(s -> uri.query("sort={sort}"));
		return uri;
	}

	private UriComponentsBuilder getFullyTemplatedUriBuilder() {
		return baseLink.toUriComponentsBuilder()
				.query("page={page}")
				.query("size={size}")
				.query("sort={sort}");
	}
}

@@ -562,74 +562,72 @@
 nal 
-ControllerLinkBuilder baseLink;%0A%09private final Optional%3CSort%3E sort
+Optional%3CSort%3E sort;%0A%09private final UriComponentsBuilder baseUri
 ;%0A%09p
@@ -731,24 +731,200 @@
 LinkBuilder 
+baseControllerLink) %7B%0A%09%09this(pageMetadata, baseControllerLink.toUriComponentsBuilder());%0A%09%7D%0A%0A%09public PageLinksAssembler(PageMetadataResource pageMetadata, UriComponentsBuilder 
 baseLink) %7B%0A
@@ -986,24 +986,51 @@
 nk);%0A%09%09this.
+baseUri = baseLink;%0A%09%09this.
 pageMetadata
@@ -1048,36 +1048,8 @@
 data
-;%0A%09%09this.baseLink = baseLink
 ;%0A%09%09
@@ -3401,37 +3401,11 @@
 base
-Link.toUriComponentsBuilder()
+Uri
 %0A%09%09%09
@@ -3600,37 +3600,11 @@
 base
-Link.toUriComponentsBuilder()
+Uri
 %0A%09%09%09

Make PageLinksAssembler more flexible