syntax = "proto3";

import "google/protobuf/timestamp.proto";

// The histogram service definition.
service HistogrammerService {
  // Sends a histogram initialization request
  rpc Init(InitRequest) returns (InitResponse) {}
  // Returns histogram metadata for reconnecting fill clients
  rpc Describe(DescribeRequest) returns (DescribeResponse) {}
  // Checks whether a histogram exists and is accessible
  rpc Exists(ExistsRequest) returns (ExistsResponse) {}
  // Sends a filling request
  rpc Fill(FillRequest) returns (FillResponse) {}
  // Sends a snapshot request of the current histogram
  rpc Snapshot(SnapshotRequest) returns (SnapshotResponse) {}
  // Deletes a histogram from the server
  rpc Delete(DeleteRequest) returns (DeleteResponse) {}
  // Resets a histogram on the server
  rpc Reset(ResetRequest) returns (ResetResponse) {}
  // Sends a flushing request (to disk)
  rpc Flush(FlushRequest) returns (FlushResponse) {}
  // Returns a point-in-time snapshot of server stats
  rpc Stats(StatsRequest) returns (StatsResponse) {}
}

// This request sends JSON payload to initialize the histogram on the server
message InitRequest {
  string hist_json = 1;
}

// The response message
message InitResponse {
  string hist_id = 1;
}

message DescribeRequest {
  string hist_id = 1;
}

message DescribeResponse {
  string hist_json = 1;
}

message ExistsRequest {
  string hist_id = 1;
}

message ExistsResponse {
  bool exists = 1;
}

// The request message containing the pre-binned values to merge into a chunk.
message FillRequest {
  string hist_id = 1;
  optional bytes unique_id = 2;
  map<string, Value> chunk_key = 3;
  map<string, Value> dense_storage = 4;
}

message FillResponse {}

// This request sends JSON payload to initialize the histogram on the server
message SnapshotRequest {
  string hist_id = 1;
  bool delete_from_server = 2;
}

// The response message
message SnapshotResponse {
  string hist_json = 1;
  map<string, Value> data = 2;
}

message DeleteRequest {
  string hist_id = 1;
}

message DeleteResponse {}

message ResetRequest {
  string hist_id = 1;
}

message ResetResponse {}

// The request message for flushing the histogram.
message FlushRequest {
  string hist_id = 1;
  string destination = 2; // where to flush the histogram data
}

message FlushResponse {}

message StatsRequest {}

message StatsResponse {
  uint64 histogram_count = 1;
  uint64 histogram_bytes = 2;
  uint64 active_rpcs = 3;
  string version = 4;
  uint64 uptime_seconds = 5;
  double user_cpu_seconds = 6;
  double system_cpu_seconds = 7;
  map<string, uint64> rpc_calls_total = 8;
  google.protobuf.Timestamp observed_at = 9;
  TokenScopedStats token_scoped = 10;
}

message TokenScopedStats {
  uint64 histogram_count = 1;
  uint64 histogram_bytes = 2;
  map<string, uint64> rpc_calls_total = 3;
}

// Data type representation (just a small subset for now)
message Dtype {
  enum Type {
    // add more types as needed
    TYPE_DT_FLOAT32 = 0;
    TYPE_DT_FLOAT64 = 1;
    TYPE_DT_INT32 = 2;
    TYPE_DT_INT64 = 3;
  }

  Type type = 2;
}

// A simple representation of a NumPy ndarray (we're ignoring endianness and other complexities for brevity)
message Ndarray {
  repeated int64 shape = 1;
  Dtype dtype = 2;
  bytes data = 3;
}

message Value {
  oneof value {
    Ndarray array_value = 1; // for array values (e.g., regular/variable/integer axes)
    string string_value = 2; // for string values (e.g., str category axes)
    int64 int_value = 3; // for integer values (e.g., int category axes)
    bool bool_value = 4; // for boolean values (e.g., boolean axes axes)
  }
}
