syntax = "proto3";

option go_package = ".;main";

import "google/protobuf/empty.proto";
import "google/protobuf/timestamp.proto";

// Bank provides operations for interacting with bank accounts. All
// operations operate for the authenticated user (identified via an
// "authorization" request header, where the type is "token" and the
// credential is the customer's ID).
service Bank {
    // OpenAccount creates an account with the type and given initial deposit
    // as its balance.
    rpc OpenAccount(OpenAccountRequest) returns (Account);
    // CloseAccount closes the indicated account. An account can only be
    // closed if its balance is zero.
    rpc CloseAccount(CloseAccountRequest) returns (google.protobuf.Empty);
    // GetAccounts lists all accounts for the current customer.
    rpc GetAccounts(google.protobuf.Empty) returns (GetAccountsResponse);
    // GetTransactions streams all transactions that match the given criteria.
    // If the given start date is not specified, transactions since beginning
    // of time are included. Similarly, if the given end date is not specified,
    // transactions all the way to the presnet are included.
    rpc GetTransactions(GetTransactionsRequest) returns (stream Transaction);
    // Deposit increases the balance of an account by depositing funds into it.
    rpc Deposit(DepositRequest) returns (BalanceResponse);
    // Withdraw decreases the balance of an account by withdrawing funds from it.
    rpc Withdraw(WithdrawRequest) returns (BalanceResponse);
    // Transfer moves money from one account to another. The source and destination
    // accounts can be with this bank (e.g. "local" account numbers) or can be
    // external accounts, identified by their ACH routing and account numbers.
    rpc Transfer(TransferRequest) returns (TransferResponse);
}

message OpenAccountRequest {
    int32 initial_deposit_cents = 1;
    Account.Type type = 2;
}

message CloseAccountRequest {
    uint64 account_number = 1;
}

message GetAccountsResponse {
    repeated Account accounts = 1;
}

message Account {
    uint64 account_number = 1;
    enum Type {
        UNKNOWN = 0;
        CHECKING = 1;
        SAVING = 2;
        MONEY_MARKET = 3;
        LINE_OF_CREDIT = 4;
        LOAN = 5;
        EQUITIES = 6;
    }
    Type type = 2;
    int32 balance_cents = 3;
}

message GetTransactionsRequest {
    uint64 account_number = 1;
    google.protobuf.Timestamp start = 2;
    google.protobuf.Timestamp end = 3;
}

message Transaction {
    uint64 account_number = 1;
    uint64 seq_number = 2;
    google.protobuf.Timestamp date = 3;
    int32 amount_cents = 4;
    string desc = 5;
}

message DepositRequest {
    uint64 account_number = 1;
    int32 amount_cents = 2;
    enum Source {
        UNKNOWN = 0;
        CASH = 1;
        CHECK = 2;
        ACH = 3;
        WIRE = 4;
    }
    Source source = 3;
    string desc = 4;
}

message BalanceResponse {
    uint64 account_number = 1;
    int32 balance_cents = 2;
}

message WithdrawRequest {
    uint64 account_number = 1;
    int32 amount_cents = 2;
    string desc = 3;
}

message TransferRequest {
    message ExternalAccount {
        uint64 ach_routing_number = 1;
        uint64 ach_account_number = 2;
    }
    oneof source {
        uint64 source_account_number = 1;
        ExternalAccount external_source = 2;
    }
    oneof dest {
        uint64 dest_account_number = 3;
        ExternalAccount external_dest = 4;
    }
    int32 amount_cents = 5;
    string desc = 6;
}

message TransferResponse {
    uint64 src_account_number = 1;
    int32 src_balance_cents = 2;
    uint64 dest_account_number = 3;
    int32 dest_balance_cents = 4;
}
