syntax = "proto3";
package f5.nginx.agent.sdk;
option go_package = "github.com/nginx/agent/sdk/v2/proto;proto";

import "gogo.proto";
import "common.proto";
import "agent.proto";
import "host.proto";
import "nginx.proto";
import "config.proto";
import "events/event.proto";
import "dp_software_details.proto";
import "nap.proto";

// Command is the envelope sent between the management plane and the data plane, requesting some action or reporting a response
message Command {
  Metadata meta = 1 [(gogoproto.jsontag) = "meta" ];        // add metadata later with fields like timestamp etc
  
  enum CommandType {
    NORMAL = 0;
    DOWNLOAD = 1;
    UPLOAD = 2;
  }
  // used as a dispatch flag to quickly send the command to the correct base processor that will then further sort
  // based on the actual data type
  CommandType type = 2 [(gogoproto.jsontag) = "type" ];

  oneof data {
    // common command status response - used by most command responses
    CommandStatusResponse cmd_status = 3 [(gogoproto.jsontag) = "cmd_status" ];

    // request action on nginx config when sent C → A - all action values (see NgxConfig)
    // notify config details when sent  A → C - only RETURN action
    NginxConfig nginx_config = 4 [(gogoproto.jsontag) = "nginx_config" ];

    // request action on nginx config when sent C → A - all action values (see NgxConfig)
    // notify config details when sent  A → C - only RETURN action
    NginxConfigResponse nginx_config_response = 5 [(gogoproto.jsontag) = "nginx_config_response" ];

    // request connection to a management plane, A → C
    AgentConnectRequest agent_connect_request = 6 [(gogoproto.jsontag) = "agent_connect_request" ];

    // connection response to the data plane, C → A
    AgentConnectResponse agent_connect_response = 7 [(gogoproto.jsontag) = "agent_connect_response" ];

    // request Configuration parameters for agent, A → C
    AgentConfigRequest agent_config_request = 8 [(gogoproto.jsontag) = "agent_config_request" ];

    // configuration parameters for Agent C → A. This message can be sent asynchronously as well
    AgentConfig agent_config = 9 [(gogoproto.jsontag) = "agent_config" ];

    // DataplaneStatus reports Dataplane metrics the Agent is aware of
    DataplaneStatus dataplane_status = 11 [(gogoproto.jsontag) = "dataplane_status" ];

    // EventReport reports events the Agent is aware of, e.g. Start/Stop of Agent, Config Apply NGINX
    f5.nginx.agent.sdk.events.EventReport event_report = 12 [(gogoproto.jsontag) = "event_report" ];

    // DataplaneSoftwareDetails contains details for additional software running on the dataplane that pertains
    // to NGINX Agent
    DataplaneSoftwareDetails dataplane_software_details = 13 [(gogoproto.jsontag) = "dataplane_software_details"];

    // DataplaneUpdate contains details for dataplane resources that have changed
    DataplaneUpdate dataplane_update = 14 [(gogoproto.jsontag) = "dataplane_update" ];
  }
}

message CommandStatusResponse {
  enum CommandStatus {
    CMD_UNKNOWN = 0;
    CMD_OK = 1;
    CMD_ERROR = 2;
  }

  enum CommandErrorCode {
    ERR_OK = 0; // No Error
    ERR_UNKNOWN = 1; // unknown error
  }

  CommandStatus status = 1 [(gogoproto.jsontag) = "status" ];
  CommandErrorCode error_code = 2 [(gogoproto.jsontag) = "error_code" ];
  string message = 3 [(gogoproto.jsontag) = "message" ];
  string error = 4 [(gogoproto.jsontag) = "error" ];
}

// DataplaneStatus reports Dataplane metrics the Agent is aware of
message DataplaneStatus {
  string system_id = 1 [(gogoproto.jsontag) = "system_id" ];
  repeated NginxDetails details = 2 [(gogoproto.jsontag) = "details" ]; // moving to dataplane_software_details
  HostInfo host = 3 [(gogoproto.jsontag) = "host" ];
  repeated NginxHealth healths = 5 [(gogoproto.jsontag) = "healths" ]; // moving to DataplaneSoftwareHealth
  repeated DataplaneSoftwareDetails dataplane_software_details = 6 [(gogoproto.jsontag) = "dataplane_software_details"];
  repeated DataplaneSoftwareHealth dataplane_software_healths = 7 [(gogoproto.jsontag) = "dataplane_software_healths"];
  repeated AgentActivityStatus agent_activity_status = 8 [(gogoproto.jsontag) = "agent_activity_status" ];
}

message AgentActivityStatus {
    oneof Status {
        NginxConfigStatus nginx_config_status = 1 [(gogoproto.jsontag) = "nginx_config_status" ];
    }
}

message NginxConfigStatus {
  string correlation_id = 1 [(gogoproto.jsontag) = "correlation_id" ];
  Status status = 2 [(gogoproto.jsontag) = "status" ];
  string message = 3 [(gogoproto.jsontag) = "message" ];

  enum Status {
    PENDING = 0;
    OK = 1;
    ERROR = 2;
  }
}

message DataplaneSoftwareHealth {
    oneof health {
        NginxHealth nginx_health = 1 [(gogoproto.jsontag) = "nginx_health"];
        AppProtectWAFHealth app_protect_waf_health = 2 [(gogoproto.jsontag) = "app_protect_waf_health"];
    }
}

message DataplaneUpdate {
    HostInfo host = 1 [(gogoproto.jsontag) = "host"];
    repeated DataplaneSoftwareDetails dataplane_software_details = 2 [(gogoproto.jsontag) = "dataplane_software_details"];
}

message DownloadRequest {
  Metadata meta = 1 [(gogoproto.jsontag) = "meta" ];
}

message NginxConfigResponse {
  CommandStatusResponse status = 1 [(gogoproto.jsontag) = "status" ];
  NginxConfigAction action = 2 [(gogoproto.jsontag) = "action" ];
  ConfigDescriptor config_data = 3 [(gogoproto.jsontag) = "config_data" ];
}

message UploadStatus {
  enum TransferStatus {
    UNKNOWN = 0;
    OK = 1;
    FAILED = 2;
  }
  Metadata meta = 1 [(gogoproto.jsontag) = "meta" ];
  TransferStatus status = 2 [(gogoproto.jsontag) = "status" ];
  string reason = 3 [(gogoproto.jsontag) = "reason" ];
}

message DataChunk {
  oneof chunk {
    ChunkedResourceHeader header = 1 [(gogoproto.jsontag) = "header" ];
    ChunkedResourceChunk data = 2 [(gogoproto.jsontag) = "data" ];
  };
}

message ChunkedResourceHeader {
  Metadata meta = 1 [(gogoproto.jsontag) = "meta" ];
  // number of chunks expected in this transfer
  int32 chunks = 2 [(gogoproto.jsontag) = "chunks" ];
  string checksum = 3 [(gogoproto.jsontag) = "checksum" ];
  int32 chunk_size = 4 [(gogoproto.jsontag) = "chunk_size" ];
}

message ChunkedResourceChunk {
  Metadata meta = 1 [(gogoproto.jsontag) = "meta" ];
  int32 chunk_id = 2 [(gogoproto.jsontag) = "chunk_id" ];
  bytes data = 3 [(gogoproto.jsontag) = "data" ];
}
