package accounts import ( "encoding/json" decimal "github.com/alpacahq/alpacadecimal" "s1d3sw1ped/robinhood-agentic-mcp/internal/wire" ) func (r *RealizedPnLResult) UnmarshalJSON(b []byte) error { var wrap struct { Total any `json:"total"` TotalGain any `json:"total_gain"` Percent any `json:"percent"` TotalPct any `json:"total_percent"` Buckets []struct { Label string `json:"label"` Name string `json:"name"` Amount any `json:"amount"` Gain any `json:"gain"` Percent any `json:"percent"` Trades int `json:"trades"` Count int `json:"count"` } `json:"buckets"` Results []struct { Label string `json:"label"` Amount any `json:"amount"` Percent any `json:"percent"` Trades int `json:"trades"` } `json:"results"` } if err := json.Unmarshal(wire.Unwrap(b), &wrap); err != nil { return err } var err error if r.Total, err = firstDec(wrap.Total, wrap.TotalGain); err != nil { return err } if r.Percent, err = firstDec(wrap.Percent, wrap.TotalPct); err != nil { return err } src := wrap.Buckets if len(src) == 0 { for _, row := range wrap.Results { src = append(src, struct { Label string `json:"label"` Name string `json:"name"` Amount any `json:"amount"` Gain any `json:"gain"` Percent any `json:"percent"` Trades int `json:"trades"` Count int `json:"count"` }{Label: row.Label, Amount: row.Amount, Percent: row.Percent, Trades: row.Trades}) } } r.Buckets = make([]PnLBucket, 0, len(src)) for _, row := range src { label := row.Label if label == "" { label = row.Name } amt, err := firstDec(row.Amount, row.Gain) if err != nil { return err } pct, err := firstDec(row.Percent) if err != nil { return err } n := row.Trades if n == 0 { n = row.Count } r.Buckets = append(r.Buckets, PnLBucket{Label: label, Amount: amt, Percent: pct, Trades: n}) } return nil } func (r *PnLTradeHistoryResult) UnmarshalJSON(b []byte) error { type row struct { Symbol string `json:"symbol"` Side string `json:"side"` Quantity any `json:"quantity"` Price any `json:"price"` PnL any `json:"realized_gain"` Gain any `json:"gain"` } rows, next, err := wire.UnmarshalRows[row](b, "trades", "results") if err != nil { return err } r.NextCursor = next r.Trades = make([]PnLTrade, 0, len(rows)) for _, row := range rows { qty, err := firstDec(row.Quantity) if err != nil { return err } px, err := firstDec(row.Price) if err != nil { return err } pnl, err := firstDec(row.PnL, row.Gain) if err != nil { return err } r.Trades = append(r.Trades, PnLTrade{Symbol: row.Symbol, Side: row.Side, Quantity: qty, Price: px, PnL: pnl}) } return nil } func (r *UpgradeInfoResult) UnmarshalJSON(b []byte) error { var wrap struct { URL string `json:"url"` WebURL string `json:"web_url"` MobileURL string `json:"mobile_url"` Links struct { Web string `json:"web"` Mobile string `json:"mobile"` } `json:"links"` } if err := json.Unmarshal(wire.Unwrap(b), &wrap); err != nil { return err } r.URL = wrap.URL r.WebURL = wrap.WebURL if r.WebURL == "" { r.WebURL = wrap.Links.Web } r.MobileURL = wrap.MobileURL if r.MobileURL == "" { r.MobileURL = wrap.Links.Mobile } if r.URL == "" { r.URL = r.WebURL } return nil } func (r *OnboardingInfoResult) UnmarshalJSON(b []byte) error { var wrap struct { URL string `json:"url"` WebURL string `json:"web_url"` } if err := json.Unmarshal(wire.Unwrap(b), &wrap); err != nil { return err } r.URL = wrap.URL r.WebURL = wrap.WebURL if r.URL == "" { r.URL = r.WebURL } return nil } func (r *SearchResult) UnmarshalJSON(b []byte) error { type row struct { Symbol string `json:"symbol"` Name string `json:"name"` ID string `json:"id"` InstrumentID string `json:"instrument_id"` } rows, _, err := wire.UnmarshalRows[row](b, "results", "instruments") if err != nil { return err } r.Results = make([]SearchHit, 0, len(rows)) for _, row := range rows { r.Results = append(r.Results, SearchHit{ Symbol: row.Symbol, Name: row.Name, ID: row.ID, InstrumentID: row.InstrumentID, }) } return nil } func firstDec(vs ...any) (decimal.Decimal, error) { for _, v := range vs { if v == nil { continue } if s, ok := v.(string); ok && s == "" { continue } return wire.Dec(v) } return decimal.Zero, nil }