syntax = "proto3";

package tidb_mgmt_service.v1;

import "google/api/annotations.proto";
import "google/api/field_behavior.proto";
import "google/protobuf/timestamp.proto";
import "protoc-gen-openapiv2/options/annotations.proto";

option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
  swagger: "2.0"
  host: ""
  base_path: "/inner/mgmt/v1"
  info: {
    version: "v1"
    title: "Control Plane Internal API"
    description: "Control Plane Internal API."
  }
  schemes: HTTPS
};

// ShadowPoolManagementService provides CRUD operations for shadow pool configurations.
// All APIs here are for global control plane internal use only.
service ShadowPoolManagementService {
  rpc CreateShadowPool(CreateShadowPoolRequest) returns (ShadowPool) {
    option (google.api.http) = {
      post: "/shadow_pools"
      body: "*"
    };
  }

  rpc GetShadowPool(GetShadowPoolRequest) returns (ShadowPool) {
    option (google.api.http) = {get: "/shadow_pools/{id}"};
  }

  rpc ListShadowPools(ListShadowPoolsRequest) returns (ListShadowPoolsResponse) {
    option (google.api.http) = {get: "/shadow_pools"};
  }

  rpc UpdateShadowPool(UpdateShadowPoolRequest) returns (ShadowPool) {
    option (google.api.http) = {
      put: "/shadow_pools/{shadow_pool.id}"
      body: "*"
    };
  }

  rpc DeleteShadowPool(DeleteShadowPoolRequest) returns (DeleteShadowPoolResponse) {
    option (google.api.http) = {delete: "/shadow_pools/{id}"};
  }
}

// ShadowPool represents the configuration of a shadow pool.
message ShadowPool {
  uint64 id = 1 [(google.api.field_behavior) = OUTPUT_ONLY];
  string name = 2 [(google.api.field_behavior) = REQUIRED];

  uint64 organization_id = 3 [(google.api.field_behavior) = REQUIRED];
  uint64 project_id = 4 [(google.api.field_behavior) = REQUIRED];
  string region = 5 [(google.api.field_behavior) = REQUIRED];
  string cloud_provider = 6 [(google.api.field_behavior) = REQUIRED];
  string service_plan = 7 [(google.api.field_behavior) = REQUIRED];

  // Priority determines the order in which shadow pools are selected;
  // lower value means higher priority.
  uint64 priority = 8 [(google.api.field_behavior) = OPTIONAL];
  bool enabled = 9 [(google.api.field_behavior) = OPTIONAL];

  int32 min_capacity = 10 [(google.api.field_behavior) = OPTIONAL];
  int32 max_capacity = 11 [(google.api.field_behavior) = OPTIONAL];

  AutoScalingConfig auto_scaling_config = 12 [(google.api.field_behavior) = OPTIONAL];
  InstanceDemand instance_demand = 13 [(google.api.field_behavior) = OPTIONAL];

  // SQL statements executed during cluster initialization.
  repeated string init_sqls = 14 [(google.api.field_behavior) = OPTIONAL];

  google.protobuf.Timestamp created_at = 100 [(google.api.field_behavior) = OUTPUT_ONLY];
  google.protobuf.Timestamp updated_at = 101 [(google.api.field_behavior) = OUTPUT_ONLY];
}

// AutoScalingConfig controls the automatic scaling behavior of the shadow pool.
message AutoScalingConfig {
  // Maximum number of instances to prepare or free in one periodic operation.
  int32 max_batch_size = 1 [(google.api.field_behavior) = OPTIONAL];
  // Time in hours after which a prepared instance becomes eligible to be freed.
  int32 time_to_free_in_hours = 2 [(google.api.field_behavior) = OPTIONAL];
  // Shadow states that are eligible for freeing when they exceed time_to_free_in_hours.
  repeated ShadowState free_states = 3 [(google.api.field_behavior) = OPTIONAL];
}

// InstanceDemand specifies spending and RCU limits for instances in the shadow pool.
message InstanceDemand {
  uint64 monthly_spending_limit = 1 [(google.api.field_behavior) = OPTIONAL];
  uint64 daily_spending_limit = 2 [(google.api.field_behavior) = OPTIONAL];
  uint64 min_rcu = 3 [(google.api.field_behavior) = OPTIONAL];
  uint64 max_rcu = 4 [(google.api.field_behavior) = OPTIONAL];
}

message CreateShadowPoolRequest {
  ShadowPool shadow_pool = 1 [(google.api.field_behavior) = REQUIRED];
}

message GetShadowPoolRequest {
  uint64 id = 1 [(google.api.field_behavior) = REQUIRED];
}

message ListShadowPoolsRequest {
  repeated uint64 ids = 1 [(google.api.field_behavior) = OPTIONAL];
  repeated uint64 org_ids = 2 [(google.api.field_behavior) = OPTIONAL];
  repeated uint64 project_ids = 3 [(google.api.field_behavior) = OPTIONAL];
  repeated string service_plans = 4 [(google.api.field_behavior) = OPTIONAL];
  repeated string cloud_providers = 5 [(google.api.field_behavior) = OPTIONAL];
  repeated string regions = 6 [(google.api.field_behavior) = OPTIONAL];
  bool only_enabled = 7 [(google.api.field_behavior) = OPTIONAL];

  int32 page_size = 100 [(google.api.field_behavior) = OPTIONAL];
  string page_token = 101 [(google.api.field_behavior) = OPTIONAL];
}

message ListShadowPoolsResponse {
  repeated ShadowPool shadow_pools = 1;
  string next_page_token = 2;
}

message UpdateShadowPoolRequest {
  ShadowPool shadow_pool = 1 [(google.api.field_behavior) = REQUIRED];
}

message DeleteShadowPoolRequest {
  uint64 id = 1 [(google.api.field_behavior) = REQUIRED];
}

message DeleteShadowPoolResponse {}

// ShadowState represents the lifecycle state of a cluster within a shadow pool.
enum ShadowState {
  SHADOW_STATE_UNSPECIFIED = 0;
  // Under preparation.
  SHADOW_STATE_PREPARING = 1;
  // Prepared and ready to be rented.
  SHADOW_STATE_PREPARED = 2;
  // Being rented.
  SHADOW_STATE_RENTING = 3;
  // Rented by a user.
  SHADOW_STATE_RENTED = 4;
  // Being freed back to the pool.
  SHADOW_STATE_FREEING = 5;
  // Freed and eligible to be prepared again.
  SHADOW_STATE_FREED = 6;
  // Being claimed as a permanent cluster.
  SHADOW_STATE_CLAIMING = 7;
  // Claimed as a permanent cluster.
  SHADOW_STATE_CLAIMED = 8;
  // Being taken over as a real cluster.
  SHADOW_STATE_TAKING_OVER = 9;
  // Taken over as a real cluster.
  SHADOW_STATE_TAKEN_OVER = 10;
}
