syntax = "proto3";

package gql;

import "gql_types.proto";

// ============================================================================
// SessionService
// Manages session lifecycle and configuration.
// Errors are returned as gRPC Status codes (UNAUTHENTICATED, NOT_FOUND, etc.)
// ============================================================================

service SessionService {
  // Establish a session. Negotiates protocol version and authenticates.
  rpc Handshake(HandshakeRequest) returns (HandshakeResponse);

  // Configure session state (schema, graph, timezone, parameters).
  rpc Configure(ConfigureRequest) returns (ConfigureResponse);

  // Reset session state to defaults.
  rpc Reset(ResetRequest) returns (ResetResponse);

  // Terminate the session. Rolls back any active transaction.
  rpc Close(CloseRequest) returns (CloseResponse);

  // Health check and keepalive.
  rpc Ping(PingRequest) returns (PongResponse);
}

// ============================================================================
// GqlService
// Executes GQL statements and manages transactions.
// Errors are returned as GQLSTATUS codes in the response payload.
// gRPC status is always OK unless there is a transport-level failure.
// ============================================================================

service GqlService {
  // Execute any GQL statement. Returns a stream of response frames:
  //   1. ResultHeader  (column metadata or result type indicator)
  //   2. RowBatch*     (zero or more batches of rows)
  //   3. ResultSummary (completion status, row count, diagnostics)
  rpc Execute(ExecuteRequest) returns (stream ExecuteResponse);

  // Begin an explicit transaction.
  rpc BeginTransaction(BeginRequest) returns (BeginResponse);

  // Commit the active transaction.
  rpc Commit(CommitRequest) returns (CommitResponse);

  // Roll back the active transaction.
  rpc Rollback(RollbackRequest) returns (RollbackResponse);
}

// ============================================================================
// Session Messages
// ============================================================================

message HandshakeRequest {
  uint32 protocol_version = 1;
  AuthCredentials credentials = 2;
  map<string, string> client_info = 3;  // Driver name, version, platform
}

message HandshakeResponse {
  uint32 protocol_version = 1;
  string session_id = 2;
  ServerInfo server_info = 3;
  map<string, int64> limits = 4;  // Implementation limits (IL codes)
}

message ServerInfo {
  string name = 1;
  string version = 2;
  repeated string features = 3;
}

message ConfigureRequest {
  string session_id = 1;
  oneof property {
    string schema = 2;
    string graph = 3;
    int32 time_zone_offset_minutes = 4;
    SessionParameter parameter = 5;
  }
}

message SessionParameter {
  string name = 1;
  Value value = 2;
}

message ConfigureResponse {}

message ResetRequest {
  string session_id = 1;
  ResetTarget target = 2;
}

enum ResetTarget {
  RESET_ALL = 0;
  RESET_SCHEMA = 1;
  RESET_GRAPH = 2;
  RESET_TIME_ZONE = 3;
  RESET_PARAMETERS = 4;
}

message ResetResponse {}

message CloseRequest {
  string session_id = 1;
}

message CloseResponse {}

message PingRequest {
  string session_id = 1;
}

message PongResponse {
  int64 timestamp = 1;
}

// ============================================================================
// Execute Messages
// ============================================================================

message ExecuteRequest {
  string session_id = 1;
  string statement = 2;
  map<string, Value> parameters = 3;
  optional string transaction_id = 4;  // Omit for auto-commit
}

message ExecuteResponse {
  oneof frame {
    ResultHeader header = 1;
    RowBatch row_batch = 2;
    ResultSummary summary = 3;
  }
}

// First frame: describes what kind of result follows.
message ResultHeader {
  ResultType result_type = 1;
  repeated ColumnDescriptor columns = 2;
  bool ordered = 3;  // Whether row order is semantically meaningful (sec 4.3.6)
}

enum ResultType {
  BINDING_TABLE = 0;
  GRAPH = 1;
  OMITTED = 2;
}

message ColumnDescriptor {
  string name = 1;
  TypeDescriptor type = 2;
}

// Data frames: batched rows.
message RowBatch {
  repeated Row rows = 1;
}

message Row {
  repeated Value values = 1;  // Positional, matches column order from header
}

// Final frame: completion status and statistics.
message ResultSummary {
  GqlStatus status = 1;
  repeated GqlStatus warnings = 2;
  int64 rows_affected = 3;
  map<string, int64> counters = 4;  // nodes_created, edges_deleted, etc.
}

// ============================================================================
// Transaction Messages
// ============================================================================

message BeginRequest {
  string session_id = 1;
  TransactionMode mode = 2;
}

message BeginResponse {
  string transaction_id = 1;
  GqlStatus status = 2;
}

message CommitRequest {
  string session_id = 1;
  string transaction_id = 2;
}

message CommitResponse {
  GqlStatus status = 1;
}

message RollbackRequest {
  string session_id = 1;
  string transaction_id = 2;
}

message RollbackResponse {
  GqlStatus status = 1;
}

enum TransactionMode {
  READ_WRITE = 0;
  READ_ONLY = 1;
}

// ============================================================================
// CatalogService
// Manages the catalog hierarchy: schemas, graphs, and graph types.
// Replaces DatabaseService with spec-aligned catalog model (sec 12).
// Errors are returned as gRPC Status codes.
// ============================================================================

service CatalogService {
  // Schema management (sec 12.2, 12.3 - Feature GC01)
  rpc ListSchemas(ListSchemasRequest) returns (ListSchemasResponse);
  rpc CreateSchema(CreateSchemaRequest) returns (CreateSchemaResponse);
  rpc DropSchema(DropSchemaRequest) returns (DropSchemaResponse);

  // Graph management (sec 12.4, 12.5 - Feature GC04)
  rpc ListGraphs(ListGraphsRequest) returns (ListGraphsResponse);
  rpc CreateGraph(CreateGraphRequest) returns (CreateGraphResponse);
  rpc DropGraph(DropGraphRequest) returns (DropGraphResponse);
  rpc GetGraphInfo(GetGraphInfoRequest) returns (GetGraphInfoResponse);

  // Graph type management (sec 12.6, 12.7 - Feature GG02)
  rpc ListGraphTypes(ListGraphTypesRequest) returns (ListGraphTypesResponse);
  rpc CreateGraphType(CreateGraphTypeRequest) returns (CreateGraphTypeResponse);
  rpc DropGraphType(DropGraphTypeRequest) returns (DropGraphTypeResponse);
}

// ============================================================================
// Schema Messages
// ============================================================================

message ListSchemasRequest {}

message SchemaInfo {
  string name = 1;
  uint32 graph_count = 2;
  uint32 graph_type_count = 3;
}

message ListSchemasResponse {
  repeated SchemaInfo schemas = 1;
}

message CreateSchemaRequest {
  string name = 1;
  bool if_not_exists = 2;
}

message CreateSchemaResponse {}

message DropSchemaRequest {
  string name = 1;
  bool if_exists = 2;
}

message DropSchemaResponse {
  bool existed = 1;
}

// ============================================================================
// Graph Messages
// ============================================================================

message ListGraphsRequest {
  string schema = 1;  // Schema to list graphs from
}

message GraphSummary {
  string schema = 1;
  string name = 2;
  uint64 node_count = 3;
  uint64 edge_count = 4;
  string graph_type = 5;  // Graph type name (empty if open)
}

message ListGraphsResponse {
  repeated GraphSummary graphs = 1;
}

message CreateGraphRequest {
  string schema = 1;
  string name = 2;
  bool if_not_exists = 3;
  bool or_replace = 4;

  // Graph type (sec 12.4)
  oneof type_spec {
    bool open_type = 5;           // true = ANY GRAPH (open graph type)
    string graph_type_ref = 6;    // Reference to a named graph type
  }

  // Optional: copy contents from source graph
  optional string copy_of = 7;   // "schema.graph" qualified name

  // Engine-specific options (GrafeoDB extensions)
  string storage_mode = 10;      // "InMemory" or "Persistent"
  GraphOptions options = 11;
}

message GraphOptions {
  optional uint64 memory_limit_bytes = 1;
  optional bool backward_edges = 2;
  optional uint32 threads = 3;
  optional bool wal_enabled = 4;
  optional string wal_durability = 5;
}

message CreateGraphResponse {
  GraphSummary graph = 1;
}

message DropGraphRequest {
  string schema = 1;
  string name = 2;
  bool if_exists = 3;
}

message DropGraphResponse {
  bool existed = 1;
}

message GetGraphInfoRequest {
  string schema = 1;
  string name = 2;
}

message GetGraphInfoResponse {
  string schema = 1;
  string name = 2;
  uint64 node_count = 3;
  uint64 edge_count = 4;
  string graph_type = 5;
  string storage_mode = 6;
  uint64 memory_limit_bytes = 7;
  bool backward_edges = 8;
  uint32 threads = 9;
}

// ============================================================================
// Graph Type Messages
// ============================================================================

message ListGraphTypesRequest {
  string schema = 1;
}

message GraphTypeInfo {
  string schema = 1;
  string name = 2;
}

message ListGraphTypesResponse {
  repeated GraphTypeInfo graph_types = 1;
}

message CreateGraphTypeRequest {
  string schema = 1;
  string name = 2;
  bool if_not_exists = 3;
  bool or_replace = 4;
}

message CreateGraphTypeResponse {}

message DropGraphTypeRequest {
  string schema = 1;
  string name = 2;
  bool if_exists = 3;
}

message DropGraphTypeResponse {
  bool existed = 1;
}

// ============================================================================
// AdminService
// Graph introspection, maintenance, and index management.
// Errors are returned as gRPC Status codes.
// ============================================================================

service AdminService {
  // Get detailed graph statistics (counts, memory, disk, indexes).
  rpc GetGraphStats(GetGraphStatsRequest) returns (GetGraphStatsResponse);

  // Get WAL (Write-Ahead Log) status.
  rpc WalStatus(WalStatusRequest) returns (WalStatusResponse);

  // Force a WAL checkpoint (flush pending records to storage).
  rpc WalCheckpoint(WalCheckpointRequest) returns (WalCheckpointResponse);

  // Validate graph integrity (dangling edges, index consistency).
  rpc Validate(ValidateRequest) returns (ValidateResponse);

  // Create an index (property, vector, or text).
  rpc CreateIndex(CreateIndexRequest) returns (CreateIndexResponse);

  // Drop an index.
  rpc DropIndex(DropIndexRequest) returns (DropIndexResponse);
}

// ============================================================================
// SearchService
// Vector, text, and hybrid search operations.
// Errors are returned as gRPC Status codes.
// ============================================================================

service SearchService {
  // Vector similarity search (KNN via HNSW index).
  rpc VectorSearch(VectorSearchRequest) returns (VectorSearchResponse);

  // Full-text search (BM25 scoring).
  rpc TextSearch(TextSearchRequest) returns (TextSearchResponse);

  // Hybrid search combining text and vector results with rank fusion.
  rpc HybridSearch(HybridSearchRequest) returns (HybridSearchResponse);
}

// ============================================================================
// Admin Messages
// ============================================================================

message GetGraphStatsRequest {
  string graph = 1;
}

message GetGraphStatsResponse {
  uint64 node_count = 1;
  uint64 edge_count = 2;
  uint64 label_count = 3;
  uint64 edge_type_count = 4;
  uint64 property_key_count = 5;
  uint64 index_count = 6;
  uint64 memory_bytes = 7;
  optional uint64 disk_bytes = 8;
}

message WalStatusRequest {
  string graph = 1;
}

message WalStatusResponse {
  bool enabled = 1;
  optional string path = 2;
  uint64 size_bytes = 3;
  uint64 record_count = 4;
  optional uint64 last_checkpoint = 5;
  uint64 current_epoch = 6;
}

message WalCheckpointRequest {
  string graph = 1;
}

message WalCheckpointResponse {}

message ValidateRequest {
  string graph = 1;
}

message ValidateResponse {
  bool valid = 1;
  repeated ValidationError errors = 2;
  repeated ValidationWarning warnings = 3;
}

message ValidationError {
  string code = 1;
  string message = 2;
  optional string context = 3;
}

message ValidationWarning {
  string code = 1;
  string message = 2;
  optional string context = 3;
}

message CreateIndexRequest {
  string graph = 1;
  oneof index {
    PropertyIndexDef property_index = 2;
    VectorIndexDef vector_index = 3;
    TextIndexDef text_index = 4;
  }
}

message PropertyIndexDef {
  string property = 1;
}

message VectorIndexDef {
  string label = 1;
  string property = 2;
  optional uint32 dimensions = 3;
  optional string metric = 4;      // cosine, euclidean, dot_product, manhattan
  optional uint32 m = 5;           // HNSW links per node
  optional uint32 ef_construction = 6;
}

message TextIndexDef {
  string label = 1;
  string property = 2;
}

message CreateIndexResponse {}

message DropIndexRequest {
  string graph = 1;
  oneof index {
    PropertyIndexDef property_index = 2;
    VectorIndexDef vector_index = 3;
    TextIndexDef text_index = 4;
  }
}

message DropIndexResponse {
  bool existed = 1;
}

// ============================================================================
// Search Messages
// ============================================================================

message VectorSearchRequest {
  string graph = 1;
  string label = 2;
  string property = 3;
  repeated float query_vector = 4;
  uint32 k = 5;
  optional uint32 ef = 6;
  map<string, Value> filters = 7;
}

message TextSearchRequest {
  string graph = 1;
  string label = 2;
  string property = 3;
  string query = 4;
  uint32 k = 5;
}

message HybridSearchRequest {
  string graph = 1;
  string label = 2;
  string text_property = 3;
  string vector_property = 4;
  string query_text = 5;
  repeated float query_vector = 6;
  uint32 k = 7;
}

// A single search result. node_id is an internal numeric identifier
// (not the opaque bytes element ID from the GQL type system).
message SearchHit {
  uint64 node_id = 1;
  double score = 2;
  map<string, Value> properties = 3;
}

message VectorSearchResponse {
  repeated SearchHit hits = 1;
}

message TextSearchResponse {
  repeated SearchHit hits = 1;
}

message HybridSearchResponse {
  repeated SearchHit hits = 1;
}
