/**
 * Budget parsing and formatting helpers.
 *
 * A budget is a soft daily USD ceiling. When today's spend crosses 75%
 * of the limit, a warning surfaces in /cost; at 100%+ the warning
 * escalates but no call is blocked (review specifies "soft warnings").
 */

export type BudgetConfig = {
  dailyLimitUSD: number
}

const MAX_REASONABLE_BUDGET_USD = 10_000

/**
 * Parse a user-provided budget spec into a BudgetConfig.
 * Returns:
 *   - BudgetConfig on a positive amount (e.g. "5", "$5", "$5/day")
 *   - null when the user is explicitly clearing ("off", "clear", "0")
 *   - undefined when the input is invalid (garbage, negative, absurd)
 */
export function parseBudgetSpec(spec: string): BudgetConfig | null | undefined {
  const normalized = spec.trim().toLowerCase()
  if (normalized === '') return undefined
  if (normalized === 'off' || normalized === 'clear' || normalized === 'none') {
    return null
  }

  let s = normalized
  // Strip trailing "/day" or "/d" for convenience
  s = s.replace(/\/(day|d)$/, '').trim()
  // Strip a single leading $
  const dollarMatch = s.match(/^\$?([0-9]+(?:\.[0-9]+)?)$/)
  if (!dollarMatch) return undefined

  const amount = parseFloat(dollarMatch[1]!)
  if (!Number.isFinite(amount) || amount < 0) return undefined
  if (amount === 0) return null
  if (amount > MAX_REASONABLE_BUDGET_USD) return undefined

  return { dailyLimitUSD: amount }
}

export type BudgetWarningLevel = 'ok' | 'warn' | 'over'

export function getBudgetWarningLevel(
  config: BudgetConfig | null,
  spendUSD: number,
): BudgetWarningLevel {
  if (!config || config.dailyLimitUSD <= 0) return 'ok'
  const ratio = spendUSD / config.dailyLimitUSD
  if (ratio >= 1) return 'over'
  if (ratio >= 0.75) return 'warn'
  return 'ok'
}

function formatUSD(amount: number): string {
  if (amount >= 0.5) {
    return `$${amount.toFixed(2)}`
  }
  return `$${amount.toFixed(4).replace(/0+$/, '').replace(/\.$/, '')}`
}

/**
 * Render a one-line budget status for /cost.
 */
export function formatBudgetLine(config: BudgetConfig | null, spendUSD: number): string {
  if (!config) return 'No daily budget set (`/budget set $5` to enable)'
  const pct = Math.round((spendUSD / config.dailyLimitUSD) * 100)
  const level = getBudgetWarningLevel(config, spendUSD)
  const base = `${formatUSD(spendUSD)} / ${formatUSD(config.dailyLimitUSD)} (${pct}%)`
  if (level === 'over') return `${base} — OVER BUDGET`
  if (level === 'warn') return `${base} — approaching limit`
  return base
}

/**
 * Per-day, per-level "we've already told the user" record. Keyed by
 * local-date YYYY-MM-DD so a new day resets both thresholds.
 */
export type BudgetWarningShownState = {
  warn?: string
  over?: string
}

/**
 * Decide whether a post-turn budget warning should be surfaced, and
 * at which level. Pure — all state passed in as args so this is
 * trivially testable and the UI wiring stays thin.
 *
 * Emits 'warn' the first time today's spend crosses 75% of the
 * limit; 'over' the first time it crosses 100%. If 'over' is newly
 * reached without 'warn' having fired (user jumped past 75% in a
 * single expensive turn), 'over' is emitted — we never backfill a
 * 'warn' that was skipped.
 *
 * Returns null when no new threshold crossed on this turn.
 */
export function shouldEmitBudgetWarning(
  config: BudgetConfig | null,
  spendUSD: number,
  shown: BudgetWarningShownState,
  todayKey: string,
): BudgetWarningLevel | null {
  const level = getBudgetWarningLevel(config, spendUSD)
  if (level === 'ok') return null
  if (level === 'over' && shown.over !== todayKey) return 'over'
  if (level === 'warn' && shown.warn !== todayKey && shown.over !== todayKey) {
    return 'warn'
  }
  return null
}

/**
 * Render the post-turn warning sentence. The UI inserts it as a
 * system-`warning` message in the chat scrollback.
 */
export function formatBudgetWarningMessage(
  config: BudgetConfig,
  spendUSD: number,
  level: BudgetWarningLevel,
): string {
  const base = formatBudgetLine(config, spendUSD)
  if (level === 'over') {
    return `Daily budget exceeded — ${base}. Use \`/budget clear\` to disable or \`/budget set\` a higher limit.`
  }
  return `Daily budget at ${base}. Consider pausing or adjusting with \`/budget set\`.`
}
