syntax = "proto3";

package shrikedb.v2;

// ShrikeDB v2 is the public database gRPC API. Older database service paths
// are no longer generated from this proto.

// The main service for interacting with the database.
service ShrikeDbService {
  // --- Schema & Mapping API ---
  rpc CreateSchema(CreateSchemaRequest) returns (CreateSchemaResponse);
  rpc AddSemanticRule(AddSemanticRuleRequest) returns (AddSemanticRuleResponse);

  // --- KeyValue Modality API ---
  rpc PutKeyValue(PutKeyValueRequest) returns (PutKeyValueResponse);
  rpc GetKeyValue(GetKeyValueRequest) returns (GetKeyValueResponse);
  rpc BulkGetKeyValue(BulkGetKeyValueRequest) returns (BulkGetKeyValueResponse);
  rpc BulkPutKeyValue(BulkPutKeyValueRequest) returns (BulkPutKeyValueResponse);

  // --- Graph Modality API ---
  rpc InsertGraphBlock(InsertGraphBlockRequest) returns (InsertGraphBlockResponse);
  rpc BulkInsertGraphBlocks(BulkInsertGraphBlocksRequest) returns (BulkInsertGraphBlocksResponse);

  // --- Query API ---
  rpc ExecuteQuery(ExecuteQueryRequest) returns (stream QueryResultRow);
  rpc ExecuteSPARQL(SPARQLQueryRequest) returns (stream QueryResultRow);
  rpc ExecuteSPARQLUpdate(SPARQLUpdateRequest) returns (SPARQLUpdateResponse);
  rpc ExecuteCypher(CypherQueryRequest) returns (stream QueryResultRow);

  // --- Vector Search API ---
  rpc VectorSearch(VectorSearchRequest) returns (stream VectorSearchResult);
  rpc VectorSearchPacked(VectorSearchRequest) returns (VectorSearchPackedResponse);
  rpc VectorSearchBatchPacked(VectorSearchBatchRequest) returns (VectorSearchBatchPackedResponse);
  rpc InsertVector(InsertVectorRequest) returns (InsertVectorResponse);
  rpc BulkInsertVectors(BulkInsertVectorsRequest) returns (BulkInsertVectorsResponse);

  // --- Graph Query API ---
  rpc GraphScan(GraphScanRequest) returns (stream GraphScanResult);
  rpc BulkNeighbors(BulkNeighborsRequest) returns (BulkNeighborsResponse);
  rpc BulkNeighborsCompact(BulkNeighborsCompactRequest) returns (BulkNeighborsCompactResponse);

  // --- Transaction API ---
  rpc BeginTransaction(BeginTransactionRequest) returns (BeginTransactionResponse);
  rpc TransactionInsertVector(TransactionInsertVectorRequest) returns (TransactionInsertVectorResponse);
  rpc TransactionInsertGraphEdge(TransactionInsertGraphEdgeRequest) returns (TransactionInsertGraphEdgeResponse);
  rpc TransactionInsertKV(TransactionInsertKVRequest) returns (TransactionInsertKVResponse);
  rpc TransactionInsertSpaceKey(TransactionInsertSpaceKeyRequest) returns (TransactionInsertSpaceKeyResponse);
  rpc TransactionGetKV(TransactionGetKVRequest) returns (TransactionGetKVResponse);
  rpc TransactionQuery(TransactionQueryRequest) returns (stream QueryResultRow);
  rpc CommitTransaction(CommitTransactionRequest) returns (CommitTransactionResponse);
  rpc RollbackTransaction(RollbackTransactionRequest) returns (RollbackTransactionResponse);
  rpc PrepareTransactionCommit(PrepareTransactionCommitRequest) returns (PrepareTransactionCommitResponse);
  rpc FinalizeTransactionCommit(FinalizeTransactionCommitRequest) returns (FinalizeTransactionCommitResponse);
  rpc ApplyTransactionCommit(ApplyTransactionCommitRequest) returns (ApplyTransactionCommitResponse);
}

// ============== Messages ==============

message Uid {
  uint64 id = 1;
}

// --- Schema Messages ---

message SchemaDefinition {
  uint64 id = 1;
  string name = 2;
  map<string, string> fields = 3;
}

message CreateSchemaRequest {
  SchemaDefinition schema = 1;
}

message CreateSchemaResponse {}

// --- Semantic Mapping Messages ---

message SemanticTypeNode {
  string label = 1;
}

message SemanticTypeEdge {
  string label = 1;
}

message SemanticType {
  oneof type {
    SemanticTypeNode node = 1;
    SemanticTypeEdge edge = 2;
  }
}

message AddSemanticRuleRequest {
  uint64 schema_id = 1;
  SemanticType semantic_type = 2;
}

message AddSemanticRuleResponse {}

// --- KeyValue Messages ---

message PutKeyValueRequest {
  Uid subject_id = 1;
  uint64 schema_id = 2;
  Uid key = 3;
  bytes value = 4;
}

message PutKeyValueResponse {}

message GetKeyValueRequest {
  Uid subject_id = 1;
  Uid key = 2;
}

message GetKeyValueResponse {
  optional bytes value = 1; // `optional` indicates it might not be found.
}

message KeyValueReadResult {
  Uid key = 1;
  optional bytes value = 2;
  bool found = 3;
}

message BulkGetKeyValueRequest {
  Uid subject_id = 1;
  repeated Uid keys = 2;
}

message BulkGetKeyValueResponse {
  repeated KeyValueReadResult results = 1;
  uint64 found_count = 2;
  uint64 total_value_bytes = 3;
}

message KeyValueEntry {
  Uid key = 1;
  bytes value = 2;
}

message BulkPutKeyValueRequest {
  Uid subject_id = 1;
  uint64 schema_id = 2;
  repeated KeyValueEntry entries = 3;
}

message BulkPutKeyValueResponse {
  bool success = 1;
  uint64 count = 2;
  optional string error_message = 3;
}

// --- Graph Messages ---

// Simplified for the example
message InsertGraphBlockRequest {
    Uid subject_id = 1;
    Uid resource_id = 2;
    reserved 3;            // Reserved for removed fragment_id field
    reserved "fragment_id";
    uint64 schema_id = 4;  // Keep original field number
    bytes payload = 5;     // Keep original field number
    // In a real system, you'd define a proper GraphBlockType enum here.
    uint32 block_type = 6; // Keep original field number
}

message InsertGraphBlockResponse {
    uint64 fragment_id = 1;  // Server-generated fragment ID for reference
}

// Bulk graph block insert messages
message GraphBlockEntry {
    // Edge data
    uint64 source_uid = 1;        // Graph source vertex (was confused as subject_id)
    uint64 target_uid = 2;        // Graph target vertex
    reserved 3;                   // Reserved for removed fragment_id field
    reserved "fragment_id";
    uint64 schema_id = 4;         // Schema/resource ID (consolidated from resource_id)
    bytes payload = 5;            // Edge payload bytes
    uint64 edge_type = 6;         // Edge type/label ID (changed from block_type)
}

message BulkInsertGraphBlocksRequest {
    Uid subject_id = 1;           // Authenticated caller (ONE subject for entire request)
    repeated GraphBlockEntry blocks = 2;
}

message BulkInsertGraphBlocksResponse {
    uint64 inserted_count = 1;
    repeated uint64 fragment_ids = 2;  // Server-generated IDs in insertion order
}

// --- Query Messages ---

// Generic value type for query results
message Value {
  oneof value {
    uint64 uid = 1;
    string string_val = 2;
    double float_val = 3;
    int64 int_val = 4;
    bool bool_val = 5;
    bytes bytes_val = 6;
    VectorValue vector = 7;
    UidListValue uid_list = 8;
  }
}

message VectorValue {
  repeated float elements = 1;
}

message UidListValue {
  repeated uint64 elements = 1;
}

// Execute query request (supports multiple query languages)
message ExecuteQueryRequest {
  oneof query {
    string sparql = 1;
    string cypher = 2;
    bytes serialized_plan = 3; // Serialized LogicalPlan for Builder API
    string sql = 7; // Native SQL queries and admitted graph DML
  }
  optional uint64 snapshot_version = 4;
  optional uint32 limit = 5;
  optional uint32 offset = 6;
}

// SPARQL query request
message SPARQLQueryRequest {
  string query = 1;
  optional uint64 snapshot_version = 2;
  optional uint32 limit = 3;
  optional uint32 offset = 4;
}

// Executes one supported SPARQL mutation. Query and update responses are distinct.
message SPARQLUpdateRequest {
  string update = 1;
}

message SPARQLUpdateResponse {
  bool committed = 1;
  string operation_hash = 2;
  uint64 submitted_triples = 3;
}

// Cypher query request
message CypherQueryRequest {
  string query = 1;
  optional uint64 snapshot_version = 2;
  optional uint32 limit = 3;
  optional uint32 offset = 4;
  map<string, Value> parameters = 5;
}

// Query result row (stream of these)
message QueryResultRow {
  map<string, Value> bindings = 1;
}

// --- Vector Search Messages ---

message InsertVectorRequest {
  Uid entity_id = 1;
  string index_name = 2;
  repeated float vector = 3;
  optional uint64 schema_id = 4;
}

message InsertVectorResponse {
  bool success = 1;
}

// Bulk vector insert request - batch multiple vectors in single RPC
message BulkInsertVectorsRequest {
  repeated VectorEntry vectors = 1;
  string index_name = 2;
  optional uint64 schema_id = 3;
}

message VectorEntry {
  Uid entity_id = 1;
  repeated float vector = 2;
}

message BulkInsertVectorsResponse {
  bool success = 1;
  uint64 count = 2;
}

message VectorSearchRequest {
  string index_name = 1;
  repeated float query_vector = 2;
  uint32 k = 3;
  optional uint32 ef_search = 4;
  optional uint64 snapshot_version = 5;
  optional VectorFilter filter = 6;
}

message VectorFilter {
  // Optional filters for vector search
  repeated Uid entity_ids = 1; // Restrict to specific entities
  map<string, string> metadata_filters = 2; // Metadata filters
}

message VectorSearchResult {
  Uid entity_id = 1;
  float score = 2;
  repeated float vector = 3; // Optional: return the vector (empty if not requested)
}

message VectorSearchPackedResponse {
  repeated uint64 entity_ids = 1;
  repeated float scores = 2;
}

message VectorSearchQuery {
  repeated float query_vector = 1;
  optional uint32 k = 2;
  optional uint32 ef_search = 3;
  optional uint64 snapshot_version = 4;
  optional VectorFilter filter = 5;
}

message VectorSearchBatchRequest {
  string index_name = 1;
  repeated VectorSearchQuery queries = 2;
  optional uint32 k = 3;
  optional uint32 ef_search = 4;
  optional uint64 snapshot_version = 5;
  optional VectorFilter filter = 6;
}

message VectorSearchPackedItem {
  repeated uint64 entity_ids = 1;
  repeated float scores = 2;
}

message VectorSearchBatchPackedResponse {
  repeated VectorSearchPackedItem results = 1;
}

// --- Graph Scan Messages ---

enum GraphDirection {
  GRAPH_DIRECTION_OUT = 0;
  GRAPH_DIRECTION_IN = 1;
  GRAPH_DIRECTION_BOTH = 2;
}

message GraphScanRequest {
  // Triple pattern: subject-predicate-object
  // Use "?" prefix for variables, or specific Uid/literal for constants
  string subject = 1;    // e.g., "?person" or "uid:123"
  string predicate = 2;  // e.g., "?pred" or "knows"
  string object = 3;     // e.g., "?friend" or "uid:456"
  optional uint64 snapshot_version = 4;
  optional uint32 limit = 5;
}

message GraphScanResult {
  Uid subject_uid = 1;
  string predicate = 2;
  Uid object_uid = 3;
  optional bytes payload = 4; // Optional edge payload
  uint64 fragment_id = 5;     // Fragment ID for correlation/updates
}

message BulkNeighborsRequest {
  repeated Uid node_ids = 1;
  optional string predicate = 2;      // Empty/absent = any predicate
  GraphDirection direction = 3;       // OUT / IN / BOTH
  optional uint32 limit_per_node = 4; // Cap per source node
}

message NeighborRecord {
  Uid node = 1;
  string predicate = 2;
  optional bytes payload = 3;
  uint64 fragment_id = 4;
}

message NodeNeighbors {
  Uid source_node = 1;
  repeated NeighborRecord neighbors = 2;
}

message BulkNeighborsResponse {
  repeated NodeNeighbors nodes = 1;
}

message BulkNeighborsCompactRequest {
  repeated Uid node_ids = 1;
  optional string predicate = 2;      // Empty/absent = any predicate
  GraphDirection direction = 3;       // OUT / IN / BOTH
  optional uint32 limit_per_node = 4; // Cap per source node
  bool include_predicates = 5;        // Include response-local predicate ids/dictionary
}

message CompactNodeNeighbors {
  uint64 source_node_id = 1;
  uint32 start_offset = 2;
  uint32 neighbor_count = 3;
}

message BulkNeighborsCompactResponse {
  repeated CompactNodeNeighbors nodes = 1;
  repeated uint64 neighbor_node_ids = 2;
  repeated uint32 predicate_ids = 3;
  repeated string predicate_dictionary = 4;
}

// --- Transaction Messages ---

message TransactionId {
  string id = 1; // UUID as string (e.g., "550e8400-e29b-41d4-a716-446655440000")
}

message BeginTransactionRequest {
  Uid subject_id = 1;           // Transaction owner
  optional uint32 timeout_ms = 2; // Optional timeout in milliseconds (default 30000)
}

message BeginTransactionResponse {
  TransactionId transaction_id = 1;
  uint64 read_version = 2;      // Snapshot version for this transaction
}

message TransactionInsertVectorRequest {
  TransactionId transaction_id = 1;
  string index_name = 2;
  Uid entity_id = 3;
  repeated float vector = 4;
}

message TransactionInsertVectorResponse {
  bool success = 1;
}

message TransactionInsertGraphEdgeRequest {
  TransactionId transaction_id = 1;
  Uid subject = 2;
  string predicate = 3;
  Uid object = 4;
  optional bytes payload = 5; // Optional edge data
}

message TransactionInsertGraphEdgeResponse {
  bool success = 1;
}

message TransactionInsertKVRequest {
  TransactionId transaction_id = 1;
  uint64 schema_id = 2;
  Uid key = 3;
  bytes value = 4;
}

message TransactionInsertKVResponse {
  bool success = 1;
}

message SpaceKeyDomain {
  int64 start_ms = 1;
  int64 end_ms = 2;
}

message SpaceKeyEvent {
  uint64 id = 1;
  uint64 entity = 2;
  double longitude = 3;
  double latitude = 4;
  int64 time_ms = 5;
}

message TransactionInsertSpaceKeyRequest {
  TransactionId transaction_id = 1;
  string index = 2;
  string batch = 3;
  SpaceKeyDomain domain = 4;
  repeated SpaceKeyEvent events = 5;
}

message TransactionInsertSpaceKeyResponse {
  bool success = 1;
}

message TransactionGetKVRequest {
  TransactionId transaction_id = 1;
  Uid key = 2;
}

message TransactionGetKVResponse {
  optional bytes value = 1; // None if not found
}

message TransactionQueryRequest {
  TransactionId transaction_id = 1;
  oneof query {
    string sparql = 2;
    string cypher = 3;
    bytes serialized_plan = 4; // Serialized LogicalPlan
  }
  optional uint32 limit = 5;
  optional uint32 offset = 6;
}

message CommitTransactionRequest {
  TransactionId transaction_id = 1;
}

message CommitTransactionResponse {
  bool success = 1;
  optional uint64 write_version = 2; // Version at which writes were committed
  optional string error_message = 3; // Error if commit failed (e.g., conflict)
}

message RollbackTransactionRequest {
  TransactionId transaction_id = 1;
}

message RollbackTransactionResponse {
  bool success = 1;
}

// HA-internal transaction commit apply payload. Public clients should use the
// regular transaction lifecycle RPCs above; this RPC is accepted only with HA
// replication metadata and the node token.
message TransactionCommitVectorWrite {
  string index_name = 1;
  Uid entity_id = 2;
  repeated float vector = 3;
}

message TransactionCommitGraphEdgeWrite {
  Uid subject = 1;
  string predicate = 2;
  Uid object = 3;
}

message TransactionCommitKVWrite {
  uint64 resource_id = 1;
  Uid key = 2;
  bytes value = 3;
}

message TransactionCommitSpaceKeyWrite {
  string index = 1;
  string batch = 2;
  SpaceKeyDomain domain = 3;
  repeated SpaceKeyEvent events = 4;
}

message TransactionCommitWrite {
  oneof write {
    TransactionCommitVectorWrite vector = 1;
    TransactionCommitGraphEdgeWrite graph_edge = 2;
    TransactionCommitKVWrite key_value = 3;
    TransactionCommitSpaceKeyWrite spacekey = 4;
  }
}

message ApplyTransactionCommitRequest {
  Uid subject_id = 1;
  uint64 read_version = 2;
  repeated TransactionCommitWrite writes = 3;
  string database = 4;
}

message ApplyTransactionCommitResponse {
  bool success = 1;
  optional uint64 write_version = 2;
  optional string error_message = 3;
}

message PrepareTransactionCommitRequest {
  ApplyTransactionCommitRequest commit = 1;
}

message PrepareTransactionCommitResponse {
  bool success = 1;
  optional string error_message = 2;
}

enum TransactionCommitDecision {
  TRANSACTION_COMMIT_DECISION_UNSPECIFIED = 0;
  TRANSACTION_COMMIT_DECISION_COMMIT = 1;
  TRANSACTION_COMMIT_DECISION_ABORT = 2;
}

message FinalizeTransactionCommitRequest {
  ApplyTransactionCommitRequest commit = 1;
  TransactionCommitDecision decision = 2;
}

message FinalizeTransactionCommitResponse {
  bool success = 1;
  optional uint64 write_version = 2;
  optional string error_message = 3;
}
