// Copyright 2022 Lightbend Inc.

// gRPC interface for Workflow user functions.

syntax = "proto3";

package kalix.component.workflow;

import "google/protobuf/any.proto";
import "google/protobuf/duration.proto";
import "kalix/component/component.proto";
import "kalix/component/entity/entity.proto";

option go_package = "github.com/lightbend/kalix-go-sdk/kalix/entity;entity";
option java_package = "kalix.protocol";

// EXPERIMENTAL: API MAY CHANGE

// The init message. This will always be the first message sent to the workflow
// when it is loaded.
message WorkflowEntityInit {
  // The name of the service that this entity is a part of.
  string service_name = 1;
  // The ID of the workflow.
  string entity_id = 2;
  // If present the workflow should initialise its state using this field.
  google.protobuf.Any user_state = 3;
  // Marker for the sdk that initialized workflow has been finished.
  bool finished = 4;
}

message ExecuteStep {
  int64 command_id = 1;
  string step_name = 2;
  google.protobuf.Any input = 3;
  google.protobuf.Any user_state = 4;
}

message StepExecuted {
  google.protobuf.Any result = 1;
}

message StepExecutionFailed {
  string error_message = 1;
}

message StepDeferredCall {
  // The name of the service to perform the side effect on.
  string service_name = 1;
  // The name of the command.
  string command_name = 2;
  // The payload of the command.
  google.protobuf.Any payload = 3;
  // The metadata to include with the side effect
  Metadata metadata = 5;
}

message StepResponse {
  int64 command_id = 1;
  string step_name = 2;
  oneof response {
    StepExecuted executed = 3;
    StepExecutionFailed execution_failed = 4;
    StepDeferredCall deferred_call = 5;
  }
}

message GetNextStep {
  int64 command_id = 1;
  string step_name = 2;
  google.protobuf.Any result = 3;
}

message StepTransition {
  string step_name = 1;
  google.protobuf.Any input = 2;
}
message Pause {}
message NoTransition {}
message EndTransition {}

message WorkflowClientAction {//TODO rename
  oneof action {
    // Send a reply
    Reply reply = 1;
    // Send a failure to the client
    Failure failure = 2;
  }
}

// A reply to a command or state execution
message WorkflowEffect {//TODO rename it
  // The id of the command being replied to. Must match the input command.
  int64 command_id = 1;
  // The action to take
  WorkflowClientAction client_action = 2;

  google.protobuf.Any user_state = 3;

  oneof transition {
    StepTransition step_transition = 4;
    EndTransition end_transition = 5;
    Pause pause = 6;
    NoTransition no_transition = 7;
  }
}

// Input message type for the gRPC stream in.
message WorkflowStreamIn {
  oneof message {
    WorkflowEntityInit init = 1;
    entity.Command command = 2;
    ExecuteStep step = 3;
    GetNextStep transition = 4;
  }
}

message RecoverStrategy {
  uint32 max_retries = 1;
  StepTransition failover_to = 2;
}

message StepConfig {
  string step_name = 1;
  google.protobuf.Duration step_timeout = 2;
  RecoverStrategy recover_strategy = 3;
}

message WorkflowConfig {
  google.protobuf.Duration workflow_timeout = 1;
  StepTransition failover_to = 2; //in case of workflow timeout
  RecoverStrategy failover_recover_strategy = 3;
  StepConfig default_step_config = 4; //step_name is ignored
  repeated StepConfig step_configs = 5;
}

// Output message type for the gRPC stream out.
message WorkflowStreamOut {
  oneof message {
    Failure failure = 1; //used for unexpected try-catch failures
    WorkflowEffect effect = 2;
    StepResponse response = 3;
    WorkflowConfig config = 4;
  }
}

// Service that the SDK (in the user function) implements to make workflow available to the proxy
service WorkflowEntities {
  // The stream. One stream will be established per active workflow. Once
  // established, the first message sent will be Init, which contains the workflow
  // ID, and eventually its current state if any. TODO finish docs
  rpc Handle(stream WorkflowStreamIn) returns (stream WorkflowStreamOut);
}
