syntax = "proto3";

package raftpb;

message RaftMessage {
    uint64 region_id = 1;
    uint64 from_peer_id = 2;
    uint64 to_peer_id = 3;
    bytes message = 4; // Serialized raft::eraftpb::Message
}

message RaftResponse {}

service RaftService {
    // Legacy raft-rs message passing
    rpc Send(RaftMessage) returns (RaftResponse);

    // OpenRaft v2 RPCs
    rpc VoteV2(OpenRaftVoteRequest) returns (OpenRaftVoteResponse);
    rpc AppendEntriesV2(OpenRaftAppendEntriesRequest) returns (OpenRaftAppendEntriesResponse);
    rpc InstallSnapshotV2(OpenRaftSnapshotRequest) returns (OpenRaftSnapshotResponse);

    // Application-level RPCs
    rpc GetMode(GetModeRequest) returns (GetModeResponse);
    rpc UpdateNamespaceMode(UpdateNamespaceModeRequest) returns (UpdateNamespaceModeResponse);
    rpc ListNamespaceModes(ListNamespaceModesRequest) returns (ListNamespaceModesResponse);
    rpc ForwardEventual(ForwardEventualRequest) returns (RaftResponse);
    rpc GetMerkle(GetMerkleRequest) returns (GetMerkleResponse);
    rpc FetchRange(FetchRangeRequest) returns (FetchRangeResponse);
}

// OpenRaft v2 messages - using serialized JSON for flexibility
message OpenRaftVoteRequest {
    uint64 region_id = 1;
    bytes data = 2; // JSON-serialized VoteRequest<FlareTypeConfig>
}

message OpenRaftVoteResponse {
    bytes data = 1; // JSON-serialized VoteResponse<FlareTypeConfig>
}

message OpenRaftAppendEntriesRequest {
    uint64 region_id = 1;
    bytes data = 2; // JSON-serialized AppendEntriesRequest<FlareTypeConfig>
}

message OpenRaftAppendEntriesResponse {
    bytes data = 1; // JSON-serialized AppendEntriesResponse<FlareTypeConfig>
}

message OpenRaftSnapshotRequest {
    uint64 region_id = 1;
    bytes vote = 2; // JSON-serialized Vote
    bytes meta = 3; // JSON-serialized SnapshotMeta
    bytes data = 4; // Snapshot data
}

message OpenRaftSnapshotResponse {
    bytes data = 1; // JSON-serialized SnapshotResponse
}

message GetModeRequest {
    string namespace = 1;
}

message GetModeResponse {
    string mode = 1; // "strong" or "eventual"
}

message UpdateNamespaceModeRequest {
    string namespace = 1;
    string mode = 2; // "strong" or "eventual"
}

message UpdateNamespaceModeResponse {
    NamespaceMode mode = 1;
}

message ListNamespaceModesRequest {}

message ListNamespaceModesResponse {
    repeated NamespaceMode namespaces = 1;
}

message NamespaceMode {
    string namespace = 1;
    uint32 id = 2;
    string mode = 3;
    bool from_default = 4; // true when created implicitly from default mode
}

message ForwardEventualRequest {
    uint64 region_id = 5;
    uint32 namespace_id = 1;
    bytes key = 2;
    bytes value = 3;
    uint64 ts = 4;
}

message GetMerkleRequest {
    uint64 region_id = 3;
    uint32 namespace_id = 1;
    uint32 chunk_size = 2; // number of keys per leaf; default server-side if zero
}

message MerkleRange {
    bytes start_key = 1;
    bytes end_key = 2;
    bytes hash = 3; // sha256
}

message GetMerkleResponse {
    bytes root = 1; // sha256 root
    repeated MerkleRange leaves = 2;
}

message FetchRangeRequest {
    uint64 region_id = 4;
    uint32 namespace_id = 1;
    bytes start_key = 2; // inclusive prefix key (namespaced)
    bytes end_key = 3;   // exclusive prefix end
}

message FetchRangeResponse {
    repeated bytes keys = 1;
    repeated bytes values = 2;
}
