// Copyright 2018 The Nakama Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * The RPC protocol for the developer console.
 */
syntax = "proto3";

package nakama.console;

import "github.com/heroiclabs/nakama-common/api/api.proto";
import "google/api/annotations.proto";
import "google/protobuf/empty.proto";
import "google/protobuf/timestamp.proto";
import "google/protobuf/wrappers.proto";
import "protoc-gen-swagger/options/annotations.proto";

option go_package = "console";

option (grpc.gateway.protoc_gen_swagger.options.openapiv2_swagger) = {
  info: {
    title: "Nakama console API v2";
    version: "2.0";
    contact: {
      name: "The Nakama Authors & Contributors";
      url: "https://github.com/heroiclabs/nakama";
      email: "hello@heroiclabs.com";
    };
  };
  host: "127.0.0.1:7351";
  external_docs: {
    url: "https://heroiclabs.com/docs";
    description: "Nakama server console documentation";
  }
  schemes: HTTP;
  consumes: "application/json";
  produces: "application/json";
  security_definitions: {
    security: {
      key: "BasicAuth";
      value: {
        type: TYPE_BASIC;
      }
    }
    security: {
      // Made up security so we can apply "Bearer <JWT_TOKEN>"
      key: "BearerJwt";
      value: {};
    }
  }
  // Default security definition.
  security: {
    security_requirement: {
      key: "BearerJwt";
      value: {};
    }
  },
};

/**
 * The developer console RPC protocol service built with GRPC.
 */
service Console {
  // Authenticate a console user with username and password.
  rpc Authenticate (AuthenticateRequest) returns (ConsoleSession) {
    option (google.api.http) = {
      post: "/v2/console/authenticate",
      body: "*"
    };
    option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = {
      security: {
        security_requirement: {};
      };
    };
  }

  // Ban a user.
  rpc BanUser (AccountId) returns (google.protobuf.Empty) {
    option (google.api.http).post = "/v2/console/account/{id}/ban";
  }

  // Delete all information stored for a user account.
  rpc DeleteAccount (AccountDeleteRequest) returns (google.protobuf.Empty) {
    option (google.api.http).delete = "/v2/console/account/{id}";
  }

  // Delete the friend relationship between two users.
  rpc DeleteFriend (DeleteFriendRequest) returns (google.protobuf.Empty) {
    option (google.api.http).delete = "/v2/console/account/{id}/friend/{friend_id}";
  }

  // Remove a user from a group.
  rpc DeleteGroupUser (DeleteGroupUserRequest) returns (google.protobuf.Empty) {
    option (google.api.http).delete = "/v2/console/account/{id}/group/{group_id}";
  }

  // Delete all storage data.
  rpc DeleteStorage (google.protobuf.Empty) returns (google.protobuf.Empty) {
    option (google.api.http).delete = "/v2/console/storage";
  }

  // Delete a storage object.
  rpc DeleteStorageObject (DeleteStorageObjectRequest) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      delete: "/v2/console/storage/{collection}/{key}/{user_id}",
      additional_bindings {
        delete: "/v2/console/storage/{collection}/{key}/{user_id}/{version}"
      }
    };
  }

  // Delete (non-recorded) all user accounts.
  rpc DeleteUsers (google.protobuf.Empty) returns (google.protobuf.Empty) {
    option (google.api.http).delete = "/v2/console/user";
  }

  // Delete a wallet ledger item.
  rpc DeleteWalletLedger (DeleteWalletLedgerRequest) returns (google.protobuf.Empty) {
    option (google.api.http).delete = "/v2/console/account/{id}/wallet/{wallet_id}";
  }

  // Export all information stored about a user account.
  rpc ExportAccount (AccountId) returns (AccountExport) {
    option (google.api.http).get = "/v2/console/account/{id}/export";
  }

  // Get detailed account information for a single user.
  rpc GetAccount (AccountId) returns (Account) {
    option (google.api.http).get = "/v2/console/account/{id}";
  }

  // Get server config and configuration warnings.
  rpc GetConfig (google.protobuf.Empty) returns (Config) {
    option (google.api.http).get = "/v2/console/config";
  }

  // Get a user's list of friend relationships.
  rpc GetFriends (AccountId) returns (nakama.api.FriendList) {
    option (google.api.http).get = "/v2/console/account/{id}/friend";
  }

  // Get a list of groups the user is a member of.
  rpc GetGroups (AccountId) returns (nakama.api.UserGroupList) {
    option (google.api.http).get = "/v2/console/account/{id}/group";
  }

  // Get current status data for all nodes.
  rpc GetStatus (google.protobuf.Empty) returns (StatusList) {
    option (google.api.http).get = "/v2/console/status";
  }

  // Get a storage object.
  rpc GetStorage (nakama.api.ReadStorageObjectId) returns (nakama.api.StorageObject) {
    option (google.api.http).get = "/v2/console/storage/{collection}/{key}/{user_id}";
  }

  // Get a list of the user's wallet transactions.
  rpc GetWalletLedger (AccountId) returns (WalletLedgerList) {
    option (google.api.http).get = "/v2/console/account/{id}/wallet";
  }

  // List (and optionally filter) storage data.
  rpc ListStorage (ListStorageRequest) returns (StorageList) {
    option (google.api.http).get = "/v2/console/storage";
  }

  // List (and optionally filter) users.
  rpc ListUsers (ListUsersRequest) returns (UserList) {
    option (google.api.http).get = "/v2/console/user";
  }

  // Unban a user.
  rpc UnbanUser (AccountId) returns (google.protobuf.Empty) {
    option (google.api.http).post = "/v2/console/account/{id}/unban";
  }

  // Unlink the custom ID from a user account.
  rpc UnlinkCustom (AccountId) returns (google.protobuf.Empty) {
    option (google.api.http).post = "/v2/console/account/{id}/unlink/custom";
  }

  // Unlink the device ID from a user account.
  rpc UnlinkDevice (UnlinkDeviceRequest) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      post: "/v2/console/account/{id}/unlink/device",
      body: "*"
    };
  }

  // Unlink the email from a user account.
  rpc UnlinkEmail (AccountId) returns (google.protobuf.Empty) {
    option (google.api.http).post = "/v2/console/account/{id}/unlink/email";
  }

  // Unlink the Apple ID from a user account.
  rpc UnlinkApple (AccountId) returns (google.protobuf.Empty) {
    option (google.api.http).post = "/v2/console/account/{id}/unlink/apple";
  }

  // Unlink the Facebook ID from a user account.
  rpc UnlinkFacebook (AccountId) returns (google.protobuf.Empty) {
    option (google.api.http).post = "/v2/console/account/{id}/unlink/facebook";
  }

  // Unlink the Facebook Instant Game ID from a user account.
  rpc UnlinkFacebookInstantGame (AccountId) returns (google.protobuf.Empty) {
    option (google.api.http).post = "/v2/console/account/{id}/unlink/facebookinstantgame";
  }

  // Unlink the Game Center ID from a user account.
  rpc UnlinkGameCenter (AccountId) returns (google.protobuf.Empty) {
    option (google.api.http).post = "/v2/console/account/{id}/unlink/gamecenter";
  }

  // Unlink the Google ID from a user account.
  rpc UnlinkGoogle (AccountId) returns (google.protobuf.Empty) {
    option (google.api.http).post = "/v2/console/account/{id}/unlink/google";
  }

  // Unlink the Steam ID from a user account.
  rpc UnlinkSteam (AccountId) returns (google.protobuf.Empty) {
    option (google.api.http).post = "/v2/console/account/{id}/unlink/steam";
  }

  // Update one or more fields on a user account.
  rpc UpdateAccount (UpdateAccountRequest) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      post: "/v2/console/account/{id}",
      body: "*"
    };
  }

  // Write a new storage object or replace an existing one.
  rpc WriteStorageObject (WriteStorageObjectRequest) returns (nakama.api.StorageObjectAck) {
    option (google.api.http) = {
      put: "/v2/console/storage/{collection}/{key}/{user_id}",
      body: "*"
    };
  }
}

// Account information.
message Account {
  // The user's account details.
  nakama.api.Account account = 1;
  // The UNIX time when the account was disabled.
  google.protobuf.Timestamp disable_time = 2;
}

// Delete a user account.
message AccountDeleteRequest {
  // The unique identifier of the user account.
  string id = 1;
  // Record the user deletion - used for GDPR compliance.
  google.protobuf.BoolValue record_deletion = 2;
}

// An export of all information stored for a user account.
message AccountExport {
  // The user's account details.
  nakama.api.Account account = 1;
  // The user's storage.
  repeated nakama.api.StorageObject objects = 2;
  // The user's friends.
  repeated nakama.api.Friend friends = 3;
  // The user's groups.
  repeated nakama.api.Group groups = 4;
  // The user's chat messages.
  repeated nakama.api.ChannelMessage messages = 5;
  // The user's leaderboard records.
  repeated nakama.api.LeaderboardRecord leaderboard_records = 6;
  // The user's notifications.
  repeated nakama.api.Notification notifications = 7;
  // The user's wallet ledger items.
  repeated WalletLedger wallet_ledgers = 8;
}

// The identifier for a user account.
message AccountId {
  // The unique identifier of the user account.
  string id = 1;
}

// Authenticate a console user with username and password.
message AuthenticateRequest {
  // The username of the user.
  string username = 1;
  // The password of the user.
  string password = 2;
}

// The current server configuration and any associated warnings.
message Config {
  // A warning for a configuration field.
  message Warning {
    // The config field this warning is for in a JSON pointer format.
    string field = 1;
    // Warning message text.
    string message = 2;
  }

  // JSON-encoded active server configuration.
  string config = 1;
  // Any warnings about the current config.
  repeated Warning warnings = 2;
  // Server version
  string server_version = 3;
}

// A console user session.
message ConsoleSession {
  // A session token (JWT) for the console user.
  string token = 1;
}

// Delete friend relationship between two users.
message DeleteFriendRequest {
  // The user do delete for.
  string id = 1;
  // User ID of the friend to remove.
  string friend_id = 2;
}

// Remove a user from a group.
message DeleteGroupUserRequest {
  // User to remove.
  string id = 1;
  // ID of the group to remove them from.
  string group_id = 2;
}

// Delete an individual storage object.
message DeleteStorageObjectRequest {
  // Collection.
  string collection = 1;
  // Key.
  string key = 2;
  // Owner user ID.
  string user_id = 3;
  // Version for OCC.
  string version = 4;
}

// Delete a single wallet ledger item.
message DeleteWalletLedgerRequest {
  // User ID to remove wallet ledger item from.
  string id = 1;
  // ID of the wallet ledger item to remove.
  string wallet_id = 2;
}

// List (and optionally filter) storage objects.
message ListStorageRequest {
  // User ID to filter objects for.
  string user_id = 1;
}

// List (and optionally filter) users.
message ListUsersRequest {
  // User ID or username filter.
  string filter = 1;
  // Search only banned users.
  bool banned = 2;
  // Search only recorded deletes.
  bool tombstones = 3;
}

// List of storage objects.
message StorageList {
  // List of storage objects matching list/filter operation.
  repeated nakama.api.StorageObject objects = 1;
  // Approximate total number of storage objects.
  int32 total_count = 2;
}

// Unlink a particular device ID from a user's account.
message UnlinkDeviceRequest {
  // User ID to unlink from.
  string id = 1;
  // Device ID to unlink.
  string device_id = 2;
}

// Update user account information.
message UpdateAccountRequest {
  // User ID to update.
  string id = 1;
  // Username.
  google.protobuf.StringValue username = 2;
  // Display name.
  google.protobuf.StringValue display_name = 3;
  // Metadata.
  google.protobuf.StringValue metadata = 4;
  // Avatar URL.
  google.protobuf.StringValue avatar_url = 5;
  // Langtag.
  google.protobuf.StringValue lang_tag = 6;
  // Location.
  google.protobuf.StringValue location = 7;
  // Timezone.
  google.protobuf.StringValue timezone = 8;
  // Custom ID.
  google.protobuf.StringValue custom_id = 9;
  // Email.
  google.protobuf.StringValue email = 10;
  // Password.
  google.protobuf.StringValue password = 11;
  // Device ID modifications.
  map<string, string> device_ids = 12;
  // Wallet.
  google.protobuf.StringValue wallet = 13;
}

// A list of users.
message UserList {
  // A list of users.
  repeated nakama.api.User users = 1;
  // Approximate total number of users.
  int32 total_count = 2;
}

// List of nodes and their stats.
message StatusList {
  // The status of a Nakama node.
  message Status {
    // Node name.
    string name = 1;
    // Health score.
    int32 health = 2;
    // Currently connected sessions.
    int32 session_count = 3;
    // Currently registered live presences.
    int32 presence_count = 4;
    // Current number of active authoritative matches.
    int32 match_count = 5;
    // Current number of running goroutines.
    int32 goroutine_count = 6;
    // Average response latency in milliseconds.
    double avg_latency_ms = 7;
    // Average number of requests per second.
    double avg_rate_sec = 8;
    // Average input bandwidth usage.
    double avg_input_kbs = 9;
    // Average output bandwidth usage.
    double avg_output_kbs = 10;
  }

  // List of nodes and their stats.
  repeated Status nodes = 1;
}

// An individual update to a user's wallet.
message WalletLedger {
  // The identifier of this wallet change.
  string id = 1;
  // The user ID this wallet ledger item belongs to.
  string user_id = 2;
  // The changeset.
  string changeset = 3;
  // Any associated metadata.
  string metadata = 4;
  // The UNIX time when the wallet ledger item was created.
  google.protobuf.Timestamp create_time = 5;
  // The UNIX time when the wallet ledger item was updated.
  google.protobuf.Timestamp update_time = 6;
}

// List of wallet ledger items for a particular user.
message WalletLedgerList {
  // A list of wallet ledger items.
  repeated WalletLedger items = 1;
}

// Write a new storage object or update an existing one.
message WriteStorageObjectRequest {
  // Collection.
  string collection = 1;
  // Key.
  string key = 2;
  // Owner user ID.
  string user_id = 3;
  // Value.
  string value = 4;
  // Version for OCC.
  string version = 5;
  // Read permission value.
  google.protobuf.Int32Value permission_read = 6;
  // Write permission value.
  google.protobuf.Int32Value permission_write = 7;
}
