package main

// pricing.go centralises model pricing as a per-model table (the LiteLLM pattern)
// instead of three hardcoded Grok fields. The spend ledger prices each call by the
// model it actually used, so when a second model (Gemini) starts answering some
// routes, its cost books correctly against the same global ceiling.

// ModelPrice is the per-1M-token USD price for one model, applied to the API's
// returned usage so the wallet ceiling tracks real cost even as prices change.
type ModelPrice struct {
	InputPerM  float64 // non-cached prompt tokens
	CachedPerM float64 // prompt tokens served from the provider cache (cheaper)
	OutputPerM float64 // completion tokens
}

// CostBreakdown is the per-component USD cost of answering one request. A plain
// grok_direct call has only Token; a cascade adds Router (the cheap classifier),
// Grounding (Gemini Google-search) and/or WebTool (Grok web search) on top. Settle
// books each column separately so the ledger and request_log can attribute spend,
// and so a half-finished cascade can book only what it actually spent (§8.1).
type CostBreakdown struct {
	Token     float64
	Grounding float64 // Gemini grounded-prompt TOKEN cost
	WebTool   float64
	Router    float64
	// GroundingFee is the per-grounded-prompt FEE (the $35/1k overage on a paid Gemini
	// tier, GEMINI_GROUNDING_PER_PROMPT_USD) — kept separate from Grounding (the token
	// cost) for clean analytics. Booked the moment the grounded prompt is admitted, even
	// on the error return (§7 SG1). Settle folds it into the grounding_usd spend column,
	// so the $10 ceiling finally sees it without a spend-table migration.
	GroundingFee float64
}

// Total is the grand total across all components (the number the wallet ceiling and
// request_log.total_usd care about). Computed, never stored, so it can't drift.
func (c CostBreakdown) Total() float64 {
	return c.Token + c.Grounding + c.WebTool + c.Router + c.GroundingFee
}

// priceFor returns the configured price for a model. An unknown model falls back to
// the default (final-voice) model's price rather than $0 — a $0 price would silently
// blind the global ceiling to that call, the one failure mode we never want.
func (c *Config) priceFor(model string) ModelPrice {
	if p, ok := c.Prices[model]; ok {
		return p
	}
	return c.Prices[c.XAIModel]
}
