syntax = "proto3";

package photon.imessage.v1;

import "photon/imessage/v1/chat_types.proto";
import "google/protobuf/empty.proto";
import "photon/imessage/v1/group_types.proto";
import "photon/imessage/v1/streaming.proto";

option swift_prefix = "PIMsg_";


// ---------------------------------------------------------------------------
// Service
// ---------------------------------------------------------------------------

// Group-chat administration plus a durable event stream.
service GroupService {

  // Writes
  rpc SetDisplayName(SetDisplayNameRequest) returns (SetDisplayNameResponse);

  rpc AddParticipants(AddParticipantsRequest) returns (AddParticipantsResponse);

  rpc RemoveParticipants(RemoveParticipantsRequest) returns (RemoveParticipantsResponse);

  // Local user voluntarily leaves the group. The chat ceases to be
  // visible from this device, hence no Chat snapshot.
  rpc LeaveGroup(LeaveGroupRequest) returns (google.protobuf.Empty);

  rpc SetIcon(SetIconRequest) returns (google.protobuf.Empty);

  rpc RemoveIcon(RemoveIconRequest) returns (google.protobuf.Empty);

  // Reads
  rpc GetIcon(GetIconRequest) returns (GetIconResponse);

  // Streams
  rpc SubscribeGroupEvents(SubscribeGroupEventsRequest)
      returns (stream SubscribeGroupEventsResponse);

}


// ---------------------------------------------------------------------------
// Writes
// ---------------------------------------------------------------------------

message SetDisplayNameRequest {

  string chat_guid = 1;

  string display_name = 2;

  optional string client_message_id = 100;

}


message SetDisplayNameResponse {

  Chat chat = 1;

}


// Adds one or more participants. An empty `addresses` list
// is rejected with `INVALID_ARGUMENT`.
message AddParticipantsRequest {

  string chat_guid = 1;

  repeated string addresses = 2;

  optional string client_message_id = 100;

}


message AddParticipantsResponse {

  Chat chat = 1;

}


// Removes one or more participants. An empty `addresses`
// list is rejected with `INVALID_ARGUMENT`.
message RemoveParticipantsRequest {

  string chat_guid = 1;

  repeated string addresses = 2;

  optional string client_message_id = 100;

}


message RemoveParticipantsResponse {

  Chat chat = 1;

}


message LeaveGroupRequest {

  string chat_guid = 1;

  optional string client_message_id = 100;

}


message SetIconRequest {

  string chat_guid = 1;

  // Server infers MIME type and file extension from `data`.
  bytes data = 2;

  optional string client_message_id = 100;

}


message RemoveIconRequest {

  string chat_guid = 1;

  optional string client_message_id = 100;

}


// ---------------------------------------------------------------------------
// Reads
// ---------------------------------------------------------------------------

message GetIconRequest {

  string chat_guid = 1;

}


message GetIconResponse {

  bytes data = 1;

  // MIME type of `data`. Always set on success; a missing icon returns
  // `NOT_FOUND` instead of an empty payload.
  string mime_type = 2;

}


// ---------------------------------------------------------------------------
// Streams
// ---------------------------------------------------------------------------

message SubscribeGroupEventsRequest {

  // Absent = subscribe to every group chat the caller can observe.
  optional string chat_guid = 1;

}


message SubscribeGroupEventsResponse {

  // Monotonic global sequence shared with `EventService.CatchUpEvents`
  // and every other `Subscribe*` stream. Absent on heartbeat frames.
  optional uint64 sequence = 1;

  oneof payload {

    GroupChangeEvent group_changed = 10;

    Heartbeat heartbeat = 99;

  }

}
