syntax = "proto3";

package panel.v1;

option go_package = "github.com/dbledeez/panel/proto/panel/v1;panelv1";

import "google/protobuf/timestamp.proto";
import "panel/v1/agent.proto";
import "panel/v1/common.proto";

// Panel is the operator-facing API — what panelctl, the web UI, and future
// automation talk to. The controller fulfils these by forwarding commands
// to the appropriate Target agent over the Agent bidi stream.
service Panel {
  rpc ListAgents(ListAgentsRequest) returns (ListAgentsResponse);
  rpc ListInstances(ListInstancesRequest) returns (ListInstancesResponse);
  rpc CreateInstance(CreateInstanceRequest) returns (CreateInstanceResponse);
  rpc StartInstance(StartInstanceRequest) returns (StartInstanceResponse);
  rpc StopInstance(StopInstanceRequest) returns (StopInstanceResponse);
  rpc DeleteInstance(DeleteInstanceRequest) returns (DeleteInstanceResponse);
  rpc ExecRCON(ExecRCONRequest) returns (ExecRCONResponse);
  rpc UpdateInstance(UpdateInstanceRequest) returns (UpdateInstanceResponse);
  rpc CreateBackup(CreateBackupRequest) returns (CreateBackupResponse);
  rpc RestoreBackup(RestoreBackupRequest) returns (RestoreBackupResponse);
  rpc StreamEvents(StreamEventsRequest) returns (stream Event);
}

message ListAgentsRequest {}
message ListAgentsResponse {
  repeated AgentInfo agents = 1;
}

message AgentInfo {
  string agent_id = 1;
  string version = 2;
  string host_os = 3;
  string host_arch = 4;
  string hostname = 5;
  google.protobuf.Timestamp connected_at = 6;
  google.protobuf.Timestamp last_seen = 7;
}

message CreateInstanceRequest {
  string agent_id = 1;
  string instance_id = 2;
  string module_id = 3;
  string version = 4;
  RunMode run_mode = 5;
  string data_path = 6;                        // optional; agent will derive if empty
  map<string, string> config_values = 7;       // user-supplied overrides, module-validated
  repeated PortMap ports = 8;                  // port overrides
}
message CreateInstanceResponse {
  string instance_id = 1;
  string correlation_id = 2;
}

message StartInstanceRequest {
  string agent_id = 1;
  string instance_id = 2;
}
message StartInstanceResponse {
  string correlation_id = 1;
}

message StopInstanceRequest {
  string agent_id = 1;
  string instance_id = 2;
  uint32 grace_seconds = 3;
}
message StopInstanceResponse {
  string correlation_id = 1;
}

message DeleteInstanceRequest {
  string agent_id = 1;
  string instance_id = 2;
  uint32 grace_seconds = 3;
  bool purge_volumes = 4;
}
message DeleteInstanceResponse {
  string correlation_id = 1;
}

// ExecRCON sends an ad-hoc RCON command to the running instance and waits
// synchronously for the agent's response. The controller correlates the
// request → response round-trip by correlation_id.
message ExecRCONRequest {
  string agent_id = 1;
  string instance_id = 2;
  string command = 3;
  uint32 timeout_ms = 4;  // optional; default 10000
}
message ExecRCONResponse {
  string output = 1;
  string error = 2;
  string correlation_id = 3;
}

// UpdateInstance kicks off a module-declared update provider against the
// target instance. The agent runs it asynchronously; progress streams as
// LogLines on the event bus.
message UpdateInstanceRequest {
  string agent_id = 1;
  string instance_id = 2;
  string provider_id = 3;  // empty = first provider
}
message UpdateInstanceResponse {
  bool accepted = 1;
  string error = 2;
  string provider_id = 3;
  string provider_kind = 4;
  string correlation_id = 5;
}

message CreateBackupRequest {
  string agent_id = 1;
  string instance_id = 2;
  string description = 3;
}
message CreateBackupResponse {
  string backup_id = 1;
  string path = 2;
  int64 size_bytes = 3;
  string error = 4;
}

message RestoreBackupRequest {
  string agent_id = 1;
  string instance_id = 2;
  string backup_id = 3;
}
message RestoreBackupResponse {
  int64 bytes_restored = 1;
  string error = 2;
}

message InstanceInfo {
  string instance_id = 1;
  string agent_id = 2;
  string module_id = 3;
  string module_version = 4;
  RunMode run_mode = 5;
  InstanceStatus status = 6;
  int32 last_exit_code = 7;
  string data_path = 8;
  string detail = 9;
  google.protobuf.Timestamp created_at = 10;
  google.protobuf.Timestamp updated_at = 11;
}

message ListInstancesRequest {
  string agent_id = 1;  // optional filter by agent
}
message ListInstancesResponse {
  repeated InstanceInfo instances = 1;
}

// StreamEvents — server streaming of the live event bus. Filters are
// optional AND-ed; empty strings = no filter on that field.
message StreamEventsRequest {
  string instance_id = 1;
  string agent_id = 2;
}

// Event is the controller's normalized form of everything an agent sends
// up that isn't a one-shot command result. It wraps the original payload
// and annotates it with the agent_id for filtering + display.
message Event {
  string agent_id = 1;
  google.protobuf.Timestamp at = 2;
  oneof payload {
    InstanceStateUpdate instance_state = 10;
    AppStateUpdate app_state = 11;
    PlayerEvent player = 12;
    LogLine log = 13;
    InstanceStatsUpdate instance_stats = 14;
  }
}
