package trading

import (
	"time"

	"git.toki-labs.com/toki/alt/packages/domain/market"
)

// Broker identifies a live trading provider. The string vocabulary is open so
// new brokers can be added without changing the type definition. "kis" is the
// only broker known at this stage of development.
type Broker string

const BrokerKIS Broker = "kis"

// OrderType expresses the execution style of a live order. The set is kept
// small and additive; brokers may supply custom strings that are preserved as-
// is rather than rejected as unknown.
type OrderType string

const (
	OrderTypeMarket OrderType = "market"
	OrderTypeLimit  OrderType = "limit"
)

// OrderSide expresses buy or sell direction. Consistent with the backtest
// package so operator-facing surfaces stay uniform across modes.
type OrderSide string

const (
	OrderSideBuy  OrderSide = "buy"
	OrderSideSell OrderSide = "sell"
)

// OrderTimeInForce captures the duration an order remains active before
// expiration. The vocabulary is additive: brokers may return values not
// listed here, and the type preserves them verbatim.
type OrderTimeInForce string

const (
	OrderTimeInForceDay OrderTimeInForce = "day"
	OrderTimeInForceGTC OrderTimeInForce = "gtc"
	OrderTimeInForceIOC OrderTimeInForce = "ioc"
	OrderTimeInForceFOK OrderTimeInForce = "fok"
)

// OrderStatus tracks the lifecycle state of a live order from the broker's
// perspective. The string type avoids closing the vocabulary to a fixed set
// of states that might not cover every broker's behaviour.
type OrderStatus string

const (
	OrderStatusPending         OrderStatus = "pending"
	OrderStatusSubmitted       OrderStatus = "submitted"
	OrderStatusPartiallyFilled OrderStatus = "partially_filled"
	OrderStatusFilled          OrderStatus = "filled"
	OrderStatusCanceled        OrderStatus = "canceled"
	OrderStatusRejected        OrderStatus = "rejected"
)

// BrokerStatus mirrors the raw status string reported by the broker in an
// account snapshot or order report. It is string-typed so unknown broker
// codes do not cause data loss.
type BrokerStatus string

// BrokerOrderRef holds broker-assigned identifiers for a live order.
type BrokerOrderRef struct {
	BrokerID string
	ClientID string
}

// OrderIntent mirrors the backtest OrderIntent shape but belongs to the live
// trading domain so it can carry broker-specific metadata while retaining the
// shared market.Price / market.Quantity / market.Decimal types. No float
// fields are used.
type OrderIntent struct {
	InstrumentID market.InstrumentID
	Side         OrderSide
	Quantity     market.Quantity
	Type         OrderType
	TimeInForce  OrderTimeInForce
	LimitPrice   market.Price
	BrokerRef    BrokerOrderRef
	CustomTags   map[string]string
}

// OrderType returns the order type, defaulting to market when the field is
// empty for convenience.
func (o OrderIntent) OrderType() OrderType {
	if o.Type == "" {
		return OrderTypeMarket
	}
	return o.Type
}

// AccountSnapshot carries live account state reported by a broker.
type AccountSnapshot struct {
	Broker           Broker
	AccountID        string
	Cash             market.Decimal
	TotalEquity      market.Decimal
	Available_margin market.Decimal
	SnapshotTime     time.Time
}

// PositionSnapshot is a single position inside a live account.
type PositionSnapshot struct {
	InstrumentID market.InstrumentID
	Side         OrderSide
	Quantity     market.Quantity
	AvgPrice     market.Price
	CurrentPrice market.Price
	MarketValue  market.Decimal
	PnL          market.Decimal
}

// AuditEvent is a broker-neutral event record that can be replayed or
// inspected later. The Type field is additive.
type AuditEvent struct {
	Type      string
	Timestamp time.Time
	Broker    Broker
	AccountID string
	Detail    map[string]string
}

// BrokerCapability describes what a live broker supports. The method set is
// open so future methods can expose deeper introspection without changing the
// struct definition.
type BrokerCapability struct {
	Broker            Broker
	Markets           map[market.Market]bool
	Venues            map[market.Venue]bool
	OrderTypes        []OrderType
	SupportsAmend     bool
	SupportsCancel    bool
	SupportsAccount   bool
	SupportsAuditTags bool
	CheckedAt         time.Time
}

// HasMarket checks whether the capability list includes the requested market.
func (c BrokerCapability) HasMarket(market market.Market) bool {
	return c.Markets[market]
}

// HasVenue checks whether the capability list includes the requested venue.
func (c BrokerCapability) HasVenue(venue market.Venue) bool {
	return c.Venues[venue]
}

// HasOrderType returns whether the broker advertises the given order type.
func (c BrokerCapability) HasOrderType(t OrderType) bool {
	for _, ty := range c.OrderTypes {
		if ty == t {
			return true
		}
	}
	return false
}
