package com.pingcap.community.blogserver.controller;

import com.fasterxml.jackson.annotation.JsonView;
import com.pingcap.community.blogserver.config.convertor.ConvertFromUsername;
import com.pingcap.community.blogserver.entity.*;
import com.pingcap.community.blogserver.exception.user.InvalidUsername;
import com.pingcap.community.blogserver.exception.user.UserNotFound;
import com.pingcap.community.blogserver.qo.UserPostQuery;
import com.pingcap.community.blogserver.service.*;
import com.pingcap.community.blogserver.vo.comment.CommentItemVO;
import com.pingcap.community.blogserver.vo.post.PostItemBasicVO;
import com.pingcap.community.blogserver.vo.user.UserDetailVO;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springdoc.api.annotations.ParameterObject;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@Tag(name = "User API")
@RestController
@AllArgsConstructor
@RequestMapping("/api/users")
public class UserController {

  private final CommentService commentService;

  private final PostService postService;

  private final LikeService likeService;

  private final FavoriteService favoriteService;

  private final UserService userService;

  @GetMapping("/{id:^[1-9]\\d*$}")
  @JsonView(UserDetailVO.UserDetailView.class)
  public UserDetailVO getUserDetail(
    @Parameter(schema = @Schema(implementation = Long.class)) @PathVariable("id") User user,
    @AuthenticationPrincipal User viewer
  ) {
    return userService.getUserDetail(user, viewer);
  }

  @GetMapping("/username/{username}")
  @JsonView(UserDetailVO.UserDetailView.class)
  public UserDetailVO getUserDetailByUsername(
    @Parameter(schema = @Schema(implementation = String.class)) @ConvertFromUsername @PathVariable("username") User user,
    @AuthenticationPrincipal User viewer
  ) {
    return userService.getUserDetail(user, viewer);
  }

  @GetMapping("/{id:^[1-9]\\d*$}/posts")
  public Page<PostItemBasicVO> getUserPostsByUserID(
    @Parameter(schema = @Schema(anyOf = { Long.class, String.class })) @PathVariable("id") User user,
    UserPostQuery query,
    @ParameterObject Pageable pageable,
    @AuthenticationPrincipal User viewer
  ) throws UserNotFound {
    return postService.getUserPosts(user, query, pageable, viewer);
  }

  @GetMapping("/username/{username}/posts")
  public Page<PostItemBasicVO> getUserPostsByUsername(
    @Parameter(schema = @Schema(anyOf = { String.class })) @ConvertFromUsername @PathVariable("username") User user,
    UserPostQuery query, @ParameterObject Pageable pageable,
    @AuthenticationPrincipal User viewer
  ) throws UserNotFound {
    return postService.getUserPosts(user, query, pageable, viewer);
  }

  @GetMapping("/{id:^[1-9]\\d*$}/comments")
  @JsonView(CommentItemVO.UserCommentItemVO.class)
  public Page<CommentItemVO> getUserComments(
      @Parameter(schema = @Schema(implementation = Long.class)) @PathVariable("id") Long userId,
      @ParameterObject Pageable pageable) {
    return commentService.getUserComments(userId, pageable);
  }

  @GetMapping("/username/{username}/comments")
  @JsonView(CommentItemVO.UserCommentItemVO.class)
  public Page<CommentItemVO> getUserCommentsByUsername(
      @Parameter(schema = @Schema(implementation = String.class)) @ConvertFromUsername @PathVariable("username") User user,
      @ParameterObject Pageable pageable
  ) throws InvalidUsername, UserNotFound {
    return commentService.getUserCommentsByUsername(user.getUsername(), pageable);
  }

  @GetMapping("/{id:^[1-9]\\d*$}/likes")
  @JsonView(Like.LikeItemView.class)
  public Page<Like> getUserLikes(
      @Parameter(schema = @Schema(implementation = Long.class)) @PathVariable("id") Long userId,
      @ParameterObject Pageable pageable) {
    return likeService.getUserLikes(userId, pageable);
  }

  @GetMapping("/username/{username}/likes")
  @JsonView(Like.LikeItemView.class)
  public Page<Like> getUserLikes(
    @Parameter(schema = @Schema(implementation = String.class)) @ConvertFromUsername @PathVariable("username") User user,
    @ParameterObject Pageable pageable
  ) {
    return likeService.getUserLikesByUsername(user.getUsername(), pageable);
  }

  @GetMapping("/{id}/favorites")
  @JsonView(Favorite.FavoriteItemView.class)
  public Page<Favorite> getUserFavorites(
    @Parameter(schema = @Schema(implementation = Long.class)) @PathVariable("id") Long userId,
    @ParameterObject Pageable pageable
  ) {
    return favoriteService.getUserFavorites(userId, pageable);
  }

  @GetMapping("/username/{username}/favorites")
  @JsonView(Favorite.FavoriteItemView.class)
  public Page<Favorite> getUserFavoritesByUsername(
    @Parameter(schema = @Schema(implementation = String.class)) @ConvertFromUsername @PathVariable("username") User user,
    @ParameterObject Pageable pageable
  ) {
    return favoriteService.getUserFavoritesByUsername(user.getUsername(), pageable);
  }

}
