syntax = "proto3";

package jammi.v1.trigger;

import "google/protobuf/timestamp.proto";

// TriggerService — primitive pub/sub over Arrow record batches.
//
// Verb vocabulary is closed: Publish, Subscribe, ListTopics. No
// domain-shaped verbs (no Discover, no Ingest*, no Run*). See ADR-01 §3.4.
service TriggerService {
  // Publish a single batch to a topic. Unary RPC.
  rpc Publish(PublishRequest) returns (PublishResponse);

  // Subscribe to a topic with an optional SQL predicate filter applied
  // server-side. Server-streaming RPC; the stream stays open until the
  // client cancels or the deadline expires.
  rpc Subscribe(SubscribeRequest) returns (stream SubscribedBatch);

  // List topics registered in the catalog. Pagination follows AIP-132.
  rpc ListTopics(ListTopicsRequest) returns (ListTopicsResponse);
}

// Topic identifier. Topics are catalog-registered (Phase 4); the name is
// a fully-qualified catalog path (e.g. "default.events.changes"). The
// engine does not interpret the path beyond catalog lookup.
message TopicName {
  string name = 1;
}

// Arrow record batch encoded as Flight IPC payload, mirroring
// arrow_flight::FlightData (data_header + data_body are both bytes).
message ArrowBatch {
  // IPC message header (Schema or RecordBatch) per Arrow's Message.fbs.
  bytes data_header = 1;
  // The actual batch of Arrow data (FlightData::data_body convention).
  bytes data_body = 2;
  // Optional application metadata; not interpreted by the engine.
  bytes app_metadata = 3;
}

message PublishRequest {
  TopicName topic = 1;
  ArrowBatch batch = 2;
  // Optional tenant scope override; if unset, the session's tenant
  // (set via SessionService.SetTenant) applies. See ADR-00 for TenantId.
  string tenant_id = 3;
}

message PublishResponse {
  // Server-assigned monotonically increasing offset within the topic.
  uint64 offset = 1;
  google.protobuf.Timestamp committed_at = 2;
}

message SubscribeRequest {
  TopicName topic = 1;
  // SQL predicate evaluated server-side against the batch schema.
  // Empty string == no filter.
  string predicate = 2;
  // Optional starting offset; 0 == from the earliest retained batch,
  // unset == from "now" (only future batches).
  optional uint64 from_offset = 3;
  // Optional tenant scope; same semantics as PublishRequest.tenant_id.
  string tenant_id = 4;
}

message SubscribedBatch {
  uint64 offset = 1;
  google.protobuf.Timestamp produced_at = 2;
  ArrowBatch batch = 3;
}

message ListTopicsRequest {
  // AIP-132 pagination.
  int32 page_size = 1;
  string page_token = 2;
  // Optional tenant scope filter.
  string tenant_id = 3;
}

message ListTopicsResponse {
  repeated TopicName topics = 1;
  string next_page_token = 2;
}
