syntax = "proto3";

package hc900;

import "google/protobuf/timestamp.proto";

option csharp_namespace = "Hc900.Gateway";

// ─── Data types ───

message TagValue {
  string tag_name = 1;
  oneof value {
    float  float32_val = 2;
    uint32 uint16_val  = 3;
  }
  uint32 quality      = 4;  // 192=good, 0=bad
  google.protobuf.Timestamp timestamp = 5;
}

message TagMetadata {
  string tag_name   = 1;
  uint32 address    = 2;
  uint32 count      = 3;  // register count (1 for uint16, 2 for float32)
  string type       = 4;  // "float32" or "uint16"
  string access     = 5;  // "R" or "RW"
  string description = 6;
  string eu          = 7;  // engineering unit
}

// ─── Read ───

message ReadTagsRequest {
  repeated string tag_names = 1;  // empty means "all cached"
}

message ReadTagsResponse {
  repeated TagValue values = 1;
  bool from_cache = 2;
}

// ─── Write ───

message WriteTagRequest {
  string tag_name = 1;
  double value    = 2;     // always sent as double; gateway casts to float32 or uint16
}

message WriteTagResponse {
  bool   success = 1;
  string error   = 2;
}

// ─── Stream (real-time) ───

message StreamTagsRequest {
  int32  interval_ms = 1;  // 0 = push on every poll
  repeated string tag_names = 2;  // empty = all
}

// ─── Metadata ───

message ListTagsRequest {
  string filter = 1;  // tag name prefix match, empty = all
  int32  limit  = 2;  // 0 = unlimited
}

message ListTagsResponse {
  repeated TagMetadata tags = 1;
}

// ─── Health ───

message HealthCheckRequest {}

message HealthCheckResponse {
  enum ServingStatus {
    UNKNOWN = 0;
    SERVING = 1;
    NOT_SERVING = 2;
  }
  ServingStatus status      = 1;
  double        uptime_sec  = 2;
  uint64        poll_count  = 3;
  double        last_poll_ms = 4;  // duration of last full poll in ms
  string        controller_ip = 5;
  uint32        active_tags   = 6;
}

// ─── Service ───

service ModbusGateway {
  rpc ReadTags(ReadTagsRequest) returns (ReadTagsResponse);
  rpc WriteTag(WriteTagRequest) returns (WriteTagResponse);
  rpc StreamTags(StreamTagsRequest) returns (stream TagValue);
  rpc ListTags(ListTagsRequest) returns (ListTagsResponse);
  rpc HealthCheck(HealthCheckRequest) returns (HealthCheckResponse);
}
