syntax = "proto3";

package confidence.flags.admin.v1;

import "google/protobuf/timestamp.proto";
import "google/api/resource.proto";
import "google/api/annotations.proto";
import "google/api/field_behavior.proto";

import "confidence/flags/admin/v1/types.proto";
import "confidence/iam/v1/iam.proto";
import "confidence/api/annotations.proto";
import "confidence/auth/v1/auth.proto";

option java_package = "com.spotify.confidence.flags.admin.v1";
option java_multiple_files = true;
option java_outer_classname = "ResolverProto";

// Service for fetching the state for resolving flags
service ResolverStateService {
  option (confidence.api.service_name) = "Flags";
  option (confidence.api.hosts) = "flags.eu.confidence.dev";
  option (confidence.api.hosts) = "flags.us.confidence.dev";

  // Gets the full state for running a resolver
  rpc FullResolverState(ResolverStateRequest) returns (stream ResolverState) {
    option (google.api.http) = {
      get: "/v1/resolverState:full"
    };
    option (confidence.auth.v1.auth) = {
      required_relation: "can_view_flag",
      object_field: "account"
    };
  }

  // Gets a signed uri that can be used to download the current resolver state
  rpc ResolverStateUri(ResolverStateUriRequest) returns (ResolverStateUriResponse){
    option (google.api.http) = {
      get: "/v1/resolverState:resolverStateUri"
    };
    option (confidence.auth.v1.auth) = {
      required_relation: "can_view_flag",
      object_field: "account"
    };
  }
}

// Request to fetch resolver state uri
message ResolverStateUriRequest {

}

// Response of fetching resolver state uri
message ResolverStateUriResponse {
  // The signed uri that can be used to fetch state
  string signed_uri = 1;
  // At what time the state uri expires
  google.protobuf.Timestamp expire_time = 2;
  // The account the referenced state belongs to
  string account = 3;
}

// Request to get the resolver state for the whole account
message ResolverStateRequest {
}

// The full state for operating a flags resolver
message ResolverState {
  // All active flags
  repeated Flag flags = 1;

  // All allocated segments, but without the `bitset_allocation` field set. The actual bitsets will be packed and sent
  // separately.
  repeated Segment segments_no_bitsets = 2;

  // Packed bitsets for the segments
  repeated PackedBitset bitsets = 5;

  // All clients
  repeated confidence.iam.v1.Client clients = 6;

  // All client credentials
  repeated confidence.iam.v1.ClientCredential client_credentials = 7;

  // The region of the account
  Region region = 8;

  repeated BloomFilter bloom_filters = 10;

  // A bloom filter for a materialized segment, delivered to local resolvers.
  // The raw bit array is extracted from Guava's BloomFilter serialization format.
  message BloomFilter {
    // The materialized segment this bloom filter belongs to
    string materialized_segment = 1 [
      (google.api.resource_reference).type = "flags.confidence.dev/MaterializedSegment"
    ];

    // Raw bit array (long[] serialized as bytes)
    bytes data = 2;

    // Number of hash functions used
    int32 hash_function_count = 3;

    // Total number of bits in the filter
    int64 bit_count = 4;

    // Strategy identifier (1 = MURMUR128_MITZ_64)
    int32 strategy = 5;
  }

  // A compressed bitset for a specific segment. The bitset will be gzipped, unless it's all ones, in which case the
  // `full_bitset` field will be set instead.
  message PackedBitset {
    // The segment which this bitset belongs to
    string segment = 1 [
      (google.api.resource_reference).type = "flags.confidence.dev/Segment"
    ];

    oneof bitset {
      // A gzip compressed bitset
      bytes gzipped_bitset = 2;

      // Set to true if all bits in the bitset are set
      bool full_bitset = 3;
    }
  }
  // An account region
  enum Region {
    // Region is not set
    REGION_UNSPECIFIED = 0;
    // EU region
    REGION_EU = 1;
    // US region
    REGION_US = 2;
  }
}
