syntax = "proto3";

// The histogram service definition.
service HistogrammerService {
  // Sends a histogram initialization request
  rpc Init(InitRequest) returns (InitResponse) {}
  // Sends a filling request
  rpc Fill(FillRequest) returns (FillResponse) {}
  // Sends a snapshot request of the current histogram
  rpc SnapShot(SnapShotRequest) returns (SnapShotResponse) {}
  // Sends a flushing request (to disk)
  rpc Flush(FlushRequest) returns (FlushResponse) {}
}

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

// The response message
message InitResponse {
  bool success = 1; // indicates if the operation was successful
  string message = 2; // additional information or error message
}

// The request message containing the values to fill the histogram.
// This map is essentially **kwargs that is passed to histogram.fill(**kwargs)
message FillRequest {
  string hist_id = 1;
  map<string, Value> kwargs = 2;
}

// The response messages
message FillResponse {
  bool success = 1; // indicates if the operation was successful
  string message = 2; // additional information or error message
}

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

// The response message
message SnapShotResponse {
  bool success = 1; // indicates if the operation was successful
  string message = 2; // additional information or error message

  // this can only be returned is success is True
  string hist_json = 3;
  map<string, Value> data = 4;
}

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

// is there a better way to re-use the result messages?
message FlushResponse {
  bool success = 1; // indicates if the operation was successful
  string message = 2; // additional information or error message
}

// 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)
  }
}
