syntax = "proto3";

package hyapp.game.v1;

option go_package = "hyapp.local/api/proto/game/v1;gamev1";

// RequestMeta 是 game-service 内部 RPC 的最小追踪和租户上下文。
message RequestMeta {
  string request_id = 1;
  string caller = 2;
  string gateway_node_id = 3;
  int64 actor_user_id = 4;
  int64 sent_at_ms = 5;
  string app_code = 6;
}

message GamePlatform {
  string app_code = 1;
  string platform_code = 2;
  string platform_name = 3;
  string status = 4;
  string api_base_url = 5;
  int32 sort_order = 6;
  int64 created_at_ms = 7;
  int64 updated_at_ms = 8;
  string adapter_type = 9;
  // callback_secret is visible to admin platform configuration pages and writable for key rotation.
  string callback_secret = 10;
  bool callback_secret_set = 11;
  repeated string callback_ip_whitelist = 12;
  string adapter_config_json = 13;
}

message GameCatalogItem {
  string app_code = 1;
  string game_id = 2;
  string platform_code = 3;
  string provider_game_id = 4;
  string game_name = 5;
  string category = 6;
  string icon_url = 7;
  string cover_url = 8;
  string launch_mode = 9;
  string orientation = 10;
  int64 min_coin = 11;
  string status = 12;
  int32 sort_order = 13;
  repeated string tags = 14;
  int64 created_at_ms = 15;
  int64 updated_at_ms = 16;
  int32 safe_height = 17;
  // whitelist_enabled 关闭时保持历史全量可见语义；开启后只向 game_user_whitelist 中的用户展示并允许启动。
  bool whitelist_enabled = 18;
}

message AppGame {
  string game_id = 1;
  string platform_code = 2;
  string name_key = 3;
  string name = 4;
  string icon_url = 5;
  string cover_url = 6;
  string category = 7;
  string launch_mode = 8;
  string orientation = 9;
  int64 min_coin = 10;
  bool enabled = 11;
  bool maintenance = 12;
  int32 sort_order = 13;
  int32 safe_height = 14;
}

message ListGamesRequest {
  RequestMeta meta = 1;
  int64 user_id = 2;
  string scene = 3;
  string room_id = 4;
  int64 region_id = 5;
  string language = 6;
  string client_platform = 7;
}

message ListGamesResponse {
  repeated AppGame games = 1;
  int64 server_time_ms = 2;
}

message ListRecentGamesRequest {
  RequestMeta meta = 1;
  int64 user_id = 2;
  string scene = 3;
  string room_id = 4;
  int64 region_id = 5;
  string language = 6;
  string client_platform = 7;
  int32 page_size = 8;
}

message ListExploreWinnersRequest {
  RequestMeta meta = 1;
  int32 page_size = 2;
}

message ExploreWinner {
  string win_id = 1;
  string game_code = 2;
  string game_id = 3;
  int64 user_id = 4;
  string display_name = 5;
  string avatar_url = 6;
  int64 coin_amount = 7;
  int64 won_at_ms = 8;
}

message ListExploreWinnersResponse {
  repeated ExploreWinner winners = 1;
  int64 server_time_ms = 2;
}

message GetBridgeScriptRequest {
  RequestMeta meta = 1;
}

message GameBridgeScriptConfig {
  string bridge_script_url = 1;
  string bridge_script_version = 2;
  string bridge_script_sha256 = 3;
}

message GetBridgeScriptResponse {
  GameBridgeScriptConfig config = 1;
  int64 server_time_ms = 2;
}

message LaunchGameRequest {
  RequestMeta meta = 1;
  int64 user_id = 2;
  string display_user_id = 3;
  string game_id = 4;
  string scene = 5;
  string room_id = 6;
  // access_token is the same bearer token used by the App request.
  // Provider adapters pass it through as the game token instead of minting a separate game token.
  string access_token = 7;
  // country_id 由 gateway 从当前用户资料注入，供 provider 回调订单按国家统计。
  int64 country_id = 8;
  // provider_token 是 gateway 签发的短期厂商令牌；仅需要限长令牌的 adapter 使用。
  string provider_token = 9;
}

message LaunchGameResponse {
  string session_id = 1;
  string launch_url = 2;
  int64 expires_at_ms = 3;
  string orientation = 4;
  int64 server_time_ms = 5;
  int32 safe_height = 6;
}

message DiceParticipant {
  int64 user_id = 1;
  int32 seat_no = 2;
  string status = 3;
  int64 stake_coin = 4;
  repeated int32 dice_points = 5;
  string result = 6;
  int64 payout_coin = 7;
  int64 balance_after = 8;
  int64 joined_at_ms = 9;
  int64 updated_at_ms = 10;
  string participant_type = 11;
  bool is_robot = 12;
  string rps_gesture = 13;
}

message DiceMatch {
  string app_code = 1;
  string match_id = 2;
  string game_id = 3;
  string room_id = 4;
  int64 region_id = 5;
  int32 min_players = 6;
  int32 max_players = 7;
  int32 current_players = 8;
  int64 stake_coin = 9;
  int32 round_no = 10;
  string status = 11;
  string result = 12;
  repeated DiceParticipant participants = 13;
  int64 join_deadline_ms = 14;
  int64 created_at_ms = 15;
  int64 updated_at_ms = 16;
  int64 settled_at_ms = 17;
  string phase = 18;
  int64 phase_deadline_ms = 19;
  int32 fee_bps = 20;
  int32 pool_bps = 21;
  string match_mode = 22;
  string forced_result = 23;
  int64 ready_at_ms = 24;
  int64 canceled_at_ms = 25;
  int64 pool_delta_coin = 26;
  // country_id 是创建局用户的国家快照，用于局级订单和统计事件按国家归因。
  int64 country_id = 27;
}

message DiceStakeOption {
  int64 stake_coin = 1;
  bool enabled = 2;
  int32 sort_order = 3;
}

message DiceConfig {
  reserved 14;

  string app_code = 1;
  string game_id = 2;
  string status = 3;
  repeated DiceStakeOption stake_options = 4;
  int32 fee_bps = 5;
  int32 pool_bps = 6;
  int32 min_players = 7;
  int32 max_players = 8;
  bool robot_enabled = 9;
  int64 robot_match_wait_ms = 10;
  int64 pool_balance_coin = 11;
  int64 created_at_ms = 12;
  int64 updated_at_ms = 13;
}

message GetDiceConfigRequest {
  RequestMeta meta = 1;
  string game_id = 2;
}

message DiceConfigResponse {
  DiceConfig config = 1;
  int64 server_time_ms = 2;
}

message RoomRPSStakeGift {
  int64 gift_id = 1;
  string gift_name = 2;
  string gift_icon_url = 3;
  int64 gift_price_coin = 4;
  bool enabled = 5;
  int32 sort_order = 6;
  string gift_id_text = 7;
  string gift_animation_url = 8;
}

message RoomRPSConfig {
  string app_code = 1;
  string game_id = 2;
  string status = 3;
  int64 challenge_timeout_ms = 4;
  int64 reveal_countdown_ms = 5;
  repeated RoomRPSStakeGift stake_gifts = 6;
  int64 created_at_ms = 7;
  int64 updated_at_ms = 8;
}

message RoomRPSPlayer {
  int64 user_id = 1;
  string gesture = 2;
  string result = 3;
  int64 balance_after = 4;
  int64 joined_at_ms = 5;
}

message RoomRPSChallenge {
  string app_code = 1;
  string challenge_id = 2;
  string room_id = 3;
  int64 region_id = 4;
  string status = 5;
  int64 stake_gift_id = 6;
  int64 stake_coin = 7;
  RoomRPSPlayer initiator = 8;
  RoomRPSPlayer challenger = 9;
  int64 winner_user_id = 10;
  string settlement_status = 11;
  string failure_reason = 12;
  int64 timeout_at_ms = 13;
  int64 reveal_at_ms = 14;
  int64 created_at_ms = 15;
  int64 matched_at_ms = 16;
  int64 settled_at_ms = 17;
  int64 updated_at_ms = 18;
  string stake_gift_id_text = 19;
}

message GetRoomRPSConfigRequest {
  RequestMeta meta = 1;
}

message RoomRPSConfigResponse {
  RoomRPSConfig config = 1;
  int64 server_time_ms = 2;
}

message CreateRoomRPSChallengeRequest {
  RequestMeta meta = 1;
  int64 user_id = 2;
  string room_id = 3;
  int64 region_id = 4;
  int64 gift_id = 5;
  string gesture = 6;
  string gift_id_text = 7;
}

message AcceptRoomRPSChallengeRequest {
  RequestMeta meta = 1;
  int64 user_id = 2;
  string challenge_id = 3;
  string gesture = 4;
}

message GetRoomRPSChallengeRequest {
  RequestMeta meta = 1;
  int64 user_id = 2;
  string challenge_id = 3;
}

message ListRoomRPSChallengesRequest {
  RequestMeta meta = 1;
  int64 user_id = 2;
  string room_id = 3;
  string status = 4;
  int64 initiator_user_id = 5;
  int64 challenger_user_id = 6;
  int64 start_time_ms = 7;
  int64 end_time_ms = 8;
  int32 page_size = 9;
  string cursor = 10;
}

message RoomRPSChallengeResponse {
  RoomRPSChallenge challenge = 1;
  int64 server_time_ms = 2;
}

message ListRoomRPSChallengesResponse {
  repeated RoomRPSChallenge challenges = 1;
  string next_cursor = 2;
  int32 page_size = 3;
  int64 server_time_ms = 4;
}

message UpdateRoomRPSConfigRequest {
  RequestMeta meta = 1;
  RoomRPSConfig config = 2;
}

message RetryRoomRPSSettlementRequest {
  RequestMeta meta = 1;
  string challenge_id = 2;
}

message ExpireRoomRPSChallengeRequest {
  RequestMeta meta = 1;
  string challenge_id = 2;
}

message CreateDiceMatchRequest {
  RequestMeta meta = 1;
  int64 user_id = 2;
  string game_id = 3;
  string room_id = 4;
  int64 region_id = 5;
  int64 stake_coin = 6;
  int32 min_players = 7;
  int32 max_players = 8;
  string rps_gesture = 9;
  // country_id 由 gateway 从当前用户资料注入，客户端不能直接决定统计国家。
  int64 country_id = 10;
}

message JoinDiceMatchRequest {
  RequestMeta meta = 1;
  int64 user_id = 2;
  string match_id = 3;
  string game_id = 4;
  string rps_gesture = 5;
}

message GetDiceMatchRequest {
  RequestMeta meta = 1;
  int64 user_id = 2;
  string match_id = 3;
  string game_id = 4;
}

message RollDiceMatchRequest {
  RequestMeta meta = 1;
  int64 user_id = 2;
  string match_id = 3;
  string game_id = 4;
  string rps_gesture = 5;
}

message MatchDiceRequest {
  RequestMeta meta = 1;
  int64 user_id = 2;
  string game_id = 3;
  string room_id = 4;
  int64 region_id = 5;
  int64 stake_coin = 6;
  string rps_gesture = 7;
  // country_id 由 gateway 从当前用户资料注入，客户端不能直接决定统计国家。
  int64 country_id = 8;
}

message CancelDiceMatchRequest {
  RequestMeta meta = 1;
  int64 user_id = 2;
  string match_id = 3;
  string game_id = 4;
}

message DiceMatchResponse {
  DiceMatch match = 1;
  int64 server_time_ms = 2;
}

message CallbackRequest {
  RequestMeta meta = 1;
  string platform_code = 2;
  string operation = 3;
  bytes raw_body = 4;
  map<string, string> headers = 5;
  map<string, string> query = 6;
  string remote_addr = 7;
}

message CallbackResponse {
  bytes raw_body = 1;
  string content_type = 2;
}

message CronBatchRequest {
  RequestMeta meta = 1;
  string run_id = 2;
  string worker_id = 3;
  int32 batch_size = 4;
  int64 lock_ttl_ms = 5;
}

message CronBatchResponse {
  int32 claimed_count = 1;
  int32 processed_count = 2;
  int32 success_count = 3;
  int32 failure_count = 4;
  bool has_more = 5;
}

message ListPlatformsRequest {
  RequestMeta meta = 1;
  string status = 2;
}

message ListPlatformsResponse {
  repeated GamePlatform platforms = 1;
  int64 server_time_ms = 2;
}

message UpsertPlatformRequest {
  RequestMeta meta = 1;
  GamePlatform platform = 2;
}

message PlatformResponse {
  GamePlatform platform = 1;
  int64 server_time_ms = 2;
}

message ListCatalogRequest {
  RequestMeta meta = 1;
  string platform_code = 2;
  string status = 3;
  int32 page_size = 4;
  string cursor = 5;
}

message ListCatalogResponse {
  repeated GameCatalogItem games = 1;
  string next_cursor = 2;
  int64 server_time_ms = 3;
}

message UpsertCatalogRequest {
  RequestMeta meta = 1;
  GameCatalogItem game = 2;
}

message CatalogResponse {
  GameCatalogItem game = 1;
  int64 server_time_ms = 2;
}

message SetGameStatusRequest {
  RequestMeta meta = 1;
  string game_id = 2;
  string status = 3;
}

message DeleteCatalogRequest {
  RequestMeta meta = 1;
  string game_id = 2;
}

message DeleteCatalogResponse {
  int64 server_time_ms = 1;
}

message ListSelfGamesRequest {
  RequestMeta meta = 1;
}

message ListSelfGamesResponse {
  repeated DiceConfig games = 1;
  int64 server_time_ms = 2;
}

message UpdateDiceConfigRequest {
  RequestMeta meta = 1;
  DiceConfig config = 2;
}

message SelfGameNewUserPolicy {
  string app_code = 1;
  string game_id = 2;
  bool enabled = 3;
  int32 protection_rounds = 4;
  int32 protection_hours = 5;
  int64 max_stake_coin = 6;
  int64 lifetime_subsidy_quota_coin = 7;
  int64 day1_subsidy_quota_coin = 8;
  int64 single_round_subsidy_cap_coin = 9;
  string strategy_level = 10;
  bool lose_streak_protection_enabled = 11;
  int32 lose_streak_trigger = 12;
  int64 created_at_ms = 13;
  int64 updated_at_ms = 14;
  int32 normal_phase_target_win_rate_percent = 15;
  bool black_pool_robot_force_win_enabled = 16;
}

message GetSelfGameNewUserPolicyRequest {
  RequestMeta meta = 1;
  string game_id = 2;
}

message UpdateSelfGameNewUserPolicyRequest {
  RequestMeta meta = 1;
  SelfGameNewUserPolicy policy = 2;
}

message SelfGameNewUserPolicyResponse {
  SelfGameNewUserPolicy policy = 1;
  int64 server_time_ms = 2;
}

message SelfGameStakePool {
  string app_code = 1;
  string game_id = 2;
  int64 stake_coin = 3;
  int64 balance_coin = 4;
  int64 reserved_coin = 5;
  int64 available_coin = 6;
  int64 target_balance_coin = 7;
  int64 safe_balance_coin = 8;
  int64 warning_balance_coin = 9;
  int64 danger_balance_coin = 10;
  string status = 11;
  string pool_level = 12;
  int64 required_pool_coin = 13;
  int64 human_win_capacity = 14;
  bool bot_match_enabled = 15;
  string black_reason = 16;
  int64 created_at_ms = 17;
  int64 updated_at_ms = 18;
}

message ListSelfGameStakePoolsRequest {
  RequestMeta meta = 1;
  string game_id = 2;
}

message UpdateSelfGameStakePoolRequest {
  RequestMeta meta = 1;
  SelfGameStakePool pool = 2;
}

message SelfGameStakePoolResponse {
  SelfGameStakePool pool = 1;
  int64 server_time_ms = 2;
}

message ListSelfGameStakePoolsResponse {
  repeated SelfGameStakePool pools = 1;
  int64 server_time_ms = 2;
}

message DicePoolAdjustment {
  string adjustment_id = 1;
  string game_id = 2;
  int64 amount_coin = 3;
  string direction = 4;
  string reason = 5;
  int64 balance_after = 6;
  int64 created_at_ms = 7;
  int64 stake_coin = 8;
}

message AdjustSelfGameStakePoolRequest {
  RequestMeta meta = 1;
  string game_id = 2;
  int64 amount_coin = 3;
  string direction = 4;
  string reason = 5;
  int64 stake_coin = 6;
}

message AdjustSelfGameStakePoolResponse {
  DicePoolAdjustment adjustment = 1;
  DiceConfig config = 2;
  int64 server_time_ms = 3;
}

message DiceRobot {
  string app_code = 1;
  string game_id = 2;
  int64 user_id = 3;
  string status = 4;
  int64 created_by_admin_id = 5;
  int64 created_at_ms = 6;
  int64 updated_at_ms = 7;
}

message ListDiceRobotsRequest {
  RequestMeta meta = 1;
  string game_id = 2;
  string status = 3;
  int32 page_size = 4;
  string cursor = 5;
}

message ListDiceRobotsResponse {
  repeated DiceRobot robots = 1;
  string next_cursor = 2;
  int64 server_time_ms = 3;
}

message RegisterDiceRobotsRequest {
  RequestMeta meta = 1;
  string game_id = 2;
  repeated int64 user_ids = 3;
}

message RegisterDiceRobotsResponse {
  repeated DiceRobot robots = 1;
  int64 server_time_ms = 2;
}

message SetDiceRobotStatusRequest {
  RequestMeta meta = 1;
  string game_id = 2;
  int64 user_id = 3;
  string status = 4;
}

message DeleteDiceRobotRequest {
  RequestMeta meta = 1;
  string game_id = 2;
  int64 user_id = 3;
}

message DeleteDiceRobotResponse {
  bool deleted = 1;
  int64 server_time_ms = 2;
}

message DiceRobotResponse {
  DiceRobot robot = 1;
  int64 server_time_ms = 2;
}

// GameWhitelistUser 是 game-service 持有的游戏访问成员事实；用户展示资料由 admin-server 向 user-service 补齐。
message GameWhitelistUser {
  string app_code = 1;
  string game_id = 2;
  int64 user_id = 3;
  int64 created_by_admin_id = 4;
  int64 created_at_ms = 5;
}

message SetGameWhitelistEnabledRequest {
  RequestMeta meta = 1;
  string game_id = 2;
  bool enabled = 3;
}

message ListGameWhitelistUsersRequest {
  RequestMeta meta = 1;
  string game_id = 2;
  int32 page_size = 3;
}

message ListGameWhitelistUsersResponse {
  repeated GameWhitelistUser users = 1;
  int64 server_time_ms = 2;
}

message AddGameWhitelistUserRequest {
  RequestMeta meta = 1;
  string game_id = 2;
  int64 user_id = 3;
}

message GameWhitelistUserResponse {
  GameWhitelistUser user = 1;
  int64 server_time_ms = 2;
}

message DeleteGameWhitelistUserRequest {
  RequestMeta meta = 1;
  string game_id = 2;
  int64 user_id = 3;
}

message DeleteGameWhitelistUserResponse {
  int64 server_time_ms = 1;
}

service GameAppService {
  rpc ListGames(ListGamesRequest) returns (ListGamesResponse);
  rpc ListRecentGames(ListRecentGamesRequest) returns (ListGamesResponse);
  rpc ListExploreWinners(ListExploreWinnersRequest) returns (ListExploreWinnersResponse);
  rpc GetBridgeScript(GetBridgeScriptRequest) returns (GetBridgeScriptResponse);
  rpc LaunchGame(LaunchGameRequest) returns (LaunchGameResponse);
  rpc GetDiceConfig(GetDiceConfigRequest) returns (DiceConfigResponse);
  rpc MatchDice(MatchDiceRequest) returns (DiceMatchResponse);
  rpc CreateDiceMatch(CreateDiceMatchRequest) returns (DiceMatchResponse);
  rpc JoinDiceMatch(JoinDiceMatchRequest) returns (DiceMatchResponse);
  rpc GetDiceMatch(GetDiceMatchRequest) returns (DiceMatchResponse);
  rpc RollDiceMatch(RollDiceMatchRequest) returns (DiceMatchResponse);
  rpc CancelDiceMatch(CancelDiceMatchRequest) returns (DiceMatchResponse);
  rpc GetRoomRPSConfig(GetRoomRPSConfigRequest) returns (RoomRPSConfigResponse);
  rpc ListRoomRPSChallenges(ListRoomRPSChallengesRequest) returns (ListRoomRPSChallengesResponse);
  rpc CreateRoomRPSChallenge(CreateRoomRPSChallengeRequest) returns (RoomRPSChallengeResponse);
  rpc AcceptRoomRPSChallenge(AcceptRoomRPSChallengeRequest) returns (RoomRPSChallengeResponse);
  rpc GetRoomRPSChallenge(GetRoomRPSChallengeRequest) returns (RoomRPSChallengeResponse);
}

service GameCallbackService {
  rpc HandleCallback(CallbackRequest) returns (CallbackResponse);
}

// GameCronService 只给 cron-service 触发 game-service 拥有的补偿批处理。
service GameCronService {
  rpc ProcessLevelEventOutboxBatch(CronBatchRequest) returns (CronBatchResponse);
}

service GameAdminService {
  rpc ListPlatforms(ListPlatformsRequest) returns (ListPlatformsResponse);
  rpc UpsertPlatform(UpsertPlatformRequest) returns (PlatformResponse);
  rpc ListCatalog(ListCatalogRequest) returns (ListCatalogResponse);
  rpc UpsertCatalog(UpsertCatalogRequest) returns (CatalogResponse);
  rpc SetGameStatus(SetGameStatusRequest) returns (CatalogResponse);
  rpc DeleteCatalog(DeleteCatalogRequest) returns (DeleteCatalogResponse);
  rpc SetGameWhitelistEnabled(SetGameWhitelistEnabledRequest) returns (CatalogResponse);
  rpc ListGameWhitelistUsers(ListGameWhitelistUsersRequest) returns (ListGameWhitelistUsersResponse);
  rpc AddGameWhitelistUser(AddGameWhitelistUserRequest) returns (GameWhitelistUserResponse);
  rpc DeleteGameWhitelistUser(DeleteGameWhitelistUserRequest) returns (DeleteGameWhitelistUserResponse);
  rpc ListSelfGames(ListSelfGamesRequest) returns (ListSelfGamesResponse);
  rpc UpdateDiceConfig(UpdateDiceConfigRequest) returns (DiceConfigResponse);
  rpc GetSelfGameNewUserPolicy(GetSelfGameNewUserPolicyRequest) returns (SelfGameNewUserPolicyResponse);
  rpc UpdateSelfGameNewUserPolicy(UpdateSelfGameNewUserPolicyRequest) returns (SelfGameNewUserPolicyResponse);
  rpc ListSelfGameStakePools(ListSelfGameStakePoolsRequest) returns (ListSelfGameStakePoolsResponse);
  rpc UpdateSelfGameStakePool(UpdateSelfGameStakePoolRequest) returns (SelfGameStakePoolResponse);
  rpc AdjustSelfGameStakePool(AdjustSelfGameStakePoolRequest) returns (AdjustSelfGameStakePoolResponse);
  rpc ListDiceRobots(ListDiceRobotsRequest) returns (ListDiceRobotsResponse);
  rpc RegisterDiceRobots(RegisterDiceRobotsRequest) returns (RegisterDiceRobotsResponse);
  rpc SetDiceRobotStatus(SetDiceRobotStatusRequest) returns (DiceRobotResponse);
  rpc DeleteDiceRobot(DeleteDiceRobotRequest) returns (DeleteDiceRobotResponse);
  rpc GetRoomRPSConfig(GetRoomRPSConfigRequest) returns (RoomRPSConfigResponse);
  rpc UpdateRoomRPSConfig(UpdateRoomRPSConfigRequest) returns (RoomRPSConfigResponse);
  rpc ListRoomRPSChallenges(ListRoomRPSChallengesRequest) returns (ListRoomRPSChallengesResponse);
  rpc GetRoomRPSChallenge(GetRoomRPSChallengeRequest) returns (RoomRPSChallengeResponse);
  rpc RetryRoomRPSSettlement(RetryRoomRPSSettlementRequest) returns (RoomRPSChallengeResponse);
  rpc ExpireRoomRPSChallenge(ExpireRoomRPSChallengeRequest) returns (RoomRPSChallengeResponse);
}
