syntax = "proto3";

package alt.v1;

option go_package = "git.toki-labs.com/toki/alt/packages/contracts/gen/go/alt/v1;altv1";

import "alt/v1/common.proto";
import "alt/v1/market.proto";
import "alt/v1/backtest.proto";

// live_trading.proto defines the broker-neutral live trading command/query
// surface. This subtask only wires up the broker capability probe
// (GetLiveBrokerCapabilities); subsequent subtasks add order/position/audit
// message families on top of the same proto.

// OrderTimeInForce is a string-typed field in the live domain, so we use
// string here as well. The protobuf enum is unnecessary since brokers may
// return values we haven't enumerated.

// GetLiveBrokerCapabilitiesRequest is a query sent to the worker to discover
// what markets, venues, and order types the live broker adapter supports.
message GetLiveBrokerCapabilitiesRequest {
  string account_id = 1;
}

// GetLiveBrokerCapabilitiesResponse wraps the broker capability report or an
// error explaining why the probe failed.
message GetLiveBrokerCapabilitiesResponse {
  LiveBrokerCapability broker_capabilities = 1;
  ErrorInfo error = 2;
}

// LiveBrokerCapability describes what a live broker supports. It mirrors the
// domain types in packages/domain/trading but is wire-format only so that
// generated code stays minimal for this milestone.
message LiveBrokerCapability {
  string broker = 1;
  repeated Market markets = 2;
  repeated Venue venues = 3;
  repeated string order_types = 4;
  bool supports_amend = 5;
  bool supports_cancel = 6;
  bool supports_account = 7;
  bool supports_audit_tags = 8;
  int64 checked_at_unix_ms = 9;
}

// LiveOrderIntent mirrors the backtest/trading domain intent but belongs to
// the live protobuf surface so live consumers can decode it without importing
// backtest messages. Side/type/status stay string-typed to match the domain
// vocabulary and to keep the lifecycle additive without new enums.
message LiveOrderIntent {
  string instrument_id = 1;
  // side is "buy" or "sell".
  string side = 2;
  Quantity quantity = 3;
  // type is "market", "limit", or broker-specific (e.g. "kis_best_limit").
  string type = 4;
  string time_in_force = 5;
  Price limit_price = 6;
  string broker_client_id = 7;
  map<string, string> custom_tags = 8;
}

// LiveOrder is a broker-submitted order with execution status updates. It uses
// string-typed side/type/status so unknown broker values are preserved.
message LiveOrder {
  string id = 1;
  string broker_id = 2;
  string client_id = 3;
  string account_id = 4;
  string instrument_id = 5;
  string side = 6;
  Quantity quantity = 7;
  string type = 8;
  string time_in_force = 9;
  Price limit_price = 10;
  string status = 11;
  // broker_status mirrors the raw status reported by the broker.
  string broker_status = 12;
  BacktestTrade fill = 13;
  string rejection_reason = 14;
  int64 created_at_unix_ms = 15;
  int64 updated_at_unix_ms = 16;
}

// LiveCashBalance is a single currency-denominated cash entry in a live account.
// Raw account numbers and provider-specific identifiers are never included.
message LiveCashBalance {
  Currency currency = 1;
  Decimal amount = 2;
}

// LiveAccountSnapshot carries sanitized live account state from a broker.
// Raw account numbers and provider payload are never exposed.
message LiveAccountSnapshot {
  string account_id = 1;
  string broker = 2;
  repeated LiveCashBalance cash = 3;
  repeated LivePositionSnapshot positions = 4;
  int64 synced_at_unix_ms = 5;
  bool stale = 6;
}

// SyncLiveAccountRequest triggers a fresh account snapshot fetch from the broker.
message SyncLiveAccountRequest {
  string account_id = 1;
}

// SyncLiveAccountResponse returns the refreshed snapshot or a typed error.
message SyncLiveAccountResponse {
  LiveAccountSnapshot snapshot = 1;
  ErrorInfo error = 2;
}

// GetLiveAccountSnapshotRequest retrieves the last synced account snapshot.
message GetLiveAccountSnapshotRequest {
  string account_id = 1;
}

// GetLiveAccountSnapshotResponse returns the cached snapshot or a typed error.
message GetLiveAccountSnapshotResponse {
  LiveAccountSnapshot snapshot = 1;
  ErrorInfo error = 2;
}

// LivePositionSnapshot is a single position inside a live account.
message LivePositionSnapshot {
  string instrument_id = 1;
  string side = 2;
  Quantity quantity = 3;
  Price avg_price = 4;
  Price current_price = 5;
  Decimal market_value = 6;
  Decimal pnl = 7;
}

// LiveAuditEvent is a durable, broker-neutral record of a live operation event.
// Payload must never carry raw tokens, account numbers, or provider bodies.
message LiveAuditEvent {
  string type = 1;
  int64 timestamp_unix_ms = 2;
  string broker = 3;
  string account_id = 4;
  map<string, string> payload = 5;
  string event_id = 6;
  string order_id = 7;
  string status = 8;
  string reason = 9;
  string actor = 10;
  string correlation_id = 11;
}

// ListLiveAuditEventsRequest queries the durable audit trail with optional
// filters by account, order, and event type.
message ListLiveAuditEventsRequest {
  string account_id = 1;
  string order_id = 2;
  string event_type = 3;
  int32 limit = 4;
}

// ListLiveAuditEventsResponse returns the matching audit event records or a
// typed error.
message ListLiveAuditEventsResponse {
  repeated LiveAuditEvent events = 1;
  ErrorInfo error = 2;
}

// OperatorConfirmation is the explicit operator gate required before any live
// order reaches the broker. A missing or unconfirmed field causes the worker to
// return invalid_request without touching the broker.
message OperatorConfirmation {
  bool confirmed = 1;
  string operator_id = 2;
  string reason = 3;
  int64 confirmed_at_unix_ms = 4;
}

// SubmitLiveOrderRequest submits a live order through the broker. The
// operator_confirmation gate must be present and confirmed=true or the worker
// returns invalid_request.
message SubmitLiveOrderRequest {
  string account_id = 1;
  LiveOrderIntent intent = 2;
  OperatorConfirmation operator_confirmation = 3;
  string idempotency_key = 4;
}

// LiveRiskDecision carries the outcome of a risk policy evaluation for a live
// order submission. It is included in SubmitLiveOrderResponse when the risk
// guard blocked the order so headless operators can surface the denial reason
// alongside the rejected order record.
message LiveRiskDecision {
  bool allowed = 1;
  string reason = 2;
}

// SubmitLiveOrderResponse carries the submitted live order or a typed error.
// When the order was blocked by the risk policy, order carries the rejected
// in-memory record and risk_decision carries the denial reason.
message SubmitLiveOrderResponse {
  LiveOrder order = 1;
  ErrorInfo error = 2;
  LiveRiskDecision risk_decision = 3;
}

// CancelLiveOrderRequest cancels a pending live order by its live order id.
message CancelLiveOrderRequest {
  string account_id = 1;
  string live_order_id = 2;
}

// CancelLiveOrderResponse carries the cancelled order or a typed error.
message CancelLiveOrderResponse {
  LiveOrder order = 1;
  ErrorInfo error = 2;
}

// GetLiveOrderRequest retrieves the current state of a live order.
message GetLiveOrderRequest {
  string account_id = 1;
  string live_order_id = 2;
}

// GetLiveOrderResponse carries the retrieved live order or a typed error.
message GetLiveOrderResponse {
  LiveOrder order = 1;
  ErrorInfo error = 2;
}

// LiveRiskPolicy describes the active risk limits applied before any live order
// reaches the broker. All limits are adjustable at runtime; a zero value for
// a numeric limit means the limit is not enforced.
message LiveRiskPolicy {
  // max_order_notional_by_currency maps a currency code (e.g. "KRW", "USD")
  // to the maximum allowed notional value per order as a decimal string.
  map<string, string> max_order_notional_by_currency = 1;
  int32 max_daily_orders = 2;
  int32 max_open_orders = 3;
  bool allow_short_selling = 4;
}

// LiveKillSwitchState captures whether live order submission is globally halted.
// The safe default is halted=true; operators must explicitly disable the kill
// switch before any live order can reach the broker.
message LiveKillSwitchState {
  bool halted = 1;
  string reason = 2;
}

// GetLiveRiskPolicyRequest queries the active risk policy for a live account.
message GetLiveRiskPolicyRequest {
  string account_id = 1;
}

// GetLiveRiskPolicyResponse returns the active risk policy or a typed error.
message GetLiveRiskPolicyResponse {
  LiveRiskPolicy policy = 1;
  ErrorInfo error = 2;
}

// GetLiveKillSwitchRequest queries the current kill switch state.
message GetLiveKillSwitchRequest {
  string account_id = 1;
}

// GetLiveKillSwitchResponse returns the current kill switch state or a typed error.
message GetLiveKillSwitchResponse {
  LiveKillSwitchState state = 1;
  ErrorInfo error = 2;
}

// SetLiveKillSwitchRequest sets the kill switch to halted or unhalted.
message SetLiveKillSwitchRequest {
  string account_id = 1;
  bool halted = 2;
  string reason = 3;
}

// SetLiveKillSwitchResponse returns the new kill switch state or a typed error.
message SetLiveKillSwitchResponse {
  LiveKillSwitchState state = 1;
  ErrorInfo error = 2;
}
