syntax = "proto3";

package messages;

option go_package = "git.tornberg.me/go-cart-actor/proto;messages";

// -----------------------------------------------------------------------------
// Control Plane gRPC API
// -----------------------------------------------------------------------------
// Replaces the legacy custom frame-based control channel (previously port 1338).
// Responsibilities:
//   - Liveness (Ping)
//   - Membership negotiation (Negotiate)
//   - Deterministic ring-based ownership (ConfirmOwner RPC removed)
//   - Actor ID listing for remote grain spawning (GetActorIds)
//   - Graceful shutdown notifications (Closing)
// No authentication / TLS is defined initially (can be added later).
// -----------------------------------------------------------------------------

// Empty request placeholder (common pattern).
message Empty {}

// Ping reply includes responding host and its current unix time (seconds).
message PingReply {
  string host = 1;
  int64 unix_time = 2;
}

// NegotiateRequest carries the caller's full view of known hosts (including self).
message NegotiateRequest {
  repeated string known_hosts = 1;
}

// NegotiateReply returns the callee's healthy hosts (including itself).
message NegotiateReply {
  repeated string hosts = 1;
}

// CartIdsReply returns the list of cart IDs (string form) currently owned locally.
message ActorIdsReply {
  repeated uint64 ids = 1;
}

// OwnerChangeAck retained as response type for Closing RPC (ConfirmOwner removed).
message OwnerChangeAck {
  bool accepted = 1;
  string message = 2;
}

// ClosingNotice notifies peers this host is terminating (so they can drop / re-resolve).
message ClosingNotice {
  string host = 1;
}

// OwnershipAnnounce broadcasts first-touch ownership claims for cart IDs.
// First claim wins; receivers SHOULD NOT overwrite an existing different owner.
message OwnershipAnnounce {
  string host = 1;               // announcing host
  repeated uint64 ids = 2;   // newly claimed cart ids
}

// ExpiryAnnounce broadcasts that a host evicted the provided cart IDs.
message ExpiryAnnounce {
  string host = 1;
  repeated uint64 ids = 2;
}

// ControlPlane defines cluster coordination and ownership operations.
service ControlPlane {
  // Ping for liveness; lightweight health signal.
  rpc Ping(Empty) returns (PingReply);

  // Negotiate merges host views; used during discovery & convergence.
  rpc Negotiate(NegotiateRequest) returns (NegotiateReply);

  // GetCartIds lists currently owned cart IDs on this node.
  rpc GetLocalActorIds(Empty) returns (ActorIdsReply);

  // ConfirmOwner RPC removed (was legacy ownership acknowledgement; ring-based ownership now authoritative)

  // Ownership announcement: first-touch claim broadcast (idempotent; best-effort).
  rpc AnnounceOwnership(OwnershipAnnounce) returns (OwnerChangeAck);

  // Expiry announcement: drop remote ownership hints when local TTL expires.
  rpc AnnounceExpiry(ExpiryAnnounce) returns (OwnerChangeAck);

  // Closing announces graceful shutdown so peers can proactively adjust.
  rpc Closing(ClosingNotice) returns (OwnerChangeAck);
}

// -----------------------------------------------------------------------------
// Generation Instructions:
// protoc --go_out=. --go_opt=paths=source_relative \
//        --go-grpc_out=. --go-grpc_opt=paths=source_relative \
//        control_plane.proto
//
// Future Enhancements:
//  - Add a streaming membership watch (server -> client) for immediate updates.
//  - Add TLS / mTLS for secure intra-cluster communication.
//  - Add richer health metadata (load, grain count) in PingReply.
// -----------------------------------------------------------------------------
