syntax = "proto3";

package lightningstor.node.v1;

option java_package = "com.lightningstor.node.v1";
option go_package = "lightningstor/node/v1;nodev1";

import "google/protobuf/empty.proto";

// =============================================================================
// Node Storage Service - Chunk-level operations for distributed storage
// =============================================================================

service NodeService {
    // Chunk operations
    rpc PutChunk(PutChunkRequest) returns (PutChunkResponse);
    rpc GetChunk(GetChunkRequest) returns (GetChunkResponse);
    rpc DeleteChunk(DeleteChunkRequest) returns (google.protobuf.Empty);
    rpc ChunkExists(ChunkExistsRequest) returns (ChunkExistsResponse);
    rpc ChunkSize(ChunkSizeRequest) returns (ChunkSizeResponse);

    // Health and status
    rpc Ping(PingRequest) returns (PingResponse);
    rpc GetStatus(GetStatusRequest) returns (GetStatusResponse);

    // Batch operations for efficiency
    rpc BatchPutChunks(stream PutChunkRequest) returns (BatchPutChunksResponse);
    rpc BatchGetChunks(BatchGetChunksRequest) returns (stream GetChunkResponse);
}

// =============================================================================
// Chunk Operations
// =============================================================================

message PutChunkRequest {
    // Unique identifier for the chunk
    string chunk_id = 1;
    // Shard index (for erasure coding)
    uint32 shard_index = 2;
    // Whether this is a parity shard
    bool is_parity = 3;
    // Chunk data
    bytes data = 4;
}

message PutChunkResponse {
    // Size of data stored
    uint64 size = 1;
}

message GetChunkRequest {
    string chunk_id = 1;
    uint32 shard_index = 2;
    bool is_parity = 3;
}

message GetChunkResponse {
    // Chunk data (or empty if streaming)
    bytes data = 1;
    // Size of the chunk
    uint64 size = 2;
}

message DeleteChunkRequest {
    string chunk_id = 1;
}

message ChunkExistsRequest {
    string chunk_id = 1;
}

message ChunkExistsResponse {
    bool exists = 1;
}

message ChunkSizeRequest {
    string chunk_id = 1;
}

message ChunkSizeResponse {
    // Size in bytes, or 0 if not found
    uint64 size = 1;
    bool exists = 2;
}

// =============================================================================
// Health and Status
// =============================================================================

message PingRequest {}

message PingResponse {
    // Round-trip time in microseconds (server processing time)
    uint64 latency_us = 1;
}

message GetStatusRequest {}

message GetStatusResponse {
    // Node identifier
    string node_id = 1;
    // Endpoint address
    string endpoint = 2;
    // Zone/rack for placement
    string zone = 3;
    // Region
    string region = 4;
    // Storage capacity in bytes
    uint64 capacity_bytes = 5;
    // Used storage in bytes
    uint64 used_bytes = 6;
    // Number of chunks stored
    uint64 chunk_count = 7;
    // Node is healthy and accepting requests
    bool healthy = 8;
    // Uptime in seconds
    uint64 uptime_seconds = 9;
}

// =============================================================================
// Batch Operations
// =============================================================================

message BatchPutChunksResponse {
    // Number of chunks successfully stored
    uint32 success_count = 1;
    // Number of chunks that failed
    uint32 failure_count = 2;
    // Error messages for failed chunks
    repeated string errors = 3;
}

message BatchGetChunksRequest {
    repeated GetChunkRequest chunks = 1;
}
