/*
 * Wire
 * Copyright (C) 2021 Wire Swiss GmbH
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see http://www.gnu.org/licenses/.
 *
 */

syntax = "proto2";

option java_package = "com.waz.model";
option optimize_for = LITE_RUNTIME;

message GenericMessage {
  required string message_id = 1; // client generated random id, preferably UUID
  oneof content {
    Text text = 2;
    ImageAsset image = 3; // deprecated in favour of Asset
    Knock knock = 4;
    LastRead lastRead = 6;
    Cleared cleared = 7;
    External external = 8;
    ClientAction clientAction = 9;
    Calling calling = 10;
    Asset asset = 11;
    MessageHide hidden = 12;
    Location location = 13;
    MessageDelete deleted = 14;
    MessageEdit edited = 15;
    Confirmation confirmation = 16;
    Reaction reaction = 17;
    Ephemeral ephemeral = 18;
    Availability availability = 19;
    Composite composite = 20;
    ButtonAction buttonAction = 21;
    ButtonActionConfirmation buttonActionConfirmation = 22;
    DataTransfer dataTransfer = 23; // client-side synchronization across devices of the same user
  }
}

message QualifiedUserId {
  required string id     = 1;
  required string domain = 2;
}

message QualifiedConversationId {
  required string id = 1;
  required string domain = 2;
}

message Composite {
  repeated Item items = 1;
  optional bool expects_read_confirmation = 2 [default = false];
  optional LegalHoldStatus legal_hold_status = 3 [default = UNKNOWN];

  message Item {
      oneof content {
          Text text = 1;
          Button button = 2;
      }
  }
}

message Button {
  required string text = 1;
  required string id = 2;
}

message ButtonAction {
  required string button_id = 1;
  required string reference_message_id = 2;
}

message ButtonActionConfirmation {
  required string reference_message_id = 1;
  optional string button_id = 2; // if not present, no button is accepted
}

message Availability {
  enum Type {
    NONE = 0;
    AVAILABLE = 1;
    AWAY = 2;
    BUSY = 3;
  }

  required Type type = 1;
}

message Ephemeral {
  required int64 expire_after_millis = 1;
  oneof content {
    Text text = 2;
    ImageAsset image = 3; // deprecated in favour of Asset
    Knock knock = 4;
    Asset asset = 5;
    Location location = 6;
  }
}

message Text {
  required string content = 1;
  // reserved 2; // reserved keyword is not available in older protoc versions
  repeated LinkPreview link_preview = 3;
  repeated Mention mentions = 4;
  optional Quote quote = 5; // if this Text is part of a MessageEdit, this field is ignored
  optional bool expects_read_confirmation = 6 [default = false]; // whether the sender is expecting to receive a read confirmation
  optional LegalHoldStatus legal_hold_status = 7 [default = UNKNOWN]; // whether this message was sent to legal hold
}

message Knock {
  required bool hot_knock = 1 [default = false];
  optional bool expects_read_confirmation = 2 [default = false]; // whether the sender is expecting to receive a read confirmation
  optional LegalHoldStatus legal_hold_status = 3 [default = UNKNOWN]; // whether this message was sent to legal hold
}

message LinkPreview {
  required string url = 1;
  required int32 url_offset = 2; // url offset from beginning of text message

  oneof preview {
    Article article = 3; // deprecated - use meta_data
  }

  optional string permanent_url = 5;
  optional string title = 6;
  optional string summary = 7;
  optional Asset image = 8;

  oneof meta_data {
    Tweet tweet = 9;
  }
}

message Tweet {
  optional string author = 1;
  optional string username = 2;
}

// deprecated - use the additional fields in LinkPreview
message Article {
  required string permanent_url = 1;
  optional string title = 2;
  optional string summary = 3;
  optional Asset image = 4;
}

message Mention {
  required int32 start = 1; // offset from beginning of the message counting in utf16 characters
  required int32 length = 2;
  oneof mention_type {
    // deprecated. Should be set such that old clients always fail when looking
    // up the user. Ideally, this should not be a problem, as a non-federation
    // aware user should never be part of a federated conversation.
    string user_id = 3;
  }
  // only optional to maintain backwards compatibility.
  optional QualifiedUserId qualified_user_id = 4;
}

message LastRead {
  // deprecated. Should be set such that old clients always fail when looking up
  // the conversation.
  required string conversation_id = 1;
  required int64 last_read_timestamp = 2;
  // only optional to maintain backwards compatibility
  optional QualifiedConversationId qualified_conversation_id = 3;
}

message Cleared {
  // deprecated. Should be set such that old clients always fail when looking up
  // the conversation.
  required string conversation_id = 1;
  required int64 cleared_timestamp = 2;
  // only optional to maintain backwards compatibility
  optional QualifiedConversationId qualified_conversation_id = 3;
}

message MessageHide {
  // deprecated. Should be set such that old clients always fail when looking up
  // the conversation.
  required string conversation_id = 1;
  required string message_id = 2;
  // only optional to maintain backwards compatibility
  optional QualifiedConversationId qualified_conversation_id = 3;
}

message MessageDelete {
  required string message_id = 1;
}

message MessageEdit {
  required string replacing_message_id = 1;
  oneof content {
    Text text = 2;
    Composite composite = 3;
    // Reply can also be edited, but the edit will only affect the Text part
  }
}

message Quote {
  required string quoted_message_id = 1;
  optional bytes quoted_message_sha256 = 2;
}

message Confirmation {
  enum Type {
    DELIVERED = 0;
    READ = 1;
  }

  required Type type = 2;
  required string first_message_id = 1;
  repeated string more_message_ids = 3;
}

message Location {
  required float longitude = 1;
  required float latitude = 2;
  optional string name = 3; // location description/name
  optional int32 zoom = 4; // google maps zoom level (check maps api documentation)
  optional bool expects_read_confirmation = 5 [default = false]; // whether the sender is expecting to receive a read confirmation
  optional LegalHoldStatus legal_hold_status = 6 [default = UNKNOWN]; // whether this message was sent to legal hold
}

// deprecated in favour of Asset.Original.ImageMetaData
message ImageAsset {
  required string tag = 1;
  required int32 width = 2;
  required int32 height = 3;
  required int32 original_width = 4;
  required int32 original_height = 5;
  required string mime_type = 6;
  required int32 size = 7;
  optional bytes otr_key = 8;
  optional bytes mac_key = 9; // deprecated - use sha256
  optional bytes mac = 10; // deprecated - use sha256
  optional bytes sha256 = 11; // sha256 of ciphertext
}

message Asset {
  message Original {
    required string mime_type = 1;
    required uint64 size = 2;
    optional string name = 3;
    oneof meta_data {
      ImageMetaData image = 4;
      VideoMetaData video = 5;
      AudioMetaData audio = 6;
    }
    optional string source = 7; // link to source e.g. http://giphy.com/234245
    optional string caption = 8; // caption of the asset, e.g. "dog" for a Giphy "dog" search result
  }

  message Preview {
    required string mime_type = 1;
    required uint64 size = 2;
    optional RemoteData remote = 3;
    oneof meta_data {
      ImageMetaData image = 4;
    }
  }

  message ImageMetaData {
    required int32 width = 1;
    required int32 height = 2;
    optional string tag = 3;
  }

  message VideoMetaData {
    optional int32 width = 1;
    optional int32 height = 2;
    optional uint64 duration_in_millis = 3;
  }

  message AudioMetaData {
    optional uint64 duration_in_millis = 1;
    // repeated float normalized_loudness = 2 [packed=true]; // deprecated - Switched to bytes instead
    optional bytes normalized_loudness = 3; // each byte represent one loudness value as a byte (char) value.
    // e.g. a 100-bytes field here represents 100 loudness values.
    // Values are in chronological order and range from 0 to 255.
  }

  enum NotUploaded {
    CANCELLED = 0;
    FAILED = 1;
  }

  message RemoteData {
    required bytes otr_key = 1;
    required bytes sha256 = 2; // obsolete but required for backward compatibility
    optional string asset_id = 3;
    // optional bytes asset_token = 4; // deprecated - changed type to string
    optional string asset_token = 5;
    optional string asset_domain = 7;
    optional EncryptionAlgorithm encryption = 6;
  }

  optional Original original = 1;
  // optional Preview preview = 2;  // deprecated - preview was completely replaced
  oneof status {
    NotUploaded not_uploaded = 3;
    RemoteData uploaded = 4;
  }
  optional Preview preview = 5;
  optional bool expects_read_confirmation = 6 [default = false]; // whether the sender is expecting to receive a read confirmation
  optional LegalHoldStatus legal_hold_status = 7 [default = UNKNOWN]; // whether this message was sent to legal hold
}

// Actual message is encrypted with AES and sent as additional data
message External {
  required bytes otr_key = 1;
  optional bytes sha256 = 2; // sha256 of ciphertext, obsolete but required for backward compatibility
  optional EncryptionAlgorithm encryption = 3;
}

message Reaction {
  optional string emoji = 1; // some emoji reaction or the empty string to remove previous reaction(s)
  required string message_id = 2;
  optional LegalHoldStatus legal_hold_status = 3 [default = UNKNOWN]; // whether this message was sent to legal hold
}

message Calling {
  required string content = 1;
  optional QualifiedConversationId qualified_conversation_id = 2;
}

message DataTransfer {
  optional TrackingIdentifier trackingIdentifier = 1;
}

message TrackingIdentifier {
  required string identifier = 1;
}

// Enums have to come last because of an unresolved issue with jsdoc
// https://github.com/jsdoc/jsdoc/pull/1686

enum ClientAction {
  RESET_SESSION = 0;
}

enum EncryptionAlgorithm {
  AES_CBC = 0;
  AES_GCM = 1;
}

enum LegalHoldStatus {
  UNKNOWN = 0;
  DISABLED = 1;
  ENABLED = 2;
}
