syntax = "proto3";

package plasmavmc.v1;

option go_package = "plasmavmc/v1;plasmavmcv1";

// ============================================================================
// VM Service
// ============================================================================

service VmService {
  // Lifecycle
  rpc CreateVm(CreateVmRequest) returns (VirtualMachine);
  rpc GetVm(GetVmRequest) returns (VirtualMachine);
  rpc ListVms(ListVmsRequest) returns (ListVmsResponse);
  rpc UpdateVm(UpdateVmRequest) returns (VirtualMachine);
  rpc DeleteVm(DeleteVmRequest) returns (Empty);

  // Power operations
  rpc StartVm(StartVmRequest) returns (VirtualMachine);
  rpc StopVm(StopVmRequest) returns (VirtualMachine);
  rpc RebootVm(RebootVmRequest) returns (VirtualMachine);
  rpc ResetVm(ResetVmRequest) returns (VirtualMachine);
  rpc MigrateVm(MigrateVmRequest) returns (VirtualMachine);
  // Internal node-to-node RPC used by the control plane when staging a migration target.
  rpc PrepareVmMigration(PrepareVmMigrationRequest) returns (VirtualMachine);
  rpc RecoverVm(RecoverVmRequest) returns (VirtualMachine);

  // Disk operations
  rpc AttachDisk(AttachDiskRequest) returns (VirtualMachine);
  rpc DetachDisk(DetachDiskRequest) returns (VirtualMachine);

  // Network operations
  rpc AttachNic(AttachNicRequest) returns (VirtualMachine);
  rpc DetachNic(DetachNicRequest) returns (VirtualMachine);

  // Events
  rpc WatchVm(WatchVmRequest) returns (stream VmEvent);
}

// ============================================================================
// Image Service
// ============================================================================

service ImageService {
  rpc CreateImage(CreateImageRequest) returns (Image);
  rpc BeginImageUpload(BeginImageUploadRequest) returns (BeginImageUploadResponse);
  rpc UploadImagePart(UploadImagePartRequest) returns (UploadImagePartResponse);
  rpc CompleteImageUpload(CompleteImageUploadRequest) returns (Image);
  rpc AbortImageUpload(AbortImageUploadRequest) returns (Empty);
  rpc GetImage(GetImageRequest) returns (Image);
  rpc ListImages(ListImagesRequest) returns (ListImagesResponse);
  rpc UpdateImage(UpdateImageRequest) returns (Image);
  rpc DeleteImage(DeleteImageRequest) returns (Empty);
}

// ============================================================================
// Volume Service
// ============================================================================

service VolumeService {
  rpc CreateVolume(CreateVolumeRequest) returns (Volume);
  rpc GetVolume(GetVolumeRequest) returns (Volume);
  rpc ListVolumes(ListVolumesRequest) returns (ListVolumesResponse);
  rpc DeleteVolume(DeleteVolumeRequest) returns (Empty);
  rpc ResizeVolume(ResizeVolumeRequest) returns (Volume);
  rpc RegisterExternalVolume(RegisterExternalVolumeRequest) returns (Volume);
}

// ============================================================================
// Node Service
// ============================================================================

service NodeService {
  rpc ListNodes(ListNodesRequest) returns (ListNodesResponse);
  rpc GetNode(GetNodeRequest) returns (Node);
  rpc CordonNode(CordonNodeRequest) returns (Node);
  rpc UncordonNode(UncordonNodeRequest) returns (Node);
  rpc DrainNode(DrainNodeRequest) returns (Node);
  rpc HeartbeatNode(HeartbeatNodeRequest) returns (Node);
}

// ============================================================================
// Common Messages
// ============================================================================

message Empty {}

// ============================================================================
// VM Messages
// ============================================================================

message VirtualMachine {
  string id = 1;
  string name = 2;
  string org_id = 3;
  string project_id = 4;
  VmState state = 5;
  VmSpec spec = 6;
  VmStatus status = 7;
  string node_id = 8;
  HypervisorType hypervisor = 9;
  int64 created_at = 10;
  int64 updated_at = 11;
  string created_by = 12;
  map<string, string> metadata = 13;
  map<string, string> labels = 14;
}

enum VmState {
  VM_STATE_UNSPECIFIED = 0;
  VM_STATE_PENDING = 1;
  VM_STATE_CREATING = 2;
  VM_STATE_STOPPED = 3;
  VM_STATE_STARTING = 4;
  VM_STATE_RUNNING = 5;
  VM_STATE_STOPPING = 6;
  VM_STATE_MIGRATING = 7;
  VM_STATE_ERROR = 8;
  VM_STATE_FAILED = 9;
  VM_STATE_DELETED = 10;
}

enum HypervisorType {
  HYPERVISOR_TYPE_UNSPECIFIED = 0;
  HYPERVISOR_TYPE_KVM = 1;
  HYPERVISOR_TYPE_FIRECRACKER = 2;
  HYPERVISOR_TYPE_MVISOR = 3;
}

message VmSpec {
  CpuSpec cpu = 1;
  MemorySpec memory = 2;
  repeated DiskSpec disks = 3;
  repeated NetworkSpec network = 4;
  BootSpec boot = 5;
  SecuritySpec security = 6;
}

message CpuSpec {
  uint32 vcpus = 1;
  uint32 cores_per_socket = 2;
  uint32 sockets = 3;
  string cpu_model = 4;
}

message MemorySpec {
  uint64 size_mib = 1;
  bool hugepages = 2;
}

message DiskSpec {
  string id = 1;
  DiskSource source = 2;
  uint64 size_gib = 3;
  DiskBus bus = 4;
  DiskCache cache = 5;
  uint32 boot_index = 6;
}

message DiskSource {
  oneof source {
    string image_id = 1;
    string volume_id = 2;
    bool blank = 3;
  }
}

enum DiskBus {
  DISK_BUS_UNSPECIFIED = 0;
  DISK_BUS_VIRTIO = 1;
  DISK_BUS_SCSI = 2;
  DISK_BUS_IDE = 3;
  DISK_BUS_SATA = 4;
}

enum DiskCache {
  DISK_CACHE_UNSPECIFIED = 0;
  DISK_CACHE_NONE = 1;
  DISK_CACHE_WRITEBACK = 2;
  DISK_CACHE_WRITETHROUGH = 3;
}

enum VolumeDriverKind {
  VOLUME_DRIVER_KIND_UNSPECIFIED = 0;
  VOLUME_DRIVER_KIND_MANAGED = 1;
  VOLUME_DRIVER_KIND_CEPH_RBD = 2;
}

enum VolumeFormat {
  VOLUME_FORMAT_UNSPECIFIED = 0;
  VOLUME_FORMAT_RAW = 1;
  VOLUME_FORMAT_QCOW2 = 2;
}

enum VolumeStatus {
  VOLUME_STATUS_UNSPECIFIED = 0;
  VOLUME_STATUS_PENDING = 1;
  VOLUME_STATUS_AVAILABLE = 2;
  VOLUME_STATUS_IN_USE = 3;
  VOLUME_STATUS_ERROR = 4;
}

message NetworkSpec {
  string id = 1;
  string network_id = 2;
  string mac_address = 3;
  string ip_address = 4;
  NicModel model = 5;
  repeated string security_groups = 6;
  string port_id = 7;  // PrismNET port ID for OVN integration
  string subnet_id = 8;  // PrismNET subnet ID for OVN integration
  string cidr_block = 9;  // Effective subnet CIDR for the realized dataplane
  string gateway_ip = 10;  // Effective subnet gateway for the realized dataplane
  bool dhcp_enabled = 11;
}

enum NicModel {
  NIC_MODEL_UNSPECIFIED = 0;
  NIC_MODEL_VIRTIO_NET = 1;
  NIC_MODEL_E1000 = 2;
}

message BootSpec {
  string kernel = 1;
  string initrd = 2;
  string cmdline = 3;
}

message SecuritySpec {
  bool secure_boot = 1;
  bool tpm = 2;
}

message VmStatus {
  VmState actual_state = 1;
  uint32 host_pid = 2;
  int64 started_at = 3;
  repeated string ip_addresses = 4;
  ResourceUsage resource_usage = 5;
  string last_error = 6;
}

message ResourceUsage {
  double cpu_percent = 1;
  uint64 memory_used_mib = 2;
  uint64 disk_read_bytes = 3;
  uint64 disk_write_bytes = 4;
  uint64 network_rx_bytes = 5;
  uint64 network_tx_bytes = 6;
}

// VM migration request
message MigrateVmRequest {
  string org_id = 1;
  string project_id = 2;
  string vm_id = 3;
  // Destination worker node identifier
  string destination_node_id = 4;
  // Optional timeout (seconds). 0 = server default
  uint32 timeout_seconds = 5;
  // If true, wait until migration completes
  bool wait = 6;
}

message PrepareVmMigrationRequest {
  string org_id = 1;
  string project_id = 2;
  string vm_id = 3;
  VmSpec spec = 4;
  HypervisorType hypervisor = 5;
  // QEMU incoming listen URI (e.g., tcp:0.0.0.0:4444)
  string listen_uri = 6;
  map<string, string> metadata = 7;
  map<string, string> labels = 8;
  string name = 9;
}

message RecoverVmRequest {
  string org_id = 1;
  string project_id = 2;
  string vm_id = 3;
  string name = 4;
  VmSpec spec = 5;
  HypervisorType hypervisor = 6;
  map<string, string> metadata = 7;
  map<string, string> labels = 8;
  bool start = 9;
}

// VM Service Requests
message CreateVmRequest {
  string name = 1;
  string org_id = 2;
  string project_id = 3;
  VmSpec spec = 4;
  HypervisorType hypervisor = 5;
  map<string, string> metadata = 6;
  map<string, string> labels = 7;
}

message GetVmRequest {
  string org_id = 1;
  string project_id = 2;
  string vm_id = 3;
}

message ListVmsRequest {
  string org_id = 1;
  string project_id = 2;
  int32 page_size = 3;
  string page_token = 4;
  string filter = 5;
}

message ListVmsResponse {
  repeated VirtualMachine vms = 1;
  string next_page_token = 2;
}

message UpdateVmRequest {
  string org_id = 1;
  string project_id = 2;
  string vm_id = 3;
  VmSpec spec = 4;
  map<string, string> metadata = 5;
  map<string, string> labels = 6;
}

message DeleteVmRequest {
  string org_id = 1;
  string project_id = 2;
  string vm_id = 3;
  bool force = 4;
}

message StartVmRequest {
  string org_id = 1;
  string project_id = 2;
  string vm_id = 3;
}

message StopVmRequest {
  string org_id = 1;
  string project_id = 2;
  string vm_id = 3;
  bool force = 4;
  uint32 timeout_seconds = 5;
}

message RebootVmRequest {
  string org_id = 1;
  string project_id = 2;
  string vm_id = 3;
}

message ResetVmRequest {
  string org_id = 1;
  string project_id = 2;
  string vm_id = 3;
}

message AttachDiskRequest {
  string org_id = 1;
  string project_id = 2;
  string vm_id = 3;
  DiskSpec disk = 4;
}

message DetachDiskRequest {
  string org_id = 1;
  string project_id = 2;
  string vm_id = 3;
  string disk_id = 4;
}

message AttachNicRequest {
  string org_id = 1;
  string project_id = 2;
  string vm_id = 3;
  NetworkSpec nic = 4;
}

message DetachNicRequest {
  string org_id = 1;
  string project_id = 2;
  string vm_id = 3;
  string nic_id = 4;
}

message WatchVmRequest {
  string org_id = 1;
  string project_id = 2;
  string vm_id = 3;
}

message VmEvent {
  string vm_id = 1;
  VmEventType event_type = 2;
  VirtualMachine vm = 3;
  int64 timestamp = 4;
}

enum VmEventType {
  VM_EVENT_TYPE_UNSPECIFIED = 0;
  VM_EVENT_TYPE_CREATED = 1;
  VM_EVENT_TYPE_UPDATED = 2;
  VM_EVENT_TYPE_DELETED = 3;
  VM_EVENT_TYPE_STATE_CHANGED = 4;
}

// ============================================================================
// Image Messages
// ============================================================================

message Image {
  string id = 1;
  string name = 2;
  string org_id = 3;
  Visibility visibility = 4;
  ImageFormat format = 5;
  uint64 size_bytes = 6;
  string checksum = 7;
  OsType os_type = 8;
  string os_version = 9;
  Architecture architecture = 10;
  uint32 min_disk_gib = 11;
  uint32 min_memory_mib = 12;
  ImageStatus status = 13;
  int64 created_at = 14;
  int64 updated_at = 15;
  map<string, string> metadata = 16;
}

enum Visibility {
  VISIBILITY_UNSPECIFIED = 0;
  VISIBILITY_PUBLIC = 1;
  VISIBILITY_PRIVATE = 2;
  VISIBILITY_SHARED = 3;
}

enum ImageFormat {
  IMAGE_FORMAT_UNSPECIFIED = 0;
  IMAGE_FORMAT_RAW = 1;
  IMAGE_FORMAT_QCOW2 = 2;
  IMAGE_FORMAT_VMDK = 3;
  IMAGE_FORMAT_VHD = 4;
}

enum OsType {
  OS_TYPE_UNSPECIFIED = 0;
  OS_TYPE_LINUX = 1;
  OS_TYPE_WINDOWS = 2;
  OS_TYPE_BSD = 3;
}

enum Architecture {
  ARCHITECTURE_UNSPECIFIED = 0;
  ARCHITECTURE_X86_64 = 1;
  ARCHITECTURE_AARCH64 = 2;
}

enum ImageStatus {
  IMAGE_STATUS_UNSPECIFIED = 0;
  IMAGE_STATUS_PENDING = 1;
  IMAGE_STATUS_UPLOADING = 2;
  IMAGE_STATUS_AVAILABLE = 3;
  IMAGE_STATUS_ERROR = 4;
}

message CreateImageRequest {
  string name = 1;
  string org_id = 2;
  Visibility visibility = 3;
  ImageFormat format = 4;
  OsType os_type = 5;
  string os_version = 6;
  Architecture architecture = 7;
  uint32 min_disk_gib = 8;
  uint32 min_memory_mib = 9;
  map<string, string> metadata = 10;
  string source_url = 11;
}

message BeginImageUploadRequest {
  string name = 1;
  string org_id = 2;
  Visibility visibility = 3;
  ImageFormat format = 4;
  OsType os_type = 5;
  string os_version = 6;
  Architecture architecture = 7;
  uint32 min_disk_gib = 8;
  uint32 min_memory_mib = 9;
  map<string, string> metadata = 10;
}

message BeginImageUploadResponse {
  Image image = 1;
  string upload_session_id = 2;
  uint32 minimum_part_size_bytes = 3;
}

message UploadImagePartRequest {
  string org_id = 1;
  string image_id = 2;
  string upload_session_id = 3;
  uint32 part_number = 4;
  bytes body = 5;
}

message UploadImagePartResponse {
  uint32 part_number = 1;
  uint64 committed_size_bytes = 2;
}

message CompleteImageUploadRequest {
  string org_id = 1;
  string image_id = 2;
  string upload_session_id = 3;
}

message AbortImageUploadRequest {
  string org_id = 1;
  string image_id = 2;
  string upload_session_id = 3;
}

message GetImageRequest {
  string org_id = 1;
  string image_id = 2;
}

message ListImagesRequest {
  string org_id = 1;
  int32 page_size = 2;
  string page_token = 3;
  bool include_public = 4;
}

message ListImagesResponse {
  repeated Image images = 1;
  string next_page_token = 2;
}

message UpdateImageRequest {
  string org_id = 1;
  string image_id = 2;
  string name = 3;
  Visibility visibility = 4;
  map<string, string> metadata = 5;
}

message DeleteImageRequest {
  string org_id = 1;
  string image_id = 2;
}

// ============================================================================
// Volume Messages
// ============================================================================

message Volume {
  string id = 1;
  string name = 2;
  string org_id = 3;
  string project_id = 4;
  uint64 size_gib = 5;
  VolumeDriverKind driver = 6;
  string storage_class = 7;
  VolumeFormat format = 8;
  VolumeStatus status = 9;
  string attached_to_vm = 10;
  map<string, string> metadata = 11;
  map<string, string> labels = 12;
  int64 created_at = 13;
  int64 updated_at = 14;
  VolumeBacking backing = 15;
  string attached_to_node = 16;
  uint64 attachment_generation = 17;
  uint64 last_flushed_attachment_generation = 18;
}

message VolumeBacking {
  oneof backing {
    ManagedVolumeBacking managed = 1;
    CephRbdBacking ceph_rbd = 2;
  }
}

message ManagedVolumeBacking {}

message CephRbdBacking {
  string cluster_id = 1;
  string pool = 2;
  string image = 3;
}

message CreateVolumeRequest {
  string name = 1;
  string org_id = 2;
  string project_id = 3;
  uint64 size_gib = 4;
  VolumeDriverKind driver = 5;
  string storage_class = 6;
  string image_id = 7;
  map<string, string> metadata = 8;
  map<string, string> labels = 9;
}

message GetVolumeRequest {
  string org_id = 1;
  string project_id = 2;
  string volume_id = 3;
}

message ListVolumesRequest {
  string org_id = 1;
  string project_id = 2;
  int32 page_size = 3;
  string page_token = 4;
}

message ListVolumesResponse {
  repeated Volume volumes = 1;
  string next_page_token = 2;
}

message DeleteVolumeRequest {
  string org_id = 1;
  string project_id = 2;
  string volume_id = 3;
}

message ResizeVolumeRequest {
  string org_id = 1;
  string project_id = 2;
  string volume_id = 3;
  uint64 size_gib = 4;
}

message RegisterExternalVolumeRequest {
  string name = 1;
  string org_id = 2;
  string project_id = 3;
  uint64 size_gib = 4;
  VolumeDriverKind driver = 5;
  string storage_class = 6;
  CephRbdBacking ceph_rbd = 7;
  map<string, string> metadata = 8;
  map<string, string> labels = 9;
}

// ============================================================================
// Node Messages
// ============================================================================

message Node {
  string id = 1;
  string name = 2;
  NodeState state = 3;
  NodeCapacity capacity = 4;
  NodeCapacity allocatable = 5;
  NodeCapacity allocated = 6;
  repeated HypervisorType hypervisors = 7;
  map<string, string> labels = 8;
  string agent_version = 9;
  int64 last_heartbeat = 10;
  repeated VolumeDriverKind supported_volume_drivers = 11;
  repeated string supported_storage_classes = 12;
  bool shared_live_migration = 13;
}

enum NodeState {
  NODE_STATE_UNSPECIFIED = 0;
  NODE_STATE_READY = 1;
  NODE_STATE_NOT_READY = 2;
  NODE_STATE_CORDONED = 3;
  NODE_STATE_DRAINING = 4;
  NODE_STATE_MAINTENANCE = 5;
}

message NodeCapacity {
  uint32 vcpus = 1;
  uint64 memory_mib = 2;
  uint64 storage_gib = 3;
}

message ListNodesRequest {
  int32 page_size = 1;
  string page_token = 2;
}

message ListNodesResponse {
  repeated Node nodes = 1;
  string next_page_token = 2;
}

message GetNodeRequest {
  string node_id = 1;
}

message CordonNodeRequest {
  string node_id = 1;
}

message UncordonNodeRequest {
  string node_id = 1;
}

message DrainNodeRequest {
  string node_id = 1;
  bool force = 2;
  uint32 timeout_seconds = 3;
}

message HeartbeatNodeRequest {
  string node_id = 1;
  string name = 2;
  NodeState state = 3;
  NodeCapacity capacity = 4;
  NodeCapacity allocatable = 5;
  repeated HypervisorType hypervisors = 6;
  map<string, string> labels = 7;
  string agent_version = 8;
  repeated VolumeDriverKind supported_volume_drivers = 9;
  repeated string supported_storage_classes = 10;
  bool shared_live_migration = 11;
}
