// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

syntax = "proto3";
package org.apache.texera.amber.engine.architecture.rpc;

import "org/apache/texera/amber/core/virtualidentity.proto";
import "org/apache/texera/amber/core/workflow.proto";
import "org/apache/texera/amber/core/executor.proto";
import "org/apache/texera/amber/engine/architecture/worker/statistics.proto";
import "org/apache/texera/amber/engine/architecture/sendsemantics/partitionings.proto";
import "scalapb/scalapb.proto";
import "google/protobuf/timestamp.proto";

option (scalapb.options) = {
  scope: FILE,
  preserve_unknown_fields: false
  no_default_values_in_constructor: true
};

message ControlRequest {
  oneof sealed_value {
    // request for controller
    PropagateEmbeddedControlMessageRequest propagateEmbeddedControlMessageRequest = 1;
    TakeGlobalCheckpointRequest takeGlobalCheckpointRequest = 2;
    DebugCommandRequest debugCommandRequest = 3;
    EvaluatePythonExpressionRequest evaluatePythonExpressionRequest = 4;
    RetryWorkflowRequest retryWorkflowRequest = 5;
    ConsoleMessageTriggeredRequest consoleMessageTriggeredRequest = 6;
    PortCompletedRequest portCompletedRequest = 7;
    WorkerStateUpdatedRequest workerStateUpdatedRequest = 8;
    LinkWorkersRequest linkWorkersRequest = 9;
    WorkflowReconfigureRequest workflowReconfigureRequest = 10;

    // request for worker
    AddInputChannelRequest addInputChannelRequest = 50;
    AddPartitioningRequest addPartitioningRequest = 51;
    AssignPortRequest assignPortRequest = 52;
    FinalizeCheckpointRequest finalizeCheckpointRequest = 53;
    InitializeExecutorRequest initializeExecutorRequest = 54;
    UpdateExecutorRequest updateExecutorRequest = 55;
    EmptyRequest emptyRequest = 56;
    PrepareCheckpointRequest prepareCheckpointRequest = 57;
    QueryStatisticsRequest queryStatisticsRequest = 58;

    // request for testing
    Ping ping = 100;
    Pong pong = 101;
    Nested nested = 102;
    Pass pass = 103;
    ErrorCommand errorCommand = 104;
    Recursion recursion = 105;
    Collect collect = 106;
    GenerateNumber generateNumber = 107;
    MultiCall multiCall = 108;
    Chain chain = 109;
  }
}

message EmptyRequest{}

message AsyncRPCContext {
  option (scalapb.message).no_box = true;
  core.ActorVirtualIdentity sender = 1 [(scalapb.field).no_box = true];
  core.ActorVirtualIdentity receiver = 2 [(scalapb.field).no_box = true];
}

message ControlInvocation {
  option (scalapb.message).extends = "org.apache.texera.amber.engine.common.ambermessage.DirectControlMessagePayload";
  string methodName = 1;
  ControlRequest command = 2 [(scalapb.field).no_box = true];
  AsyncRPCContext context = 3;
  int64 commandId = 4;
}

enum EmbeddedControlMessageType {
  ALL_ALIGNMENT = 0;
  NO_ALIGNMENT = 1;
  PORT_ALIGNMENT = 2;
}

message EmbeddedControlMessage {
  option (scalapb.message).extends = "org.apache.texera.amber.engine.common.ambermessage.WorkflowFIFOMessagePayload";
  core.EmbeddedControlMessageIdentity id = 1 [(scalapb.field).no_box = true];
  EmbeddedControlMessageType ecm_type = 2;
  repeated core.ChannelIdentity scope = 3;
  map<string, ControlInvocation> commandMapping = 4;
}

message PropagateEmbeddedControlMessageRequest {
  repeated core.PhysicalOpIdentity sourceOpToStartProp = 1;
  core.EmbeddedControlMessageIdentity id = 2 [(scalapb.field).no_box = true];
  EmbeddedControlMessageType ecm_type = 3;
  repeated core.PhysicalOpIdentity scope = 4;
  repeated core.PhysicalOpIdentity targetOps = 5;
  ControlRequest command = 6;
  string methodName = 7;
}

message TakeGlobalCheckpointRequest {
  bool estimationOnly = 1;
  core.EmbeddedControlMessageIdentity checkpointId = 2 [(scalapb.field).no_box = true];
  string destination = 3;
}

message WorkflowReconfigureRequest{
  repeated UpdateExecutorRequest reconfiguration = 1;
  string reconfigurationId = 2;
}


message DebugCommandRequest {
  string workerId = 1;
  string cmd = 2;
}

message EvaluatePythonExpressionRequest {
  string expression = 1;
  string operatorId = 2;
}

message RetryWorkflowRequest {
  repeated core.ActorVirtualIdentity workers = 1;
}

enum ConsoleMessageType{
  PRINT = 0;
  ERROR = 1;
  COMMAND = 2;
  DEBUGGER = 3;
}

message ConsoleMessage {
  option (scalapb.message).extends = "org.apache.texera.amber.engine.architecture.controller.ClientEvent";
  string worker_id = 1;
  google.protobuf.Timestamp timestamp = 2  [(scalapb.field).no_box = true];
  ConsoleMessageType msg_type = 3;
  string source = 4;
  string title = 5;
  string message = 6;
}

message ConsoleMessageTriggeredRequest {
  ConsoleMessage consoleMessage = 1 [(scalapb.field).no_box = true];
}

message PortCompletedRequest {
  core.PortIdentity portId = 1 [(scalapb.field).no_box = true];
  bool input = 2;
}

message WorkerStateUpdatedRequest {
  worker.WorkerState state = 1 [(scalapb.field).no_box = true];
}

message LinkWorkersRequest {
  core.PhysicalLink link = 1 [(scalapb.field).no_box = true];
}

// Ping message
message Ping {
  int32 i = 1;
  int32 end = 2;
  core.ActorVirtualIdentity to = 3 [(scalapb.field).no_box = true];
}

// Pong message
message Pong {
  int32 i = 1;
  int32 end = 2;
  core.ActorVirtualIdentity to = 3 [(scalapb.field).no_box = true];
}

// Pass message
message Pass {
  string value = 1;
}

// Nested message
message Nested {
  int32 k = 1;
}

// MultiCall message
message MultiCall {
  repeated core.ActorVirtualIdentity seq = 1;
}

// ErrorCommand message
message ErrorCommand {
}

// Collect message
message Collect {
  repeated core.ActorVirtualIdentity workers = 1;
}

// GenerateNumber message
message GenerateNumber {
}

// Chain message
message Chain {
  repeated core.ActorVirtualIdentity nexts = 1;
}

// Recursion message
message Recursion {
  int32 i = 1;
}

// Messages for the commands
message AddInputChannelRequest {
  core.ChannelIdentity channelId = 1 [(scalapb.field).no_box = true];
  core.PortIdentity portId = 2 [(scalapb.field).no_box = true];
}

message AddPartitioningRequest {
  core.PhysicalLink tag = 1 [(scalapb.field).no_box = true];
  sendsemantics.Partitioning partitioning = 2 [(scalapb.field).no_box = true];
}

message AssignPortRequest {
  core.PortIdentity portId = 1 [(scalapb.field).no_box = true];
  bool input = 2;
  map<string, string> schema = 3;
  repeated string storageUris = 4;
  repeated sendsemantics.Partitioning partitionings = 5;
}

message FinalizeCheckpointRequest {
  core.EmbeddedControlMessageIdentity checkpointId = 1 [(scalapb.field).no_box = true];
  string writeTo = 2;
}

message InitializeExecutorRequest {
  int32 totalWorkerCount = 1;
  core.OpExecInitInfo opExecInitInfo = 2;
  bool isSource = 3;
}

message UpdateExecutorRequest {
  core.PhysicalOpIdentity targetOpId = 1 [(scalapb.field).no_box = true];
  core.OpExecInitInfo newExecInitInfo = 2;
}

message PrepareCheckpointRequest{
  core.EmbeddedControlMessageIdentity checkpointId = 1 [(scalapb.field).no_box = true];
  bool estimationOnly = 2;
}

enum StatisticsUpdateTarget {
  BOTH_UI_AND_PERSISTENCE = 0;
  UI_ONLY = 1;
  PERSISTENCE_ONLY = 2;
}

message QueryStatisticsRequest{
  repeated core.ActorVirtualIdentity filterByWorkers = 1;
  StatisticsUpdateTarget updateTarget = 2;
}