syntax = "proto3";

package lightningstor.v1;

option java_package = "com.lightningstor.v1";
option go_package = "lightningstor/v1;lightningstorv1";

import "google/protobuf/timestamp.proto";
import "google/protobuf/empty.proto";

// =============================================================================
// Object Service - Core object operations
// =============================================================================

service ObjectService {
    // Object operations
    rpc PutObject(PutObjectRequest) returns (PutObjectResponse);
    rpc GetObject(GetObjectRequest) returns (stream GetObjectResponse);
    rpc DeleteObject(DeleteObjectRequest) returns (DeleteObjectResponse);
    rpc HeadObject(HeadObjectRequest) returns (HeadObjectResponse);
    rpc CopyObject(CopyObjectRequest) returns (CopyObjectResponse);

    // Listing
    rpc ListObjects(ListObjectsRequest) returns (ListObjectsResponse);
    rpc ListObjectVersions(ListObjectVersionsRequest) returns (ListObjectVersionsResponse);

    // Multipart uploads
    rpc CreateMultipartUpload(CreateMultipartUploadRequest) returns (CreateMultipartUploadResponse);
    rpc UploadPart(stream UploadPartRequest) returns (UploadPartResponse);
    rpc CompleteMultipartUpload(CompleteMultipartUploadRequest) returns (CompleteMultipartUploadResponse);
    rpc AbortMultipartUpload(AbortMultipartUploadRequest) returns (google.protobuf.Empty);
    rpc ListParts(ListPartsRequest) returns (ListPartsResponse);
    rpc ListMultipartUploads(ListMultipartUploadsRequest) returns (ListMultipartUploadsResponse);
}

// =============================================================================
// Bucket Service - Bucket management
// =============================================================================

service BucketService {
    rpc CreateBucket(CreateBucketRequest) returns (CreateBucketResponse);
    rpc DeleteBucket(DeleteBucketRequest) returns (google.protobuf.Empty);
    rpc HeadBucket(HeadBucketRequest) returns (HeadBucketResponse);
    rpc ListBuckets(ListBucketsRequest) returns (ListBucketsResponse);

    // Bucket configuration
    rpc GetBucketVersioning(GetBucketVersioningRequest) returns (GetBucketVersioningResponse);
    rpc PutBucketVersioning(PutBucketVersioningRequest) returns (google.protobuf.Empty);
    rpc GetBucketPolicy(GetBucketPolicyRequest) returns (GetBucketPolicyResponse);
    rpc PutBucketPolicy(PutBucketPolicyRequest) returns (google.protobuf.Empty);
    rpc DeleteBucketPolicy(DeleteBucketPolicyRequest) returns (google.protobuf.Empty);

    // Tagging
    rpc GetBucketTagging(GetBucketTaggingRequest) returns (GetBucketTaggingResponse);
    rpc PutBucketTagging(PutBucketTaggingRequest) returns (google.protobuf.Empty);
    rpc DeleteBucketTagging(DeleteBucketTaggingRequest) returns (google.protobuf.Empty);
}

// =============================================================================
// Common Types
// =============================================================================

message ObjectMetadata {
    string content_type = 1;
    string content_encoding = 2;
    string content_disposition = 3;
    string content_language = 4;
    string cache_control = 5;
    map<string, string> user_metadata = 6;
}

message ObjectInfo {
    string key = 1;
    string etag = 2;
    uint64 size = 3;
    google.protobuf.Timestamp last_modified = 4;
    string storage_class = 5;
    string version_id = 6;
    bool is_latest = 7;
    ObjectMetadata metadata = 8;
}

message BucketInfo {
    string name = 1;
    string id = 2;
    string region = 3;
    google.protobuf.Timestamp created_at = 4;
    string org_id = 5;
    string project_id = 6;
}

message Tag {
    string key = 1;
    string value = 2;
}

message PartInfo {
    uint32 part_number = 1;
    string etag = 2;
    uint64 size = 3;
    google.protobuf.Timestamp last_modified = 4;
}

message CompletedPart {
    uint32 part_number = 1;
    string etag = 2;
}

// =============================================================================
// Object Operations - Requests & Responses
// =============================================================================

message PutObjectRequest {
    string bucket = 1;
    string key = 2;
    bytes body = 3;
    ObjectMetadata metadata = 4;
    string content_md5 = 5;
    // Conditional writes
    string if_none_match = 6;  // * to prevent overwrite
}

message PutObjectResponse {
    string etag = 1;
    string version_id = 2;
}

message GetObjectRequest {
    string bucket = 1;
    string key = 2;
    string version_id = 3;
    // Range request
    int64 range_start = 4;
    int64 range_end = 5;
    // Conditional gets
    string if_match = 6;
    string if_none_match = 7;
    google.protobuf.Timestamp if_modified_since = 8;
    google.protobuf.Timestamp if_unmodified_since = 9;
}

message GetObjectResponse {
    // First message contains metadata, subsequent messages contain body chunks
    oneof content {
        ObjectInfo metadata = 1;
        bytes body_chunk = 2;
    }
}

message DeleteObjectRequest {
    string bucket = 1;
    string key = 2;
    string version_id = 3;
}

message DeleteObjectResponse {
    bool delete_marker = 1;
    string version_id = 2;
}

message HeadObjectRequest {
    string bucket = 1;
    string key = 2;
    string version_id = 3;
}

message HeadObjectResponse {
    ObjectInfo object = 1;
}

message CopyObjectRequest {
    string source_bucket = 1;
    string source_key = 2;
    string source_version_id = 3;
    string dest_bucket = 4;
    string dest_key = 5;
    ObjectMetadata metadata = 6;
    bool metadata_directive_replace = 7;
}

message CopyObjectResponse {
    string etag = 1;
    string version_id = 2;
    google.protobuf.Timestamp last_modified = 3;
}

// =============================================================================
// Listing Operations
// =============================================================================

message ListObjectsRequest {
    string bucket = 1;
    string prefix = 2;
    string delimiter = 3;
    string start_after = 4;
    string continuation_token = 5;
    uint32 max_keys = 6;
}

message ListObjectsResponse {
    repeated ObjectInfo objects = 1;
    repeated string common_prefixes = 2;
    bool is_truncated = 3;
    string next_continuation_token = 4;
    uint32 key_count = 5;
}

message ListObjectVersionsRequest {
    string bucket = 1;
    string prefix = 2;
    string delimiter = 3;
    string key_marker = 4;
    string version_id_marker = 5;
    uint32 max_keys = 6;
}

message ListObjectVersionsResponse {
    repeated ObjectInfo versions = 1;
    repeated DeleteMarkerEntry delete_markers = 2;
    repeated string common_prefixes = 3;
    bool is_truncated = 4;
    string next_key_marker = 5;
    string next_version_id_marker = 6;
}

message DeleteMarkerEntry {
    string key = 1;
    string version_id = 2;
    bool is_latest = 3;
    google.protobuf.Timestamp last_modified = 4;
}

// =============================================================================
// Multipart Upload Operations
// =============================================================================

message CreateMultipartUploadRequest {
    string bucket = 1;
    string key = 2;
    ObjectMetadata metadata = 3;
}

message CreateMultipartUploadResponse {
    string bucket = 1;
    string key = 2;
    string upload_id = 3;
}

message UploadPartRequest {
    // First message must contain metadata
    string bucket = 1;
    string key = 2;
    string upload_id = 3;
    uint32 part_number = 4;
    bytes body = 5;
    string content_md5 = 6;
}

message UploadPartResponse {
    string etag = 1;
}

message CompleteMultipartUploadRequest {
    string bucket = 1;
    string key = 2;
    string upload_id = 3;
    repeated CompletedPart parts = 4;
}

message CompleteMultipartUploadResponse {
    string bucket = 1;
    string key = 2;
    string etag = 3;
    string version_id = 4;
}

message AbortMultipartUploadRequest {
    string bucket = 1;
    string key = 2;
    string upload_id = 3;
}

message ListPartsRequest {
    string bucket = 1;
    string key = 2;
    string upload_id = 3;
    uint32 part_number_marker = 4;
    uint32 max_parts = 5;
}

message ListPartsResponse {
    string bucket = 1;
    string key = 2;
    string upload_id = 3;
    repeated PartInfo parts = 4;
    bool is_truncated = 5;
    uint32 next_part_number_marker = 6;
}

message ListMultipartUploadsRequest {
    string bucket = 1;
    string prefix = 2;
    string delimiter = 3;
    string key_marker = 4;
    string upload_id_marker = 5;
    uint32 max_uploads = 6;
}

message ListMultipartUploadsResponse {
    string bucket = 1;
    repeated MultipartUploadInfo uploads = 2;
    repeated string common_prefixes = 3;
    bool is_truncated = 4;
    string next_key_marker = 5;
    string next_upload_id_marker = 6;
}

message MultipartUploadInfo {
    string key = 1;
    string upload_id = 2;
    google.protobuf.Timestamp initiated = 3;
}

// =============================================================================
// Bucket Operations - Requests & Responses
// =============================================================================

message CreateBucketRequest {
    string bucket = 1;
    string region = 2;
    string org_id = 3;
    string project_id = 4;
}

message CreateBucketResponse {
    BucketInfo bucket = 1;
}

message DeleteBucketRequest {
    string bucket = 1;
}

message HeadBucketRequest {
    string bucket = 1;
}

message HeadBucketResponse {
    BucketInfo bucket = 1;
}

message ListBucketsRequest {
    string org_id = 1;
    string project_id = 2;
    string prefix = 3;
    uint32 max_buckets = 4;
    string continuation_token = 5;
}

message ListBucketsResponse {
    repeated BucketInfo buckets = 1;
    bool is_truncated = 2;
    string next_continuation_token = 3;
}

// =============================================================================
// Bucket Configuration
// =============================================================================

message GetBucketVersioningRequest {
    string bucket = 1;
}

message GetBucketVersioningResponse {
    string status = 1;  // Enabled, Suspended, or empty
}

message PutBucketVersioningRequest {
    string bucket = 1;
    string status = 2;  // Enabled or Suspended
}

message GetBucketPolicyRequest {
    string bucket = 1;
}

message GetBucketPolicyResponse {
    string policy = 1;  // JSON policy document
}

message PutBucketPolicyRequest {
    string bucket = 1;
    string policy = 2;  // JSON policy document
}

message DeleteBucketPolicyRequest {
    string bucket = 1;
}

// =============================================================================
// Bucket Tagging
// =============================================================================

message GetBucketTaggingRequest {
    string bucket = 1;
}

message GetBucketTaggingResponse {
    repeated Tag tags = 1;
}

message PutBucketTaggingRequest {
    string bucket = 1;
    repeated Tag tags = 2;
}

message DeleteBucketTaggingRequest {
    string bucket = 1;
}
