// 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 Nakama server RPC protocol for games and apps.
 */
syntax = "proto3";

package nakama.api;

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

option go_package = "github.com/heroiclabs/nakama/v3/apigrpc";

option java_multiple_files = true;
option java_outer_classname = "NakamaApiGrpc";
option java_package = "com.heroiclabs.nakama.api";

option csharp_namespace = "Nakama.Protobuf";

option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
  info: {
    title: "Nakama 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:7350";
  external_docs: {
    url: "https://heroiclabs.com/docs";
    description: "Nakama server 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: {
        type: TYPE_INVALID;
      }
    }
    security: {
      key: "HttpKeyAuth";
      value: {
        type: TYPE_API_KEY;
        in: IN_HEADER;
        name: "http_key";
      }
    }
  }
  // Default security definition.
  security: {
    security_requirement: {
      key: "BearerJwt";
      value: {};
    }
  }
};

/**
 * The Nakama RPC protocol service built with GRPC.
 */
service Nakama {
  // Add friends by ID or username to a user's account.
  rpc AddFriends (api.AddFriendsRequest) returns (google.protobuf.Empty) {
    option (google.api.http).post = "/v2/friend";
  }

  // Add users to a group.
  rpc AddGroupUsers (api.AddGroupUsersRequest) returns (google.protobuf.Empty) {
    option (google.api.http).post = "/v2/group/{group_id}/add";
  }

  // Refresh a user's session using a refresh token retrieved from a previous authentication request.
  rpc SessionRefresh (api.SessionRefreshRequest) returns (api.Session) {
    option (google.api.http) = {
      post: "/v2/account/session/refresh",
      body: "*"
    };
    option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
      security: {
        security_requirement: {
          key: "BasicAuth";
          value: {};
        }
      }
    };
  }

  // Log out a session, invalidate a refresh token, or log out all sessions/refresh tokens for a user.
  rpc SessionLogout (api.SessionLogoutRequest) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      post: "/v2/session/logout",
      body: "*"
    };
  }

  // Authenticate a user with an Apple ID against the server.
  rpc AuthenticateApple (api.AuthenticateAppleRequest) returns (api.Session) {
    option (google.api.http) = {
      post: "/v2/account/authenticate/apple",
      body: "account"
    };
    option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
      security: {
        security_requirement: {
          key: "BasicAuth";
          value: {};
        }
      }
    };
  }

  // Authenticate a user with a custom id against the server.
  rpc AuthenticateCustom (api.AuthenticateCustomRequest) returns (api.Session) {
    option (google.api.http) = {
      post: "/v2/account/authenticate/custom",
      body: "account"
    };
    option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
      security: {
        security_requirement: {
          key: "BasicAuth";
          value: {};
        }
      }
    };
  }

  // Authenticate a user with a device id against the server.
  rpc AuthenticateDevice (api.AuthenticateDeviceRequest) returns (api.Session) {
    option (google.api.http) = {
      post: "/v2/account/authenticate/device",
      body: "account"
    };
    option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
      security: {
        security_requirement: {
          key: "BasicAuth";
          value: {};
        }
      }
    };
  }

  // Authenticate a user with an email+password against the server.
  rpc AuthenticateEmail (api.AuthenticateEmailRequest) returns (api.Session) {
    option (google.api.http) = {
      post: "/v2/account/authenticate/email",
      body: "account"
    };
    option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
      security: {
        security_requirement: {
          key: "BasicAuth";
          value: {};
        }
      }
    };
  }

  // Authenticate a user with a Facebook OAuth token against the server.
  rpc AuthenticateFacebook (api.AuthenticateFacebookRequest) returns (api.Session) {
    option (google.api.http) = {
      post: "/v2/account/authenticate/facebook",
      body: "account"
    };
    option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
      security: {
        security_requirement: {
          key: "BasicAuth";
          value: {};
        }
      }
    };
  }

  // Authenticate a user with a Facebook Instant Game token against the server.
  rpc AuthenticateFacebookInstantGame (api.AuthenticateFacebookInstantGameRequest) returns (api.Session) {
    option (google.api.http) = {
      post: "/v2/account/authenticate/facebookinstantgame",
      body: "account"
    };
    option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
      security: {
        security_requirement: {
          key: "BasicAuth";
          value: {};
        }
      }
    };
  }

  // Authenticate a user with Apple's GameCenter against the server.
  rpc AuthenticateGameCenter (api.AuthenticateGameCenterRequest) returns (api.Session) {
    option (google.api.http) = {
      post: "/v2/account/authenticate/gamecenter",
      body: "account"
    };
    option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
      security: {
        security_requirement: {
          key: "BasicAuth";
          value: {};
        }
      }
    };
  }

  // Authenticate a user with Google against the server.
  rpc AuthenticateGoogle (api.AuthenticateGoogleRequest) returns (api.Session) {
    option (google.api.http) = {
      post: "/v2/account/authenticate/google",
      body: "account"
    };
    option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
      security: {
        security_requirement: {
          key: "BasicAuth";
          value: {};
        }
      }
    };
  }

  // Authenticate a user with Steam against the server.
  rpc AuthenticateSteam (api.AuthenticateSteamRequest) returns (api.Session) {
    option (google.api.http) = {
      post: "/v2/account/authenticate/steam",
      body: "account"
    };
    option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
      security: {
        security_requirement: {
          key: "BasicAuth";
          value: {};
        }
      }
    };
  }

  // Ban a set of users from a group.
  rpc BanGroupUsers (api.BanGroupUsersRequest) returns (google.protobuf.Empty) {
    option (google.api.http).post = "/v2/group/{group_id}/ban";
  }

  // Block one or more users by ID or username.
  rpc BlockFriends (api.BlockFriendsRequest) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      post: "/v2/friend/block"
    };
  }

  // Create a new group with the current user as the owner.
  rpc CreateGroup (api.CreateGroupRequest) returns (api.Group) {
    option (google.api.http) = {
      post: "/v2/group",
      body: "*"
    };
  }

  // Delete the current user's account.
  rpc DeleteAccount (google.protobuf.Empty) returns (google.protobuf.Empty) {
    option (google.api.http).delete = "/v2/account";
  }

  // Delete one or more users by ID or username.
  rpc DeleteFriends (api.DeleteFriendsRequest) returns (google.protobuf.Empty) {
    option (google.api.http).delete = "/v2/friend";
  }

  // Delete a group by ID.
  rpc DeleteGroup (api.DeleteGroupRequest) returns (google.protobuf.Empty) {
    option (google.api.http).delete = "/v2/group/{group_id}";
  }

  // Delete a leaderboard record.
  rpc DeleteLeaderboardRecord (api.DeleteLeaderboardRecordRequest) returns (google.protobuf.Empty) {
    option (google.api.http).delete = "/v2/leaderboard/{leaderboard_id}";
  }

  // Delete one or more notifications for the current user.
  rpc DeleteNotifications (api.DeleteNotificationsRequest) returns (google.protobuf.Empty) {
    option (google.api.http).delete = "/v2/notification";
  }

  // Delete a tournament record.
  rpc DeleteTournamentRecord (api.DeleteTournamentRecordRequest) returns (google.protobuf.Empty) {
    option (google.api.http).delete = "/v2/tournament/{tournament_id}";
  }

  // Delete one or more objects by ID or username.
  rpc DeleteStorageObjects (api.DeleteStorageObjectsRequest) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      put: "/v2/storage/delete",
      body: "*"
    };
  }

  // Submit an event for processing in the server's registered runtime custom events handler.
  rpc Event (api.Event) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      post: "/v2/event",
      body: "*"
    };
  }

  // Fetch the current user's account.
  rpc GetAccount (google.protobuf.Empty) returns (api.Account) {
    option (google.api.http).get = "/v2/account";
  }

  // Fetch zero or more users by ID and/or username.
  rpc GetUsers (api.GetUsersRequest) returns (api.Users) {
    option (google.api.http).get = "/v2/user";
  }

  // Get subscription by product id.
  rpc GetSubscription (api.GetSubscriptionRequest) returns (api.ValidatedSubscription) {
    option (google.api.http).get = "/v2/iap/subscription/{product_id}";
  }

  // A healthcheck which load balancers can use to check the service.
  rpc Healthcheck (google.protobuf.Empty) returns (google.protobuf.Empty) {
    option (google.api.http).get = "/healthcheck";
  }

  // Import Facebook friends and add them to a user's account.
  rpc ImportFacebookFriends (api.ImportFacebookFriendsRequest) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      post: "/v2/friend/facebook",
      body: "account"
    };
  }

  // Import Steam friends and add them to a user's account.
  rpc ImportSteamFriends (api.ImportSteamFriendsRequest) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      post: "/v2/friend/steam",
      body: "account"
    };
  }

  // Immediately join an open group, or request to join a closed one.
  rpc JoinGroup (api.JoinGroupRequest) returns (google.protobuf.Empty) {
    option (google.api.http).post = "/v2/group/{group_id}/join";
  }

  // Attempt to join an open and running tournament.
  rpc JoinTournament (api.JoinTournamentRequest) returns (google.protobuf.Empty) {
    option (google.api.http).post = "/v2/tournament/{tournament_id}/join";
  }

  // Kick a set of users from a group.
  rpc KickGroupUsers (api.KickGroupUsersRequest) returns (google.protobuf.Empty) {
    option (google.api.http).post = "/v2/group/{group_id}/kick";
  }

  // Leave a group the user is a member of.
  rpc LeaveGroup (api.LeaveGroupRequest) returns (google.protobuf.Empty) {
    option (google.api.http).post = "/v2/group/{group_id}/leave";
  }

  // Add an Apple ID to the social profiles on the current user's account.
  rpc LinkApple (api.AccountApple) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      post: "/v2/account/link/apple",
      body: "*"
    };
  }

  // Add a custom ID to the social profiles on the current user's account.
  rpc LinkCustom (api.AccountCustom) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      post: "/v2/account/link/custom",
      body: "*"
    };
  }

  // Add a device ID to the social profiles on the current user's account.
  rpc LinkDevice (api.AccountDevice) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      post: "/v2/account/link/device",
      body: "*"
    };
  }

  // Add an email+password to the social profiles on the current user's account.
  rpc LinkEmail (api.AccountEmail) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      post: "/v2/account/link/email",
      body: "*"
    };
  }

  // Add Facebook to the social profiles on the current user's account.
  rpc LinkFacebook (api.LinkFacebookRequest) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      post: "/v2/account/link/facebook",
      body: "account"
    };
  }

  // Add Facebook Instant Game to the social profiles on the current user's account.
  rpc LinkFacebookInstantGame (api.AccountFacebookInstantGame) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      post: "/v2/account/link/facebookinstantgame",
      body: "*"
    };
  }

  // Add Apple's GameCenter to the social profiles on the current user's account.
  rpc LinkGameCenter (api.AccountGameCenter) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      post: "/v2/account/link/gamecenter",
      body: "*"
    };
  }

  // Add Google to the social profiles on the current user's account.
  rpc LinkGoogle (api.AccountGoogle) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      post: "/v2/account/link/google",
      body: "*"
    };
  }

  // Add Steam to the social profiles on the current user's account.
  rpc LinkSteam (api.LinkSteamRequest) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      post: "/v2/account/link/steam",
      body: "*"
    };
  }

  // List a channel's message history.
  rpc ListChannelMessages (api.ListChannelMessagesRequest) returns (api.ChannelMessageList) {
    option (google.api.http).get = "/v2/channel/{channel_id}";
  }

  // List all friends for the current user.
  rpc ListFriends (api.ListFriendsRequest) returns (api.FriendList) {
    option (google.api.http).get = "/v2/friend";
  }

  // List groups based on given filters.
  rpc ListGroups (api.ListGroupsRequest) returns (api.GroupList) {
    option (google.api.http).get = "/v2/group";
  }

  // List all users that are part of a group.
  rpc ListGroupUsers (api.ListGroupUsersRequest) returns (api.GroupUserList) {
    option (google.api.http).get = "/v2/group/{group_id}/user";
  }

  // List leaderboard records.
  rpc ListLeaderboardRecords (api.ListLeaderboardRecordsRequest) returns (api.LeaderboardRecordList) {
    option (google.api.http).get = "/v2/leaderboard/{leaderboard_id}";
  }

  // List leaderboard records that belong to a user.
  rpc ListLeaderboardRecordsAroundOwner (api.ListLeaderboardRecordsAroundOwnerRequest) returns (api.LeaderboardRecordList) {
    option (google.api.http).get = "/v2/leaderboard/{leaderboard_id}/owner/{owner_id}";
  }

  // Fetch list of running matches.
  rpc ListMatches (api.ListMatchesRequest) returns (api.MatchList) {
    option (google.api.http).get = "/v2/match";
  }

  // Fetch list of notifications.
  rpc ListNotifications (api.ListNotificationsRequest) returns (api.NotificationList) {
    option (google.api.http).get = "/v2/notification";
  }

  // List publicly readable storage objects in a given collection.
  rpc ListStorageObjects (api.ListStorageObjectsRequest) returns (api.StorageObjectList) {
    option (google.api.http) = {
      get: "/v2/storage/{collection}",
      additional_bindings {
        get: "/v2/storage/{collection}/{user_id}"
      }
    };
  }

  // List user's subscriptions.
  rpc ListSubscriptions (api.ListSubscriptionsRequest) returns (api.SubscriptionList) {
    option (google.api.http) = {
      post: "/v2/iap/subscription",
      body: "*"
    };
  }

  // List current or upcoming tournaments.
  rpc ListTournaments (api.ListTournamentsRequest) returns (api.TournamentList) {
    option (google.api.http).get = "/v2/tournament";
  }

  // List tournament records.
  rpc ListTournamentRecords (api.ListTournamentRecordsRequest) returns (api.TournamentRecordList) {
    option (google.api.http).get = "/v2/tournament/{tournament_id}";
  }

  // List tournament records for a given owner.
  rpc ListTournamentRecordsAroundOwner (api.ListTournamentRecordsAroundOwnerRequest) returns (api.TournamentRecordList) {
    option (google.api.http).get = "/v2/tournament/{tournament_id}/owner/{owner_id}";
  }

  // List groups the current user belongs to.
  rpc ListUserGroups (api.ListUserGroupsRequest) returns (api.UserGroupList) {
    option (google.api.http).get = "/v2/user/{user_id}/group";
  }

  // Promote a set of users in a group to the next role up.
  rpc PromoteGroupUsers (api.PromoteGroupUsersRequest) returns (google.protobuf.Empty) {
    option (google.api.http).post = "/v2/group/{group_id}/promote";
  }

  // Demote a set of users in a group to the next role down.
  rpc DemoteGroupUsers (api.DemoteGroupUsersRequest) returns (google.protobuf.Empty) {
    option (google.api.http).post = "/v2/group/{group_id}/demote";
  }

  // Get storage objects.
  rpc ReadStorageObjects (api.ReadStorageObjectsRequest) returns (api.StorageObjects) {
    option (google.api.http) = {
      post: "/v2/storage",
      body: "*"
    };
  }

  // Execute a Lua function on the server.
  rpc RpcFunc (api.Rpc) returns (api.Rpc) {
    option (google.api.http) = {
      post: "/v2/rpc/{id}",
      body: "payload",
      additional_bindings {
        get: "/v2/rpc/{id}"
      }
    };
    option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
      // Either HTTP key in query param or Bearer authentication.
      security: {
        security_requirement: {
          key: "HttpKeyAuth";
          value: {};
        }
        security_requirement: {
          key: "BearerJwt";
          value: {};
        }
      }
    };
  }

  // Remove the Apple ID from the social profiles on the current user's account.
  rpc UnlinkApple (api.AccountApple) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      post: "/v2/account/unlink/apple",
      body: "*"
    };
  }

  // Remove the custom ID from the social profiles on the current user's account.
  rpc UnlinkCustom (api.AccountCustom) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      post: "/v2/account/unlink/custom",
      body: "*"
    };
  }

  // Remove the device ID from the social profiles on the current user's account.
  rpc UnlinkDevice (api.AccountDevice) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      post: "/v2/account/unlink/device",
      body: "*"
    };
  }

  // Remove the email+password from the social profiles on the current user's account.
  rpc UnlinkEmail (api.AccountEmail) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      post: "/v2/account/unlink/email",
      body: "*"
    };
  }

  // Remove Facebook from the social profiles on the current user's account.
  rpc UnlinkFacebook (api.AccountFacebook) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      post: "/v2/account/unlink/facebook",
      body: "*"
    };
  }

  // Remove Facebook Instant Game profile from the social profiles on the current user's account.
  rpc UnlinkFacebookInstantGame (api.AccountFacebookInstantGame) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      post: "/v2/account/unlink/facebookinstantgame",
      body: "*"
    };
  }

  // Remove Apple's GameCenter from the social profiles on the current user's account.
  rpc UnlinkGameCenter (api.AccountGameCenter) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      post: "/v2/account/unlink/gamecenter",
      body: "*"
    };
  }

  // Remove Google from the social profiles on the current user's account.
  rpc UnlinkGoogle (api.AccountGoogle) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      post: "/v2/account/unlink/google",
      body: "*"
    };
  }

  // Remove Steam from the social profiles on the current user's account.
  rpc UnlinkSteam (api.AccountSteam) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      post: "/v2/account/unlink/steam",
      body: "*"
    };
  }

  // Update fields in the current user's account.
  rpc UpdateAccount (api.UpdateAccountRequest) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      put: "/v2/account",
      body: "*"
    };
  }

  // Update fields in a given group.
  rpc UpdateGroup (api.UpdateGroupRequest) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      put: "/v2/group/{group_id}",
      body: "*"
    };
  }

  // Validate Apple IAP Receipt
  rpc ValidatePurchaseApple (api.ValidatePurchaseAppleRequest) returns (api.ValidatePurchaseResponse) {
    option (google.api.http) = {
      post: "/v2/iap/purchase/apple",
      body: "*"
    };
  }

  // Validate Apple Subscription Receipt
  rpc ValidateSubscriptionApple (api.ValidateSubscriptionAppleRequest) returns (api.ValidateSubscriptionResponse) {
    option (google.api.http) = {
      post: "/v2/iap/subscription/apple",
      body: "*"
    };
  }

  // Validate Google IAP Receipt
  rpc ValidatePurchaseGoogle (api.ValidatePurchaseGoogleRequest) returns (api.ValidatePurchaseResponse) {
    option (google.api.http) = {
      post: "/v2/iap/purchase/google",
      body: "*"
    };
  }

  // Validate Google Subscription Receipt
  rpc ValidateSubscriptionGoogle (api.ValidateSubscriptionGoogleRequest) returns (api.ValidateSubscriptionResponse) {
    option (google.api.http) = {
      post: "/v2/iap/subscription/google",
      body: "*"
    };
  }

  // Validate Huawei IAP Receipt
  rpc ValidatePurchaseHuawei (api.ValidatePurchaseHuaweiRequest) returns (api.ValidatePurchaseResponse) {
    option (google.api.http) = {
      post: "/v2/iap/purchase/huawei",
      body: "*"
    };
  }

  // Write a record to a leaderboard.
  rpc WriteLeaderboardRecord (api.WriteLeaderboardRecordRequest) returns (api.LeaderboardRecord) {
    option (google.api.http) = {
      post: "/v2/leaderboard/{leaderboard_id}",
      body: "record"
    };
  }

  // Write objects into the storage engine.
  rpc WriteStorageObjects (api.WriteStorageObjectsRequest) returns (api.StorageObjectAcks) {
    option (google.api.http) = {
      put: "/v2/storage",
      body: "*"
    };
  }

  // Write a record to a tournament.
  rpc WriteTournamentRecord (api.WriteTournamentRecordRequest) returns (api.LeaderboardRecord) {
    option (google.api.http) = {
      put: "/v2/tournament/{tournament_id}",
      body: "record",
      additional_bindings {
        post: "/v2/tournament/{tournament_id}",
        body: "record",
      }
    };
  }
}
