syntax = "proto3";

package mpc.router.v1;

option go_package = "github.com/rwadurian/mpc-system/api/grpc/router/v1;router";

// MessageRouter service handles MPC message routing
// This is the ONLY service that server-parties need to connect to.
// All session operations are proxied through Message Router to Session Coordinator.
service MessageRouter {
  // ============================================
  // Message Routing
  // ============================================

  // RouteMessage routes a message from one party to others
  rpc RouteMessage(RouteMessageRequest) returns (RouteMessageResponse);

  // SubscribeMessages subscribes to messages for a party (streaming)
  rpc SubscribeMessages(SubscribeMessagesRequest) returns (stream MPCMessage);

  // GetPendingMessages retrieves pending messages (polling alternative)
  rpc GetPendingMessages(GetPendingMessagesRequest) returns (GetPendingMessagesResponse);

  // AcknowledgeMessage acknowledges receipt of a message
  // Must be called after processing a message to confirm delivery
  rpc AcknowledgeMessage(AcknowledgeMessageRequest) returns (AcknowledgeMessageResponse);

  // GetMessageStatus gets the delivery status of a message
  rpc GetMessageStatus(GetMessageStatusRequest) returns (GetMessageStatusResponse);

  // ============================================
  // Party Registration & Heartbeat
  // ============================================

  // RegisterParty registers a party with the message router (party actively connects)
  rpc RegisterParty(RegisterPartyRequest) returns (RegisterPartyResponse);

  // Heartbeat sends a heartbeat to keep the party alive
  rpc Heartbeat(HeartbeatRequest) returns (HeartbeatResponse);

  // ============================================
  // Session Events (Push from Coordinator)
  // ============================================

  // SubscribeSessionEvents subscribes to session lifecycle events (session start, etc.)
  rpc SubscribeSessionEvents(SubscribeSessionEventsRequest) returns (stream SessionEvent);

  // PublishSessionEvent publishes a session event (called by Session Coordinator)
  rpc PublishSessionEvent(PublishSessionEventRequest) returns (PublishSessionEventResponse);

  // ============================================
  // Party Discovery (for Session Coordinator)
  // ============================================

  // GetRegisteredParties returns all registered parties (for Session Coordinator party discovery)
  rpc GetRegisteredParties(GetRegisteredPartiesRequest) returns (GetRegisteredPartiesResponse);

  // ============================================
  // Session Operations (Proxied to Coordinator)
  // These allow server-parties to only connect to Message Router
  // ============================================

  // JoinSession joins a session (proxied to Session Coordinator)
  rpc JoinSession(JoinSessionRequest) returns (JoinSessionResponse);

  // MarkPartyReady marks a party as ready (proxied to Session Coordinator)
  rpc MarkPartyReady(MarkPartyReadyRequest) returns (MarkPartyReadyResponse);

  // ReportCompletion reports completion (proxied to Session Coordinator)
  rpc ReportCompletion(ReportCompletionRequest) returns (ReportCompletionResponse);

  // GetSessionStatus gets session status (proxied to Session Coordinator)
  rpc GetSessionStatus(GetSessionStatusRequest) returns (GetSessionStatusResponse);

  // SubmitDelegateShare submits user's share from delegate party (proxied to Session Coordinator)
  rpc SubmitDelegateShare(SubmitDelegateShareRequest) returns (SubmitDelegateShareResponse);
}

// RouteMessageRequest routes an MPC message
message RouteMessageRequest {
  string session_id = 1;
  string from_party = 2;
  repeated string to_parties = 3;        // Empty for broadcast
  int32 round_number = 4;
  string message_type = 5;
  bytes payload = 6;                     // Encrypted MPC message
}

// RouteMessageResponse confirms message routing
message RouteMessageResponse {
  bool success = 1;
  string message_id = 2;
}

// SubscribeMessagesRequest subscribes to messages for a party
message SubscribeMessagesRequest {
  string session_id = 1;
  string party_id = 2;
}

// MPCMessage represents an MPC protocol message
message MPCMessage {
  string message_id = 1;
  string session_id = 2;
  string from_party = 3;
  bool is_broadcast = 4;
  int32 round_number = 5;
  string message_type = 6;
  bytes payload = 7;
  int64 created_at = 8;                  // Unix timestamp milliseconds
}

// GetPendingMessagesRequest retrieves pending messages
message GetPendingMessagesRequest {
  string session_id = 1;
  string party_id = 2;
  int64 after_timestamp = 3;             // Get messages after this timestamp
}

// GetPendingMessagesResponse contains pending messages
message GetPendingMessagesResponse {
  repeated MPCMessage messages = 1;
}

// NotificationChannel represents a notification channel for offline parties
// If a party has notification channels, it operates in offline mode (24h async)
// If no notification channels, it operates in real-time mode (Message Router push)
message NotificationChannel {
  string email = 1;                          // Optional: email address for notifications
  string phone = 2;                          // Optional: phone number for SMS notifications
  string push_token = 3;                     // Optional: push notification token (FCM/APNs)
}

// RegisterPartyRequest registers a party with the router
message RegisterPartyRequest {
  string party_id = 1;                       // Unique party identifier
  string party_role = 2;                     // persistent, delegate, or temporary
  string version = 3;                        // Party software version
  NotificationChannel notification = 4;     // Optional: notification channel for offline mode
}

// RegisterPartyResponse confirms party registration
message RegisterPartyResponse {
  bool success = 1;
  string message = 2;
  int64 registered_at = 3;                   // Unix timestamp milliseconds
}

// SubscribeSessionEventsRequest subscribes to session events
message SubscribeSessionEventsRequest {
  string party_id = 1;                       // Party ID subscribing to events
  repeated string event_types = 2;           // Event types to subscribe (empty = all)
}

// SessionEvent represents a session lifecycle event
message SessionEvent {
  string event_id = 1;
  string event_type = 2;                     // session_created, session_started, etc.
  string session_id = 3;
  int32 threshold_n = 4;
  int32 threshold_t = 5;
  repeated string selected_parties = 6;       // PartyIDs selected for this session
  map<string, string> join_tokens = 7;        // PartyID -> JoinToken mapping
  bytes message_hash = 8;                     // For sign sessions
  int64 created_at = 9;                       // Unix timestamp milliseconds
  int64 expires_at = 10;                      // Unix timestamp milliseconds
  // For sign sessions with delegate party: user's share for delegate to use
  DelegateUserShare delegate_user_share = 11;
}

// DelegateUserShare contains user's share for delegate party to use in signing
message DelegateUserShare {
  string delegate_party_id = 1;              // The delegate party that will use this share
  bytes encrypted_share = 2;                 // User's encrypted share
  int32 party_index = 3;                     // Party index for this share
}

// PublishSessionEventRequest publishes a session event
message PublishSessionEventRequest {
  SessionEvent event = 1;
}

// PublishSessionEventResponse confirms event publication
message PublishSessionEventResponse {
  bool success = 1;
  int32 subscriber_count = 2;                // Number of parties that received the event
}

// GetRegisteredPartiesRequest requests registered parties list
message GetRegisteredPartiesRequest {
  string role_filter = 1;                    // Optional: filter by role (persistent, delegate, temporary)
  bool only_online = 2;                      // Optional: only return online parties
}

// RegisteredParty represents a registered party
message RegisteredParty {
  string party_id = 1;                       // Unique party identifier
  string role = 2;                           // persistent, delegate, or temporary
  bool online = 3;                           // Whether party is currently connected
  int64 registered_at = 4;                   // Unix timestamp milliseconds
  int64 last_seen_at = 5;                    // Unix timestamp milliseconds
  NotificationChannel notification = 6;     // Optional: notification channel (if set, party is offline mode)
}

// GetRegisteredPartiesResponse returns registered parties
message GetRegisteredPartiesResponse {
  repeated RegisteredParty parties = 1;
  int32 total_count = 2;
}

// AcknowledgeMessageRequest acknowledges message receipt
message AcknowledgeMessageRequest {
  string message_id = 1;                     // ID of the message being acknowledged
  string party_id = 2;                       // ID of the party acknowledging
  string session_id = 3;                     // Session the message belongs to
  bool success = 4;                          // True if message was processed successfully
  string error_message = 5;                  // Error message if processing failed
}

// AcknowledgeMessageResponse confirms acknowledgment
message AcknowledgeMessageResponse {
  bool success = 1;
  string message = 2;
}

// GetMessageStatusRequest requests message delivery status
message GetMessageStatusRequest {
  string message_id = 1;
  string session_id = 2;
}

// MessageDeliveryStatus represents delivery status to a single party
message MessageDeliveryStatus {
  string party_id = 1;
  string status = 2;                         // pending, delivered, acknowledged, failed
  int64 delivered_at = 3;                    // Unix timestamp milliseconds
  int64 acknowledged_at = 4;                 // Unix timestamp milliseconds
  int32 retry_count = 5;                     // Number of delivery retries
}

// GetMessageStatusResponse returns message delivery status
message GetMessageStatusResponse {
  string message_id = 1;
  string session_id = 2;
  repeated MessageDeliveryStatus deliveries = 3;
  bool all_acknowledged = 4;                 // True if all recipients acknowledged
}

// HeartbeatRequest sends a heartbeat to keep the party alive
message HeartbeatRequest {
  string party_id = 1;
  int64 timestamp = 2;                       // Unix timestamp milliseconds
}

// HeartbeatResponse confirms heartbeat receipt
message HeartbeatResponse {
  bool success = 1;
  int64 server_timestamp = 2;                // Server timestamp for clock sync
  int32 pending_messages = 3;                // Number of pending messages for this party
}

// ============================================
// Session Operations (Proxied to Coordinator)
// ============================================

// DeviceInfo contains device information
message DeviceInfo {
  string device_type = 1;                    // server, mobile, web
  string device_id = 2;
  string platform = 3;
  string app_version = 4;
}

// PartyInfo contains party information
message PartyInfo {
  string party_id = 1;
  int32 party_index = 2;
  DeviceInfo device_info = 3;
}

// SessionInfo contains session information
message SessionInfo {
  string session_id = 1;
  string session_type = 2;                   // keygen, sign
  int32 threshold_n = 3;
  int32 threshold_t = 4;
  bytes message_hash = 5;                    // For sign sessions
  string status = 6;
  string keygen_session_id = 7;              // For sign sessions: which keygen session's shares to use
}

// JoinSessionRequest joins a session
message JoinSessionRequest {
  string session_id = 1;
  string party_id = 2;
  string join_token = 3;
  DeviceInfo device_info = 4;
}

// JoinSessionResponse returns session info after joining
message JoinSessionResponse {
  bool success = 1;
  SessionInfo session_info = 2;
  repeated PartyInfo other_parties = 3;      // All participants in the session
  int32 party_index = 4;                     // This party's index
}

// MarkPartyReadyRequest marks a party as ready
message MarkPartyReadyRequest {
  string session_id = 1;
  string party_id = 2;
}

// MarkPartyReadyResponse confirms ready status
message MarkPartyReadyResponse {
  bool success = 1;
  bool all_ready = 2;                        // True if all parties are ready
}

// ReportCompletionRequest reports protocol completion
message ReportCompletionRequest {
  string session_id = 1;
  string party_id = 2;
  bytes public_key = 3;                      // For keygen: resulting public key
  bytes signature = 4;                       // For signing: resulting signature
}

// ReportCompletionResponse confirms completion report
message ReportCompletionResponse {
  bool success = 1;
  bool all_completed = 2;                    // True if all parties completed
}

// GetSessionStatusRequest requests session status
message GetSessionStatusRequest {
  string session_id = 1;
}

// GetSessionStatusResponse returns session status
message GetSessionStatusResponse {
  string session_id = 1;
  string status = 2;                         // created, in_progress, completed, failed, expired
  int32 threshold_n = 3;
  int32 threshold_t = 4;
  repeated PartyInfo participants = 5;
}

// SubmitDelegateShareRequest submits user's share from delegate party
message SubmitDelegateShareRequest {
  string session_id = 1;
  string party_id = 2;
  bytes encrypted_share = 3;                 // Encrypted share for user
  bytes public_key = 4;                      // Public key from keygen
  int32 party_index = 5;                     // Party's index in the session
}

// SubmitDelegateShareResponse contains result of share submission
message SubmitDelegateShareResponse {
  bool success = 1;
}
