// This proto file was generated from comments-service-api.yml.
// Care should be taken while both files exist to maintain backwards compatibility with the Conjure generated code.

syntax = "proto3";

package nominal.comments.v1;

import "buf/validate/validate.proto";
import "google/api/annotations.proto";
import "google/protobuf/timestamp.proto";
import "nominal/conjure/v1/compat.proto";
import "nominal/gen/v1/alias.proto";
import "nominal/gen/v1/error.proto";

option java_multiple_files = true;
option java_package = "io.nominal.comments.v1";

message Comment {
  // Unique resource identifier for the comment
  string rid = 1 [(nominal.gen.v1.alias) = {java_name: "io.nominal.comments.api.CommentRid"}];

  // The parent of the comment. It can be a resource or another comment.
  CommentParent parent = 2;

  // The user who authored the comment
  string author_rid = 3 [(nominal.gen.v1.alias) = {java_name: "com.palantir.ri.ResourceIdentifier"}];

  // The time the comment was created
  google.protobuf.Timestamp created_at = 4;

  // The time the comment was edited. Empty if the comment has not been edited.
  optional google.protobuf.Timestamp edited_at = 5;

  // The time the comment was deleted. Empty if the comment has not been deleted.
  optional google.protobuf.Timestamp deleted_at = 6;

  // The markdown content of the comment.
  string content = 7;

  // The user who pinned the comment. Empty if the comment is not pinned.
  optional string pinned_by = 8 [(nominal.gen.v1.alias) = {java_name: "com.palantir.ri.ResourceIdentifier"}];

  // The time the comment was pinned. Empty if the comment is not pinned.
  optional google.protobuf.Timestamp pinned_at = 9;

  // The reactions on the comment
  repeated Reaction reactions = 10;

  // The comment's attachments
  repeated string attachments = 11 [(nominal.gen.v1.alias) = {java_name: "io.nominal.api.rids.AttachmentRid"}];
}

// The parent of a comment. It can be a resource or another comment in the case of a reply.
message CommentParent {
  option (nominal.conjure.v1.conjure_compat) = {union_message: true};

  // The parent of a comment. It can be a resource or another comment in the case of a reply.
  oneof comment_parent {
    option (buf.validate.oneof) = {required: true};

    CommentParentResource resource = 1;
    CommentParentComment comment = 2;
  }
}

message CommentParentComment {
  // The resource identifier for the comment that the comment is replying to
  string comment_rid = 1 [(nominal.gen.v1.alias) = {java_name: "io.nominal.comments.api.CommentRid"}];
}

message CommentParentResource {
  // The type of resource that the comment is associated with
  ResourceType resource_type = 1;

  // The resource identifier for the resource that the comment is associated with. For example, a run or a workbook.
  string resource_rid = 2 [(nominal.gen.v1.alias) = {java_name: "com.palantir.ri.ResourceIdentifier"}];
}

message Conversation {
  // RID for the resource that the conversation is associated with.
  string resource_rid = 1 [(nominal.gen.v1.alias) = {java_name: "com.palantir.ri.ResourceIdentifier"}];

  // The type of the resource that the conversation is associated with.
  ResourceType resource_type = 2;

  // The comments on the conversation ordered by creation time.
  // Empty if the comment has no replies.
  repeated ConversationNode comments = 3;
}

message ConversationNode {
  // The comment
  Comment comment = 1;

  // The comments on (aka replies to) the comment ordered by creation time. Empty if the comment has no replies.
  repeated ConversationNode replies = 2;
}

message CreateCommentRequest {
  CommentParent parent = 1;

  // The content of the comment. Markdown supported.
  string content = 2;

  // Attachments to the comment.
  repeated string attachments = 3 [(nominal.gen.v1.alias) = {java_name: "io.nominal.api.rids.AttachmentRid"}];
}

message EditCommentRequest {
  // The content of the comment. Markdown supported.
  string content = 1;

  // Attachments to the comment.
  repeated string attachments = 2 [(nominal.gen.v1.alias) = {java_name: "io.nominal.api.rids.AttachmentRid"}];
}

message Reaction {
  // Unique resource identifier for the reaction
  string rid = 1 [(nominal.gen.v1.alias) = {java_name: "io.nominal.comments.api.ReactionRid"}];

  // The user who authored the reaction
  string user_rid = 2 [(nominal.gen.v1.alias) = {java_name: "com.palantir.ri.ResourceIdentifier"}];

  // The time the reaction was created
  google.protobuf.Timestamp created_at = 3;

  // The type of reaction
  ReactionType type = 4;
}

// buf:lint:ignore ENUM_VALUE_PREFIX
enum ReactionType {
  REACTION_TYPE_UNSPECIFIED = 0;
  LIKE = 1;
  DISLIKE = 2;
  HEART = 3;
  HOORAY = 4;
  ROCKET = 5;
  EYES = 6;
}

// buf:lint:ignore ENUM_VALUE_PREFIX
enum ResourceType {
  RESOURCE_TYPE_UNSPECIFIED = 0;
  RUN = 1;
  EVENT = 2;
}

message GetConversationRequest {
  // The type of resource that the comments are associated with
  ResourceType resource_type = 1;

  // The RID of resource that the comments are associated with
  string resource_rid = 2 [(nominal.gen.v1.alias) = {java_name: "com.palantir.ri.ResourceIdentifier"}];
}

message GetConversationResponse {
  Conversation conversation = 1;
}

message GetConversationCountRequest {
  // The type of resource that the comments are associated with
  ResourceType resource_type = 1;

  // The RID of resource that the comments are associated with
  string resource_rid = 2 [(nominal.gen.v1.alias) = {java_name: "com.palantir.ri.ResourceIdentifier"}];

  // Whether to include deleted comments in the count
  optional bool include_deleted = 3;
}

message GetConversationCountResponse {
  int32 count = 1;
}

message GetCommentRequest {
  // The RID of comment to fetch
  string comment_rid = 1 [(nominal.gen.v1.alias) = {java_name: "io.nominal.comments.api.CommentRid"}];
}

message GetCommentResponse {
  Comment comment = 1;
}

message CreateCommentResponse {
  Comment comment = 1;
}

message EditCommentRequestWrapper {
  // The RID of comment to edit
  string comment_rid = 1 [(nominal.gen.v1.alias) = {java_name: "io.nominal.comments.api.CommentRid"}];

  EditCommentRequest request = 2;
}

message EditCommentResponse {
  Comment comment = 1;
}

message DeleteCommentRequest {
  // The RID of comment to delete
  string comment_rid = 1 [(nominal.gen.v1.alias) = {java_name: "io.nominal.comments.api.CommentRid"}];
}

message DeleteCommentResponse {
  Comment comment = 1;
}

message PinCommentRequest {
  // The RID of comment to pin
  string comment_rid = 1 [(nominal.gen.v1.alias) = {java_name: "io.nominal.comments.api.CommentRid"}];
}

message PinCommentResponse {
  Comment comment = 1;
}

message UnpinCommentRequest {
  // The RID of comment to unpin
  string comment_rid = 1 [(nominal.gen.v1.alias) = {java_name: "io.nominal.comments.api.CommentRid"}];
}

message UnpinCommentResponse {
  Comment comment = 1;
}

message AddReactionRequest {
  // The RID of comment to delete
  string comment_rid = 1 [(nominal.gen.v1.alias) = {java_name: "io.nominal.comments.api.CommentRid"}];

  // The type of reaction
  ReactionType type = 2;
}

message AddReactionResponse {
  Comment comment = 1;
}

message RemoveReactionRequest {
  // The RID of comment to delete
  string comment_rid = 1 [(nominal.gen.v1.alias) = {java_name: "io.nominal.comments.api.CommentRid"}];

  // The type of reaction
  ReactionType type = 2;
}

message RemoveReactionResponse {
  Comment comment = 1;
}

// buf:lint:ignore ENUM_ZERO_VALUE_SUFFIX
enum CommentsError {
  COMMENTS_ERROR_COMMENT_NOT_FOUND = 0 [(nominal.gen.v1.error) = {
    code: "NOT_FOUND"
    message: "CommentNotFound"
  }];
  COMMENTS_ERROR_CONTENT_TOO_LONG = 1 [(nominal.gen.v1.error) = {
    code: "INVALID_ARGUMENT"
    message: "ContentTooLong"
  }];
  COMMENTS_ERROR_EMPTY_COMMENT_CONTENT = 2 [(nominal.gen.v1.error) = {
    code: "INVALID_ARGUMENT"
    message: "EmptyCommentContent"
  }];
  COMMENTS_ERROR_INVALID_ATTACHMENT = 3 [(nominal.gen.v1.error) = {
    code: "INVALID_ARGUMENT"
    message: "InvalidAttachment"
  }];
  COMMENTS_ERROR_MAX_NESTING_DEPTH_EXCEEDED = 4 [(nominal.gen.v1.error) = {
    code: "INVALID_ARGUMENT"
    message: "MaxNestingDepthExceeded"
  }];
  COMMENTS_ERROR_UNAUTHORIZED = 5 [(nominal.gen.v1.error) = {
    code: "PERMISSION_DENIED"
    message: "Unauthorized"
  }];
}

// Comments service manages conversations about resources.
service CommentsService {
  // A conversation is a fully resolved comment tree. It includes all comments for the given resource
  // and all the nested comments/replies to those comments.
  rpc GetConversation(GetConversationRequest) returns (GetConversationResponse) {
    option (google.api.http) = {
      get: "/comments/v1/conversations/{resource_type}/{resource_rid}"
      response_body: "conversation"
    };
  }
  // Returns the number of comments in a conversation.
  rpc GetConversationCount(GetConversationCountRequest) returns (GetConversationCountResponse) {
    option (google.api.http) = {
      get: "/comments/v1/conversations/{resource_type}/{resource_rid}/count"
      response_body: "count"
    };
  }
  // Get a comment identified by its RID
  rpc GetComment(GetCommentRequest) returns (GetCommentResponse) {
    option (google.api.http) = {
      get: "/comments/v1/comments/{comment_rid}"
      response_body: "comment"
    };
  }
  // buf:lint:ignore RPC_REQUEST_STANDARD_NAME
  // Create a comment on a resource
  rpc CreateComment(CreateCommentRequest) returns (CreateCommentResponse) {
    option (google.api.http) = {
      post: "/comments/v1/comments"
      response_body: "comment"
      body: "*"
    };
  }
  // buf:lint:ignore RPC_REQUEST_STANDARD_NAME
  // Edit an existing comment
  rpc EditComment(EditCommentRequestWrapper) returns (EditCommentResponse) {
    option (google.api.http) = {
      response_body: "comment"
      body: "request"
      put: "/comments/v1/comments/{comment_rid}"
    };
  }
  // Delete an existing comment
  rpc DeleteComment(DeleteCommentRequest) returns (DeleteCommentResponse) {
    option (google.api.http) = {
      response_body: "comment"
      delete: "/comments/v1/comments/{comment_rid}"
    };
  }
  // Pin a comment to the top of the conversation
  rpc PinComment(PinCommentRequest) returns (PinCommentResponse) {
    option (google.api.http) = {
      response_body: "comment"
      put: "/comments/v1/comments/{comment_rid}/pin"
    };
  }
  // Unpin a comment from the top of the conversation
  rpc UnpinComment(UnpinCommentRequest) returns (UnpinCommentResponse) {
    option (google.api.http) = {
      response_body: "comment"
      delete: "/comments/v1/comments/{comment_rid}/pin"
    };
  }
  // Create a reaction on a comment
  rpc AddReaction(AddReactionRequest) returns (AddReactionResponse) {
    option (google.api.http) = {
      response_body: "comment"
      put: "/comments/v1/comments/{comment_rid}/reactions/{type}"
    };
  }
  // Create a reaction on a comment
  rpc RemoveReaction(RemoveReactionRequest) returns (RemoveReactionResponse) {
    option (google.api.http) = {
      response_body: "comment"
      delete: "/comments/v1/comments/{comment_rid}/reactions/{type}"
    };
  }
}
