package org.codiki.posts;

import java.io.IOException;
import java.security.Principal;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

import javax.servlet.http.HttpServletResponse;

import org.codiki.core.entities.dto.PostDTO;
import org.codiki.core.entities.dto.View;
import org.codiki.core.entities.persistence.Post;
import org.codiki.core.entities.persistence.User;
import org.codiki.core.repositories.PostRepository;
import org.codiki.core.services.ParserService;
import org.codiki.core.services.UserService;
import org.codiki.core.utils.StringUtils;
import org.springframework.data.domain.PageRequest;
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.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.fasterxml.jackson.annotation.JsonView;

@RestController
@RequestMapping("/api/posts")
public class PostController {
	private static final int LIMIT_POSTS_HOME = 20;
	/** Service to parse post content. */
	private ParserService parserService;
	/** Posts repository. */
	private PostRepository postRepository;
	/** Posts business service. */
	private PostService postService;
	/** Users business service. */
	private UserService userService;

	/**
	 * Constructor.
	 * @param parserService Service to parse post content.
	 * @param postRepository Posts repository.
	 * @param postService Posts business service.
	 * @param userService Users business service.
	 */
	public PostController(ParserService parserService,
						  PostRepository postRepository,
						  PostService postService,
						  UserService userService) {
		this.parserService = parserService;
		this.postRepository = postRepository;
		this.postService = postService;
		this.userService = userService;
	}

	@GetMapping
	public List<PostDTO> getAll() {
		return StreamSupport.stream(postRepository.findAll().spliterator(), false)
				.map(PostDTO::new)
				.collect(Collectors.toList());
	}

	@JsonView(View.PostDTO.class)
	@GetMapping("/{postKey}")
	public Post getByKey(@PathVariable("postKey") final String pPostKey, 
			final HttpServletResponse response) {
		final Post result = getByKeyAndSource(pPostKey, response);
		if(result != null) {
			result.setText(parserService.parse(result.getText()));
		}
		return result;
	}

	@JsonView(View.PostDTO.class)
	@GetMapping("/{postKey}/source")
	public Post getByKeyAndSource(@PathVariable("postKey")final String pPostKey,
			final HttpServletResponse response) {
		return postRepository.getByKey(pPostKey)
				.orElseGet(() -> {
					response.setStatus(HttpServletResponse.SC_NOT_FOUND);
					return null;
				});
	}

	@JsonView(View.PostDTO.class)
	@GetMapping("/last")
	public List<Post> getLast() {
		return postRepository.getLast(PageRequest.of(0, LIMIT_POSTS_HOME));
	}

	@JsonView(View.PostDTO.class)
	@GetMapping("/search/{searchCriteria}")
	public List<Post> search(@PathVariable("searchCriteria") final String pSearchCriteria) {
		return postService.search(pSearchCriteria);
	}

	@JsonView(View.PostDTO.class)
	@GetMapping("/byCategory/{categoryId}")
	public List<Post> getByCategory(@PathVariable("categoryId") final Long pCategoryId) {
		return postRepository.getByCategoryId(pCategoryId);
	}

	@JsonView(View.PostDTO.class)
	@GetMapping("/myPosts")
	public List<Post> getMyPosts(final HttpServletResponse pResponse, final Principal pPrincipal) throws IOException {
		List<Post> result = new LinkedList<>();
		
		final Optional<User> connectedUser = userService.getUserByPrincipal(pPrincipal);
		if(connectedUser.isPresent()) {
			result = postRepository.getByCreator(connectedUser.get().getId());
		} else {
			pResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED);
		}
		
		return result;
	}

	@JsonView(View.PostDTO.class)
	@PostMapping("/preview")
	public Post preview(@RequestBody final Post pPost) {
		pPost.setImage(StringUtils.isNull(pPost.getImage())
				? "https://news-cdn.softpedia.com/images/news2/this-is-the-default-wallpaper-of-the-gnome-3-20-desktop-environment-500743-2.jpg"
				: pPost.getImage());

		pPost.setText(parserService.parse(pPost.getText()));
		
		return pPost;
	}

	@JsonView(View.PostDTO.class)
	@PostMapping("/")
	public Post insert(@RequestBody final Post pPost,
					   final HttpServletResponse pResponse,
					   final Principal pPrincipal) {
		pResponse.setStatus(postService.insert(pPost, pPrincipal));
		return pPost;
	}
	
	@PutMapping("/")
	public void update(@RequestBody final Post pPost,
					   final HttpServletResponse pResponse, final Principal pPrincipal) throws IOException {
		postService.update(pPost, pResponse, pPrincipal);
	}
	
	@DeleteMapping("/{postKey}")
	public void delete(@PathVariable("postKey") final String pPostKey, final Principal pPrincipal) {
		postService.delete(pPostKey, pPrincipal);
	}
}
