/**
 * 
 */
package de.bstly.board.controller;

import java.util.List;
import java.util.Optional;

import org.hibernate.search.engine.search.query.SearchResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.google.common.collect.Lists;

import de.bstly.board.businesslogic.CommentManager;
import de.bstly.board.businesslogic.EntryManager;
import de.bstly.board.businesslogic.SearchManager;
import de.bstly.board.businesslogic.SettingsManager;
import de.bstly.board.businesslogic.UserManager;
import de.bstly.board.model.Comment;
import de.bstly.board.model.Entry;
import de.bstly.board.model.support.Types;

/**
 * @author _bastler@bstly.de
 *
 */
@RestController
@RequestMapping("/search")
public class SearchController extends BaseController {

	@Autowired
	private SearchManager searchManager;
	@Autowired
	private SettingsManager settingsManager;
	@Autowired
	private EntryManager entryManager;
	@Autowired
	private UserManager userManager;
	@Autowired
	private CommentManager commentManager;

	/**
	 * Search.
	 *
	 * @param searchParameter the search parameter
	 * @param pageParameter   the page parameter
	 * @param sizeParameter   the size parameter
	 * @param byDateParameter the by date parameter
	 * @param ascParameter    the asc parameter
	 * @param ignoreParameter the ignore parameter
	 * @return the page
	 */
	@PreAuthorize("isAuthenticated()")
	@GetMapping
	public Page<Object> search(@RequestParam("q") String searchParameter,
			@RequestParam("type") Optional<String> typeParameter,
			@RequestParam("page") Optional<Integer> pageParameter,
			@RequestParam("size") Optional<Integer> sizeParameter,
			@RequestParam("byDate") Optional<Boolean> byDateParameter,
			@RequestParam("asc") Optional<Boolean> ascParameter,
			@RequestParam("ignore") Optional<List<String>> ignoreParameter) {

		if (sizeParameter.isPresent() && sizeParameter.get() > 100) {
			sizeParameter = Optional.of(100);
		}

		String type = typeParameter.orElse(Types.entry.toString());

		List<Types> types = Lists.newArrayList();

		switch (type) {
		case "entry":
			types.add(Types.entry);
			break;
		case "comment":
			types.add(Types.comment);
			break;
		case "all":
			types.add(Types.comment);
			types.add(Types.entry);
			break;
		}

		SearchResult<Object> result = searchManager.search(types, searchParameter,
				pageParameter.orElse(0), sizeParameter.orElse(settingsManager.getPageSize()),
				ascParameter.orElse(false), byDateParameter.orElse(false));

		Page<Object> objects = new PageImpl<Object>(result.hits(),
				PageRequest.of(pageParameter.orElse(0),
						sizeParameter.orElse(settingsManager.getPageSize())),
				result.total().hitCount());

		List<String> ignore = ignoreParameter.orElse(Lists.newArrayList());

		for (Object object : objects) {
			if (object instanceof Entry) {
				entryManager.applyMetadata(getCurrentUsername(),
						userManager.getKarma(getCurrentUsername()), (Entry) object, ignore);
			} else if (object instanceof Comment) {
				commentManager.applyMetadata(getCurrentUsername(), (Comment) object, ignore);
			}
		}

		return objects;
	}

}
