syntax = "proto3";

option go_package = ".;main";

import "google/protobuf/timestamp.proto";

// Support provides an interactive chat service, for customers to interact with
// the bank's support agents. A single stream, for either of the two methods, is
// a stateful connection to a single "chat session". Streams are initially disconnected
// (not part of any session). A stream must be disconnected from a session (via customer
// hang up or via agent leaving a session) before it can be connected to a new one.
service Support {
    // ChatCustomer is used by a customer-facing app to send the customer's messages
    // to a chat session. The customer is how initiates and terminates (via "hangup")
    // a chat session. Only customers may invoke this method (e.g. requests must
    // include customer auth credentials).
    rpc ChatCustomer(stream ChatCustomerRequest) returns (stream ChatCustomerResponse);
    // ChatAgent is used by an agent-facing app to allow an agent to reply to a
    // customer's messages in a chat session. The agent may accept a chat session,
    // which defaults to the session awaiting an agent for the longest period of time
    // (FIFO queue).
    rpc ChatAgent(stream ChatAgentRequest) returns (stream ChatAgentResponse);
}

enum Void {
    VOID = 0;
}

message ChatCustomerRequest {
    oneof req {
        // init is used when a chat stream is not part of a
        // chat session. This is a stream's initial state, as well as
        // the state after a "hang_up" request is sent. This creates
        // a new state session or resumes an existing one.
        InitiateChat init = 1;
        // msg is used to send the customer's messages to support
        // agents.
        string msg = 2;
        // hang_up is used to terminate a chat session. If a stream
        // is broken, but the session was not terminated, the client
        // may initiate a new stream and use init to resume that
        // session. Sessions are not terminated unless done so
        // explicitly via sending this kind of request on the stream.
        Void hang_up = 3;
    }
}

message InitiateChat {
    string resume_session_id = 1;
}

message AgentMessage {
    string agent_name = 1;
    string msg = 2;
}

message ChatCustomerResponse {
    oneof resp {
        // session is sent from the server when the stream is connected
        // to a chat session. This happens after an init request is sent
        // and the stream is connected to either a new or resumed session.
        Session session = 1;
        // msg is sent from the server to convey agents' messages to the
        // customer.
        AgentMessage msg = 2;
    }
}

message ChatAgentRequest {
    oneof req {
        // accept is used when an agent wants to join a customer chat
        // session. It can be used to connect to a specific session (by
        // ID), or to just accept the session for which the customer has
        // been waiting the longest (e.g. poll a FIFO queue of sessions
        // awaiting a support agent). It is possible for multiple agents
        // to be connected to the same chat session.
        AcceptChat accept = 1;
        // msg is used to send a message to the customer. It will also be
        // delivered to any other connected support agents.
        string msg = 2;
        // leave_session allows an agent to exit a chat session. They can
        // always re-enter later by sending an accept message for that
        // session ID.
        Void leave_session = 3;
    }
}

message AcceptChat {
    string session_id = 1;
}

message ChatEntry {
    google.protobuf.Timestamp date = 1;
    oneof entry {
        string customer_msg = 2;
        AgentMessage agent_msg = 3;
    }
}

message ChatAgentResponse {
    oneof resp {
        // accepted_session provides the detail of a chat session. The server
        // sends this message after the agent has accepted a chat session.
        Session accepted_session = 1;
        // msg is sent by the server when the customer, or another support
        // agent, sends a message in stream's current session.
        ChatEntry msg = 2;
        // session_ended notifies the support agent that their currently
        // connected chat session has been terminated by the customer.
        Void session_ended = 3;
    }
}

message Session {
    string session_id = 1;
    string customer_name = 2;
    repeated ChatEntry history = 3;
}
