syntax = "proto3";

package eigr.functions.protocol.actors;

import "google/protobuf/any.proto";

option java_package = "io.eigr.functions.protocol.actors";
option go_package = "github.com/eigr/go-support/eigr/actors;actors";

message Registry {
    map<string, Actor> actors = 1;
}

message ActorSystem {
    string name = 1;
    Registry registry = 2;
}

// A strategy for save state.
message ActorSnapshotStrategy {
    oneof strategy {
        // the timeout strategy.
        TimeoutStrategy timeout = 1;
    }
}

// A strategy which a user function's entity is passivated.
message ActorDeactivationStrategy {
    oneof strategy {
        // the timeout strategy.
        TimeoutStrategy timeout = 1;
    }
}

// A strategy based on a timeout. 
message TimeoutStrategy {
    // The timeout in millis
    int64 timeout = 1;
}

// A action represents an action that the user can perform on an Actor. 
// Actions in supporting languages are represented by functions or methods.
// An Actor action has nothing to do with the semantics of Actions in a CQRS/EventSourced system. 
// It just represents an action that supporting languages can invoke.
message Action {

    // The name of the function or method in the supporting language that has been registered in Ator.
    string name = 1;
}

// A FixedTimerAction is similar to a regular Action, its main differences are that it is scheduled to run at regular intervals 
// and only takes the actor's state as an argument.
// Timer Actions are good for executing loops that manipulate the actor's own state. 
// In Elixir or other languages in BEAM it would be similar to invoking Process.send_after(self(), atom, msg, timeout)
message FixedTimerAction {

    // The time to wait until the action is triggered
    int32 seconds = 1;

    // See Action description Above
    Action action = 2;
}

message ActorState {
    map<string, string> tags = 1;
    google.protobuf.Any state = 2;
}

// TODO doc here
message Metadata {
    // A channel group represents a way to send actions to various actors 
    // that belong to a certain semantic group.
    string channel_group = 1;

    map<string, string> tags = 2;
}

// The type that defines the runtime characteristics of the Actor.
// Regardless of the type of actor it is important that 
// all actors are registered during the proxy and host initialization phase.
enum Kind {
    // When no type is informed, the default to be assumed will be the Named pattern.
    UNKNOW_KIND = 0;

    // NAMED actors are used to create children of this based actor at runtime
    NAMED = 1;

    // UNAMED actors as the name suggests have only one real instance of themselves running 
    // during their entire lifecycle. That is, they are the opposite of the NAMED type Actors.
    UNAMED = 2;
    
    // Pooled Actors are similar to Unamed actors, but unlike them, 
    // their identifying name will always be the one registered at the system initialization stage. 
    // The great advantage of Pooled actors is that they have multiple instances of themselves 
    // acting as a request service pool.
    // Pooled actors are also stateless actors, that is, they will not have their 
    // in-memory state persisted via Statesstore. This is done to avoid problems 
    // with the correctness of the stored state.
    // Pooled Actors are generally used for tasks where the Actor Model would perform worse 
    // than other concurrency models and for tasks that do not require state concerns. 
    // Integration flows, data caching, proxies are good examples of use cases 
    // for this type of Actor.
    POOLED = 3;
    
    // Reserved for future use
    PROXY = 4;
}

message ActorSettings {

    // Indicates the type of Actor to be configured.
    Kind kind = 1;

    // Indicates whether an actor's state should be persisted in a definitive store.
    bool stateful = 2;

    // Snapshot strategy
    ActorSnapshotStrategy snapshot_strategy = 3;

    // Deactivate strategy
    ActorDeactivationStrategy deactivation_strategy = 4;

    // When kind is POOLED this is used to define minimun actor instances
    int32 min_pool_size = 5;

    // When kind is POOLED this is used to define maximum actor instances
    int32 max_pool_size = 6;
}

message ActorId {
    // The name of a Actor Entity.
    string name = 1;

    // Name of a ActorSystem
    string system = 2;

    // When the Actor is of the Unamed type, 
    // the name of the parent Actor must be informed here.
    string parent = 3;
}

message Actor {
    // Actor Identification
    ActorId id = 1;

    // A Actor state.
    ActorState state = 2;

    // Actor metadata
    Metadata metadata = 6;

    // Actor settings.
    ActorSettings settings = 3;

    // The actions registered for an actor
    repeated Action actions = 4;

    // The registered timer actions for an actor.
    repeated FixedTimerAction timer_actions = 5;
}