syntax = "proto3";

package connector.v1;

option go_package = "github.com/tech/sendico/pkg/proto/connector/v1;connectorv1";

import "google/protobuf/struct.proto";
import "google/protobuf/timestamp.proto";
import "google/protobuf/wrappers.proto";
import "api/proto/common/account_role/v1/account_role.proto";
import "api/proto/common/describable/v1/describable.proto";
import "api/proto/common/money/v1/money.proto";
import "api/proto/common/pagination/v1/cursor.proto";

// ConnectorService exposes capability-driven account and operation primitives.
service ConnectorService {
  // GetCapabilities returns the capabilities advertised by this connector.
  rpc GetCapabilities(GetCapabilitiesRequest) returns (GetCapabilitiesResponse);

  // OpenAccount provisions a new account on the connector.
  rpc OpenAccount(OpenAccountRequest) returns (OpenAccountResponse);
  // GetAccount retrieves a single account by reference.
  rpc GetAccount(GetAccountRequest) returns (GetAccountResponse);
  // ListAccounts returns a paginated list of accounts.
  rpc ListAccounts(ListAccountsRequest) returns (ListAccountsResponse);
  // GetBalance returns the current balance of an account.
  rpc GetBalance(GetBalanceRequest) returns (GetBalanceResponse);
  // UpdateAccountState transitions an account to a new lifecycle state.
  rpc UpdateAccountState(UpdateAccountStateRequest) returns (UpdateAccountStateResponse);

  // SubmitOperation submits a financial operation for execution.
  rpc SubmitOperation(SubmitOperationRequest) returns (SubmitOperationResponse);
  // GetOperation retrieves the current state of an operation.
  rpc GetOperation(GetOperationRequest) returns (GetOperationResponse);
  // ListOperations returns a paginated list of operations.
  rpc ListOperations(ListOperationsRequest) returns (ListOperationsResponse);
}

// AccountKind classifies the type of account managed by a connector.
enum AccountKind {
  // ACCOUNT_KIND_UNSPECIFIED is the default zero value.
  ACCOUNT_KIND_UNSPECIFIED = 0;
  // LEDGER_ACCOUNT is an internal ledger-based account.
  LEDGER_ACCOUNT = 1;
  // CHAIN_MANAGED_WALLET is a blockchain managed wallet.
  CHAIN_MANAGED_WALLET = 2;
  // EXTERNAL_REF is a reference to an account outside the system.
  EXTERNAL_REF = 3;
}

// AccountState represents the lifecycle state of an account.
enum AccountState {
  // ACCOUNT_STATE_UNSPECIFIED is the default zero value.
  ACCOUNT_STATE_UNSPECIFIED = 0;
  // ACCOUNT_ACTIVE means the account is open and operational.
  ACCOUNT_ACTIVE = 1;
  // ACCOUNT_SUSPENDED means the account is temporarily disabled.
  ACCOUNT_SUSPENDED = 2;
  // ACCOUNT_CLOSED means the account is permanently closed.
  ACCOUNT_CLOSED = 3;
}

// OperationType classifies the kind of financial operation.
enum OperationType {
  // OPERATION_TYPE_UNSPECIFIED is the default zero value.
  OPERATION_TYPE_UNSPECIFIED = 0;
  // CREDIT adds funds to an account.
  CREDIT = 1;
  // DEBIT removes funds from an account.
  DEBIT = 2;
  // TRANSFER moves funds between two accounts.
  TRANSFER = 3;
  // PAYOUT sends funds to an external destination.
  PAYOUT = 4;
  // FEE_ESTIMATE computes estimated fees without executing.
  FEE_ESTIMATE = 5;
  // FX performs a foreign-exchange conversion.
  FX = 6;
  // GAS_TOPUP tops up native gas for blockchain transactions.
  GAS_TOPUP = 7;
}

// OperationStatus tracks the lifecycle of an operation.
enum OperationStatus {
  // OPERATION_STATUS_UNSPECIFIED is the default zero value.
  OPERATION_STATUS_UNSPECIFIED = 0;

  OPERATION_CREATED    = 1; // record exists, not started
  OPERATION_PROCESSING = 2; // we are working on it
  OPERATION_WAITING    = 3; // waiting external world

  OPERATION_SUCCESS    = 4; // final success
  OPERATION_FAILED     = 5; // final failure
  OPERATION_CANCELLED  = 6; // final cancelled
}

// ParamType defines the data type of a connector parameter.
enum ParamType {
  // PARAM_TYPE_UNSPECIFIED is the default zero value.
  PARAM_TYPE_UNSPECIFIED = 0;
  // STRING is a plain string parameter.
  STRING = 1;
  // INT is an integer parameter.
  INT = 2;
  // BOOL is a boolean parameter.
  BOOL = 3;
  // DECIMAL_STRING is a decimal number encoded as a string.
  DECIMAL_STRING = 4;
  // JSON is a free-form JSON parameter.
  JSON = 5;
}

// ErrorCode enumerates well-known connector error codes.
enum ErrorCode {
  // ERROR_CODE_UNSPECIFIED is the default zero value.
  ERROR_CODE_UNSPECIFIED = 0;
  // UNSUPPORTED_OPERATION means the connector does not support this operation type.
  UNSUPPORTED_OPERATION = 1;
  // UNSUPPORTED_ACCOUNT_KIND means the connector does not support this account kind.
  UNSUPPORTED_ACCOUNT_KIND = 2;
  // INVALID_PARAMS means the supplied parameters are invalid.
  INVALID_PARAMS = 3;
  // INSUFFICIENT_FUNDS means the account lacks sufficient balance.
  INSUFFICIENT_FUNDS = 4;
  // NOT_FOUND means the referenced resource was not found.
  NOT_FOUND = 5;
  // TEMPORARY_UNAVAILABLE means the connector is temporarily unavailable.
  TEMPORARY_UNAVAILABLE = 6;
  // RATE_LIMITED means the caller has exceeded the rate limit.
  RATE_LIMITED = 7;
  // PROVIDER_ERROR means an upstream provider returned an error.
  PROVIDER_ERROR = 8;
}

// ParamSpec describes a single parameter accepted by the connector.
message ParamSpec {
  string key = 1;
  ParamType type = 2;
  bool required = 3;
  string description = 4;
  repeated string allowed_values = 5;
  google.protobuf.Struct example = 6;
}

// OperationParamSpec groups the parameter specs for a given operation type.
message OperationParamSpec {
  OperationType operation_type = 1;
  repeated ParamSpec params = 2;
}

// ConnectorCapabilities describes the features and constraints of a connector.
message ConnectorCapabilities {
  string connector_type = 1;
  string version = 2;
  repeated AccountKind supported_account_kinds = 3;
  repeated OperationType supported_operation_types = 4;
  repeated string supported_assets = 5; // canonical asset string (USD, ETH, USDT-TRC20)
  repeated string supported_networks = 6; // optional, connector-defined names
  repeated ParamSpec open_account_params = 7;
  repeated OperationParamSpec operation_params = 8;
  map<string, string> metadata = 9;
}

// AccountRef uniquely identifies an account within a connector.
message AccountRef {
  string connector_id = 1;
  string account_id = 2;
}

// ExternalRef identifies an account or party outside the platform.
message ExternalRef {
  string external_ref = 1;
  google.protobuf.Struct details = 2;
}

// OperationParty represents one side (source or destination) of an operation.
message OperationParty {
  oneof ref {
    AccountRef account = 1;
    ExternalRef external = 2;
  }
}

// Account is the canonical representation of a connector-managed account.
message Account {
  AccountRef ref = 1;
  AccountKind kind = 2;
  string asset = 3; // canonical asset string (USD, ETH, USDT-TRC20)
  AccountState state = 4;
  string label = 5;
  string owner_ref = 6; // optional account_ref; empty means organization-owned
  google.protobuf.Struct provider_details = 7;
  google.protobuf.Timestamp created_at = 8;
  google.protobuf.Timestamp updated_at = 9;
  common.describable.v1.Describable describable = 10;
  common.account_role.v1.AccountRole role = 11; // functional role within the organization (ledger-only; unset for non-ledger connectors)
}

// Balance holds the current balance breakdown for an account.
message Balance {
  AccountRef account_ref = 1;
  common.money.v1.Money available = 2;
  common.money.v1.Money pending_inbound = 3;
  common.money.v1.Money pending_outbound = 4;
  google.protobuf.Timestamp calculated_at = 5;
}

// ConnectorError conveys a structured error from the connector.
message ConnectorError {
  ErrorCode code = 1;
  string message = 2;
  google.protobuf.Struct details = 3;
  string correlation_id = 4;
  string parent_intent_id = 5;
  string operation_id = 6;
  string account_id = 7;
}

// Operation represents a financial operation submitted to a connector.
message Operation {
  string operation_id = 1;
  OperationType type = 2;
  OperationParty from = 3;
  OperationParty to = 4;
  common.money.v1.Money money = 5;
  string idempotency_key = 6;
  google.protobuf.Struct params = 7;
  string correlation_id = 8;
  string parent_intent_id = 9;
  OperationStatus status = 10;
  string provider_ref = 11;
  google.protobuf.Timestamp created_at = 12;
  google.protobuf.Timestamp updated_at = 13;
  common.account_role.v1.AccountRole from_role = 14;
  common.account_role.v1.AccountRole to_role = 15;
  string operation_ref = 16;
  string intent_ref = 17;
}

// OperationReceipt is the synchronous result returned after submitting an operation.
message OperationReceipt {
  string operation_id = 1;
  OperationStatus status = 2;
  string provider_ref = 3;
  ConnectorError error = 4;
  google.protobuf.Struct result = 5; // connector-specific output payload
}

// GetCapabilitiesRequest is the request for GetCapabilities.
message GetCapabilitiesRequest {}

// GetCapabilitiesResponse is the response for GetCapabilities.
message GetCapabilitiesResponse {
  ConnectorCapabilities capabilities = 1;
}

// OpenAccountRequest is the request to provision a new account.
message OpenAccountRequest {
  string idempotency_key = 1;
  AccountKind kind = 2;
  string asset = 3; // canonical asset string (USD, ETH, USDT-TRC20)
  string label = 4;
  string owner_ref = 5; // optional account_ref; empty means organization-owned
  google.protobuf.Struct params = 6;
  string correlation_id = 7;
  string parent_intent_id = 8;
  common.account_role.v1.AccountRole role = 9; // functional role (ledger-only; ignored by non-ledger connectors)
}

// OpenAccountResponse is the response for OpenAccount.
message OpenAccountResponse {
  Account account = 1;
  ConnectorError error = 2;
}

// GetAccountRequest is the request to retrieve a single account.
message GetAccountRequest {
  AccountRef account_ref = 1;
}

// GetAccountResponse is the response for GetAccount.
message GetAccountResponse {
  Account account = 1;
}

// ListAccountsRequest is the request to list accounts with optional filters.
message ListAccountsRequest {
  reserved 1;
  reserved "owner_ref";
  AccountKind kind = 2;
  string asset = 3; // canonical asset string (USD, ETH, USDT-TRC20)
  common.pagination.v1.CursorPageRequest page = 4;
  string organization_ref = 5;
  // Optional owner filter with 3-state semantics:
  // - not set: return all accounts within organization
  // - set to empty string: return accounts where owner_ref is null/empty
  // - set to a value: return accounts where owner_ref matches
  google.protobuf.StringValue owner_ref_filter = 6;
}

// ListAccountsResponse is the response for ListAccounts.
message ListAccountsResponse {
  repeated Account accounts = 1;
  common.pagination.v1.CursorPageResponse page = 2;
}

// UpdateAccountStateRequest is the request to change an account's lifecycle state.
message UpdateAccountStateRequest {
  AccountRef account_ref = 1;
  AccountState target_state = 2;
  common.account_role.v1.AccountRole source_role = 3; // optional: assert account has this role before mutation
}

// UpdateAccountStateResponse is the response for UpdateAccountState.
message UpdateAccountStateResponse {
  Account account = 1;
  ConnectorError error = 2;
}

// GetBalanceRequest is the request to retrieve an account balance.
message GetBalanceRequest {
  AccountRef account_ref = 1;
}

// GetBalanceResponse is the response for GetBalance.
message GetBalanceResponse {
  Balance balance = 1;
}

// SubmitOperationRequest is the request to submit a financial operation.
message SubmitOperationRequest {
  Operation operation = 1;
}

// SubmitOperationResponse is the response for SubmitOperation.
message SubmitOperationResponse {
  OperationReceipt receipt = 1;
}

// GetOperationRequest is the request to retrieve an operation by ID.
message GetOperationRequest {
  string operation_id = 1;
}

// GetOperationResponse is the response for GetOperation.
message GetOperationResponse {
  Operation operation = 1;
}

// ListOperationsRequest is the request to list operations with optional filters.
message ListOperationsRequest {
  AccountRef account_ref = 1;
  OperationType type = 2;
  OperationStatus status = 3;
  string correlation_id = 4;
  string parent_intent_id = 5;
  common.pagination.v1.CursorPageRequest page = 6;
}

// ListOperationsResponse is the response for ListOperations.
message ListOperationsResponse {
  repeated Operation operations = 1;
  common.pagination.v1.CursorPageResponse page = 2;
}
