syntax = "proto3";

package telemetry.v1;

option csharp_namespace = "ZB.MOM.WW.OtOpcUa.Commons.Protos.Telemetry.V1";

import "google/protobuf/timestamp.proto";

// Per-cluster mesh Phase 5: the four live-telemetry channels that used to fan out over
// DistributedPubSub (alerts / script-logs / driver-health / driver-resilience-status) now travel over
// ONE gRPC server-streaming contract. Central dials each driver node and opens Subscribe; the node
// streams its own live telemetry as a sequence of TelemetryEvent envelopes.
//
// Additive-only field evolution: never renumber or reuse a tag; a pre-field peer must read a new
// field's proto3 default correctly (that is why nullable domain fields are modelled with `optional`
// for explicit presence). Locked by the contract test in the Commons test project.
service TelemetryStreamService {
  rpc Subscribe(TelemetryStreamRequest) returns (stream TelemetryEvent);
}

message TelemetryStreamRequest {
  string correlation_id = 1;
}

message TelemetryEvent {
  string correlation_id = 1;
  oneof event {
    AlarmTransition        alarm_transition  = 2;   // <- "alerts" / AlarmTransitionEvent
    ScriptLog              script_log        = 3;   // <- "script-logs" / ScriptLogEntry
    DriverHealth           driver_health     = 4;   // <- "driver-health" / DriverHealthChanged
    DriverResilienceStatus driver_resilience = 5;   // <- "driver-resilience-status" / DriverResilienceStatusChanged
  }
}

// Mirrors ZB.MOM.WW.OtOpcUa.Commons.Messages.Alerts.AlarmTransitionEvent.
message AlarmTransition {
  string alarm_id = 1;
  string equipment_path = 2;
  string alarm_name = 3;
  string transition_kind = 4;                             // string in the record (Activated/Cleared/...); kept as string
  int32 severity = 5;
  string message = 6;
  string user = 7;
  google.protobuf.Timestamp timestamp_utc = 8;
  string alarm_type_name = 9;                             // record default "AlarmCondition"
  optional string comment = 10;                           // nullable in the record — presence distinguishes null from ""
  optional bool historize_to_aveva = 11;                  // bool? in the record — three states (null / true / false)
  repeated string referencing_equipment_paths = 12;       // null in the record is treated as empty
}

// Mirrors ZB.MOM.WW.OtOpcUa.Commons.Messages.Logging.ScriptLogEntry.
message ScriptLog {
  string script_id = 1;
  string level = 2;                                       // string in the record (Trace/Debug/Information/...); kept as string
  string message = 3;
  google.protobuf.Timestamp timestamp_utc = 4;
  optional string virtual_tag_id = 5;                     // nullable in the record
  optional string alarm_id = 6;                           // nullable in the record
  optional string equipment_id = 7;                       // nullable in the record
}

// Mirrors ZB.MOM.WW.OtOpcUa.Commons.Messages.Drivers.DriverHealthChanged.
message DriverHealth {
  string cluster_id = 1;
  string driver_instance_id = 2;
  string state = 3;                                       // DriverState-as-string in the record; kept as string
  google.protobuf.Timestamp last_successful_read_utc = 4; // DateTime? — absent Timestamp encodes null
  optional string last_error = 5;                         // nullable in the record
  int32 error_count_5min = 6;
  google.protobuf.Timestamp published_utc = 7;
  google.protobuf.Timestamp rediscovery_needed_utc = 8; // DateTime? — absent Timestamp encodes null
  optional string rediscovery_reason = 9;               // nullable in the record
}

// Mirrors ZB.MOM.WW.OtOpcUa.Commons.Messages.Drivers.DriverResilienceStatusChanged.
message DriverResilienceStatus {
  string driver_instance_id = 1;
  string host_name = 2;
  bool breaker_open = 3;
  int32 consecutive_failures = 4;
  int32 current_in_flight = 5;
  google.protobuf.Timestamp last_breaker_open_utc = 6;    // DateTime? — absent Timestamp encodes null
  google.protobuf.Timestamp last_sampled_utc = 7;
  google.protobuf.Timestamp published_utc = 8;
}
