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

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import de.bstly.board.businesslogic.CommentManager;
import de.bstly.board.businesslogic.EntryManager;
import de.bstly.board.businesslogic.SettingsManager;
import de.bstly.board.businesslogic.UserManager;
import de.bstly.board.businesslogic.VoteManager;
import de.bstly.board.controller.support.EntityResponseStatusException;
import de.bstly.board.model.Vote;
import de.bstly.board.model.support.Types;
import de.bstly.board.model.support.VoteType;

/**
 * The Class VoteController.
 */
@RestController
@RequestMapping("/votes")
public class VoteController extends BaseController {

	@Autowired
	private VoteManager voteManager;
	@Autowired
	private EntryManager entryManager;
	@Autowired
	private CommentManager commentManager;
	@Autowired
	private UserManager userManager;
	@Autowired
	private SettingsManager settingsManager;

	/**
	 * Gets the entry points.
	 *
	 * @param id the id
	 * @return the entry points
	 */
	@PreAuthorize("isAuthenticated()")
	@GetMapping("/entry/{id}")
	public long getEntryPoints(@PathVariable("id") Long id) {
		if (!entryManager.exists(id)) {
			throw new EntityResponseStatusException(HttpStatus.UNPROCESSABLE_ENTITY);
		}

		return voteManager.getPoints(id, Types.entry);
	}

	/**
	 * Vote entry up.
	 *
	 * @param id the id
	 */
	@PreAuthorize("isAuthenticated()")
	@PutMapping("/entry/{id}/up")
	public void voteEntryUp(@PathVariable("id") Long id) {
		if (!entryManager.exists(id)) {
			throw new EntityResponseStatusException(HttpStatus.UNPROCESSABLE_ENTITY);
		}

		Vote vote = voteManager.get(getCurrentUsername(), id, Types.entry);
		if (vote == null) {
			vote = new Vote();
			vote.setTarget(id);
			vote.setAuthor(getCurrentUsername());
			vote.setType(VoteType.up);
			vote.setTargetType(Types.entry);
			voteManager.save(vote);
			throw new EntityResponseStatusException(HttpStatus.CREATED);
		} else if (!VoteType.up.equals(vote.getType())) {
			voteManager.delete(vote);
		}
	}

	/**
	 * Vote entry down.
	 *
	 * @param id the id
	 */
	@PreAuthorize("isAuthenticated()")
	@PutMapping("/entry/{id}/down")
	public void voteEntryDown(@PathVariable("id") Long id) {
		if (!entryManager.exists(id)) {
			throw new EntityResponseStatusException(HttpStatus.UNPROCESSABLE_ENTITY);
		}

		if (userManager.getKarma(getCurrentUsername()) < settingsManager.getUnvoteThresh()) {
			throw new EntityResponseStatusException(HttpStatus.FORBIDDEN);
		}

		Vote vote = voteManager.get(getCurrentUsername(), id, Types.entry);
		if (vote == null) {
			vote = new Vote();
			vote.setTarget(id);
			vote.setAuthor(getCurrentUsername());
			vote.setType(VoteType.down);
			vote.setTargetType(Types.entry);
			voteManager.save(vote);
			throw new EntityResponseStatusException(HttpStatus.CREATED);
		} else if (!VoteType.down.equals(vote.getType())) {
			voteManager.delete(vote);
		}
	}

	/**
	 * Unvote entry.
	 *
	 * @param id the id
	 */
	@PreAuthorize("isAuthenticated()")
	@DeleteMapping("/entry/{id}")
	public void unvoteEntry(@PathVariable("id") Long id) {
		if (!entryManager.exists(id)) {
			throw new EntityResponseStatusException(HttpStatus.UNPROCESSABLE_ENTITY);
		}

		Vote vote = voteManager.get(getCurrentUsername(), id, Types.entry);
		if (vote == null) {
			throw new EntityResponseStatusException(HttpStatus.NOT_MODIFIED);
		}

		voteManager.delete(vote);
	}

	/**
	 * Gets the comment points.
	 *
	 * @param id the id
	 * @return the comment points
	 */
	@PreAuthorize("isAuthenticated()")
	@GetMapping("/comment/{id}")
	public long getCommentPoints(@PathVariable("id") Long id) {
		if (!commentManager.exists(id)) {
			throw new EntityResponseStatusException(HttpStatus.UNPROCESSABLE_ENTITY);
		}

		return voteManager.getPoints(id, Types.comment);
	}

	/**
	 * Vote comment up.
	 *
	 * @param id the id
	 */
	@PreAuthorize("isAuthenticated()")
	@PutMapping("/comment/{id}/up")
	public void voteCommentUp(@PathVariable("id") Long id) {
		if (!commentManager.exists(id)) {
			throw new EntityResponseStatusException(HttpStatus.UNPROCESSABLE_ENTITY);
		}

		Vote vote = voteManager.get(getCurrentUsername(), id, Types.comment);
		if (vote == null) {
			vote = new Vote();
			vote.setTarget(id);
			vote.setAuthor(getCurrentUsername());
			vote.setType(VoteType.up);
			vote.setTargetType(Types.comment);
			voteManager.save(vote);
			throw new EntityResponseStatusException(HttpStatus.CREATED);
		} else if (!VoteType.up.equals(vote.getType())) {
			voteManager.delete(vote);
		}
	}

	/**
	 * Vote comment down.
	 *
	 * @param id the id
	 */
	@PreAuthorize("isAuthenticated()")
	@PutMapping("/comment/{id}/down")
	public void voteCommentDown(@PathVariable("id") Long id) {
		if (!commentManager.exists(id)) {
			throw new EntityResponseStatusException(HttpStatus.UNPROCESSABLE_ENTITY);
		}

		Vote vote = voteManager.get(getCurrentUsername(), id, Types.comment);
		if (vote == null) {
			vote = new Vote();
			vote.setTarget(id);
			vote.setAuthor(getCurrentUsername());
			vote.setType(VoteType.down);
			vote.setTargetType(Types.comment);
			voteManager.save(vote);
			throw new EntityResponseStatusException(HttpStatus.CREATED);
		} else if (!VoteType.down.equals(vote.getType())) {
			voteManager.delete(vote);
		}
	}

	/**
	 * Unvote comment.
	 *
	 * @param id the id
	 */
	@PreAuthorize("isAuthenticated()")
	@DeleteMapping("/comment/{id}")
	public void unvoteComment(@PathVariable("id") Long id) {
		if (!commentManager.exists(id)) {
			throw new EntityResponseStatusException(HttpStatus.UNPROCESSABLE_ENTITY);
		}

		Vote vote = voteManager.get(getCurrentUsername(), id, Types.comment);
		if (vote == null) {
			throw new EntityResponseStatusException(HttpStatus.NOT_MODIFIED);
		}

		voteManager.delete(vote);
	}

}
