package com.pingcap.community.blogserver.entity;

import com.fasterxml.jackson.annotation.JsonView;
import com.pingcap.community.blogserver.enums.authority.CommentAuthority;
import com.pingcap.community.blogserver.support.acl.sdr.IRestAclEntity;
import com.pingcap.community.blogserver.util.UserAuthorityUtils;
import lombok.*;
import org.hibernate.annotations.*;
import org.springframework.http.HttpMethod;
import org.springframework.security.core.Authentication;

import javax.persistence.*;
import javax.persistence.Entity;
import javax.persistence.Table;

@Entity(name = "comment")
@Table(name = "comments")
@SQLDelete(sql = "UPDATE comments SET deleted_at = now() WHERE id = ?")
@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class Comment extends BaseEntity implements IRestAclEntity {

  public interface CommentSimpleView {}

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "id", nullable = false)
  @JsonView(CommentSimpleView.class)
  private Long id;

  @Lob
  @Column(name = "content", nullable = false)
  @JsonView(CommentSimpleView.class)
  private String content;

  // Notice: If this comment does not reply to other comments, filled in null.
  @ManyToOne
  @JoinColumn(name = "reply_comment_id")
  @ToString.Exclude
  @JsonView(CommentSimpleView.class)
  private Comment replyComment;

  @ManyToOne
  @JoinColumn(name = "post_id", nullable = false)
  @ToString.Exclude
  @NotFound(action = NotFoundAction.IGNORE)
  private Post post;

  @ManyToOne
  @JoinColumn(name = "commenter_id", nullable = false)
  @NotFound(action = NotFoundAction.IGNORE)
  @JsonView(CommentSimpleView.class)
  private User commenter;

  @Column(name = "level", nullable = false, columnDefinition = "int default 1")
  private Integer level;

  public boolean isAuthor(User user) {
    if (user == null) {
      return false;
    } else {
      return this.commenter.equals(user);
    }
  }

  @Override
  public boolean hasPermission(Authentication authentication, HttpMethod accessMethod) {
    // The comment is visible for everyone.
    if (accessMethod.equals(HttpMethod.GET)) {
      return true;
    }
    if (authentication.isAuthenticated()) {
      // The author of the post has full control over the comment.
      Object principal = authentication.getPrincipal();
      if (principal instanceof User user && isAuthor(user)) {
        return switch (accessMethod) {
          case PATCH, PUT -> UserAuthorityUtils.hasAuthority(authentication, CommentAuthority.MODIFY_COMMENT);
          case DELETE -> UserAuthorityUtils.hasAuthority(authentication, CommentAuthority.DELETE_COMMENT);
          default -> false;
        };
      }

      // Others except the author should have -OTHERS- permission to operate on the comment.
      return switch (accessMethod) {
        case PATCH, PUT -> UserAuthorityUtils.hasAuthority(authentication, CommentAuthority.MODIFY_OTHERS_COMMENT);
        case DELETE -> UserAuthorityUtils.hasAuthority(authentication, CommentAuthority.DELETE_OTHERS_COMMENT);
        default -> false;
      };
    }
    return false;
  }

}
