// Copyright 2024 Google LLC
//
// 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.

syntax = "proto3";

package valkey_search.coordinator;

import "google/protobuf/any.proto";

service Coordinator {
  // Get the current schema metadata.
  rpc GetGlobalMetadata(GetGlobalMetadataRequest)
      returns (GetGlobalMetadataResponse) {}
  // Search the index partition for documents.
  rpc SearchIndexPartition(SearchIndexPartitionRequest)
      returns (SearchIndexPartitionResponse) {}
  // Get index info across cluster
  rpc InfoIndexPartition(InfoIndexPartitionRequest)
      returns (InfoIndexPartitionResponse) {}
}

message LimitParameter {
  uint64 first_index = 1;
  uint64 number = 2;
}

message TagPredicate {
  string attribute_alias = 1;
  string raw_tag_string = 2;
}

message NumericPredicate {
  string attribute_alias = 1;
  double start = 2;
  bool is_inclusive_start = 3;
  double end = 4;
  bool is_inclusive_end = 5;
}

message TermPredicate {
  uint64 field_mask = 1;
  string content = 2;
  bool exact = 3;
}

message PrefixPredicate {
  uint64 field_mask = 1;
  string content = 2;
}

message SuffixPredicate {
  uint64 field_mask = 1;
  string content = 2;
}

message InfixPredicate {
  uint64 field_mask = 1;
  string content = 2;
}

message FuzzyPredicate {
  uint64 field_mask = 1;
  string content = 2;
  uint32 distance = 3;
}

message AndPredicate {
  repeated Predicate children = 1;
  optional uint32 slop = 2;
  bool inorder = 3;
}

message OrPredicate {
  repeated Predicate children = 1;
}

message NegatePredicate {
  Predicate predicate = 1;
}

message Predicate {
  oneof predicate {
    TagPredicate tag = 1;
    NumericPredicate numeric = 2;
    AndPredicate and = 3;
    OrPredicate or = 4;
    NegatePredicate negate = 5;
    TermPredicate term = 6;
    PrefixPredicate prefix = 7;
    SuffixPredicate suffix = 8;
    InfixPredicate infix = 9;
    FuzzyPredicate fuzzy = 10;
  }
}

message ReturnParameter {
  string identifier = 1;
  string alias = 2;
}

enum SortOrder {
  SORT_ORDER_ASCENDING = 0;
  SORT_ORDER_DESCENDING = 1;
}

message SortByParameter {
  string field = 1;
  SortOrder order = 2;
}

message IndexFingerprintVersion {
  uint64 fingerprint = 1;
  uint32 version = 2;
}

message SearchIndexPartitionRequest {
  uint32 db_num = 1;
  string index_schema_name = 2;
  string attribute_alias = 3;
  optional string score_as = 4;
  bytes query = 5;
  uint32 dialect = 6;
  uint32 k = 7;
  uint64 ef = 8;
  LimitParameter limit = 9;
  uint64 timeout_ms = 10;
  bool no_content = 11;
  optional Predicate root_filter_predicate = 12;
  repeated ReturnParameter return_parameters = 13;
  bool enable_partial_results = 14;
  bool enable_consistency = 15;
  IndexFingerprintVersion index_fingerprint_version = 16;
  uint64 slot_fingerprint = 17;
  uint64 query_operations = 18;
  optional SortByParameter sortby = 19;
}

message NeighborEntry {
  string key = 1;
  float score = 2;
  repeated AttributeContentEntry attribute_contents = 3;
}

message SearchIndexPartitionResponse {
  repeated NeighborEntry neighbors = 1;
  uint64 total_count = 2;
}

message AttributeContentEntry {
  string identifier = 1;
  bytes content = 2;
}

message GlobalMetadataVersionHeader {
  uint64 top_level_fingerprint = 1;
  uint32 top_level_version = 2;
  uint32 top_level_min_version = 3;
}

message GlobalMetadata {
  GlobalMetadataVersionHeader version_header = 1;
  // Nested map. Outer map is namespace, inner map is ID to entry.
  map<string, GlobalMetadataEntryMap> type_namespace_map = 2;
}

// GlobalMetadataEntryMap is a wrapper around a map from ID to metadata entry.
message GlobalMetadataEntryMap {
  map<string, GlobalMetadataEntry> entries = 1;
}

message GlobalMetadataEntry {
  uint32 version = 1;
  uint64 fingerprint = 2;
  uint32 encoding_version = 3;
  optional google.protobuf.Any content = 4;
  uint32 min_version = 5;
}

message GetGlobalMetadataRequest {}
message GetGlobalMetadataResponse {
  GlobalMetadata metadata = 1;
}

message InfoIndexPartitionRequest {
  uint32 db_num = 1;
  string index_name = 2;
  bool require_consistency = 3;
  IndexFingerprintVersion index_fingerprint_version = 4;
  uint64 slot_fingerprint = 5;
}

enum FanoutErrorType {
  OK = 0;
  INDEX_NAME_ERROR = 1;
  INCONSISTENT_STATE_ERROR = 2;
  COMMUNICATION_ERROR = 3;
}

message AttributeInfo {
  string identifier = 1;
  string alias = 2;
  uint64 user_indexed_memory = 3;
  uint64 num_records = 4;
}

message InfoIndexPartitionResponse {
  bool exists = 1;
  string index_name = 2;
  uint64 num_docs = 3;
  uint64 num_records = 4;
  uint64 hash_indexing_failures = 5;
  uint64 backfill_scanned_count = 6;
  uint64 backfill_db_size = 7;
  uint64 backfill_inqueue_tasks = 8;
  float backfill_complete_percent = 9;
  bool backfill_in_progress = 10;
  uint64 mutation_queue_size = 11;
  uint64 recent_mutations_queue_delay = 12;
  string state = 13;
  string error = 14;
  optional IndexFingerprintVersion index_fingerprint_version = 15;
  FanoutErrorType error_type = 16;
  uint32 db_num = 17;
  repeated AttributeInfo attributes = 18;
}
