/**
 * Per-model pricing in USD per million tokens. Used to estimate the
 * cost of an AIGeneration row from its tokensIn/tokensOut.
 *
 * Prices change. This table is a best-effort starting point for
 * common models as of mid-2026; users on other models will see
 * `null` cost (we still surface token counts). Updating: edit this
 * file and ship — no schema change needed.
 *
 * Matching strategy: case-insensitive prefix lookup against the
 * user's configured model string. Model names like
 * "claude-sonnet-4-5-20251022" match the "claude-sonnet-4-5" prefix.
 *
 * Keys are organized by provider for readability but the lookup is
 * provider-agnostic — the model string is the key.
 */

interface PriceEntry {
  inputPerM: number; // USD per 1M input tokens
  outputPerM: number; // USD per 1M output tokens
}

const PRICES: Record<string, PriceEntry> = {
  // Anthropic Claude (Messages API) — opus tier $15/$75, sonnet $3/$15,
  // haiku $0.80/$4. New point releases inherit their tier's pricing.
  'claude-opus-4-7': { inputPerM: 15, outputPerM: 75 },
  'claude-opus-4-6': { inputPerM: 15, outputPerM: 75 },
  'claude-opus-4-5': { inputPerM: 15, outputPerM: 75 },
  'claude-opus-4': { inputPerM: 15, outputPerM: 75 },
  'claude-sonnet-4-6': { inputPerM: 3, outputPerM: 15 },
  'claude-sonnet-4-5': { inputPerM: 3, outputPerM: 15 },
  'claude-sonnet-4': { inputPerM: 3, outputPerM: 15 },
  'claude-haiku-4-5': { inputPerM: 0.8, outputPerM: 4 },
  'claude-haiku-4': { inputPerM: 0.8, outputPerM: 4 },
  'claude-3-7-sonnet': { inputPerM: 3, outputPerM: 15 },
  'claude-3-5-sonnet': { inputPerM: 3, outputPerM: 15 },
  'claude-3-5-haiku': { inputPerM: 0.8, outputPerM: 4 },

  // OpenAI — gpt-5.x flagships ~$1.25-$2/$10-$15, mini/nano cheaper
  'gpt-5.5': { inputPerM: 2, outputPerM: 15 },
  'gpt-5.4': { inputPerM: 1.5, outputPerM: 12 },
  'gpt-5.4-mini': { inputPerM: 0.3, outputPerM: 2.4 },
  'gpt-5.4-nano': { inputPerM: 0.06, outputPerM: 0.5 },
  'gpt-5.3': { inputPerM: 1.5, outputPerM: 12 },
  'gpt-5.2': { inputPerM: 1.5, outputPerM: 12 },
  'gpt-5.1': { inputPerM: 1.25, outputPerM: 10 },
  'gpt-5': { inputPerM: 1.25, outputPerM: 10 },
  'gpt-5-mini': { inputPerM: 0.25, outputPerM: 2 },
  'gpt-5-nano': { inputPerM: 0.05, outputPerM: 0.4 },
  'gpt-4o': { inputPerM: 2.5, outputPerM: 10 },
  'gpt-4o-mini': { inputPerM: 0.15, outputPerM: 0.6 },
  'o1': { inputPerM: 15, outputPerM: 60 },
  'o3': { inputPerM: 2, outputPerM: 8 },
  'o3-mini': { inputPerM: 1.1, outputPerM: 4.4 },
  'o4-mini': { inputPerM: 1.1, outputPerM: 4.4 },

  // Google Gemini — Gemini 3.1 Pro is $2/$12 standard; >200K ctx is 2x.
  // Gemini 3 Flash is $0.50/$3. 3.1 Flash-Lite is the cheapest of the
  // 3.x line. Both short names (gemini-3.1-pro) and long preview names
  // (gemini-3.1-pro-preview) are accepted by the API and listed here.
  'gemini-3.1-pro-preview': { inputPerM: 2, outputPerM: 12 },
  'gemini-3.1-pro': { inputPerM: 2, outputPerM: 12 },
  'gemini-3.1-flash-lite': { inputPerM: 0.1, outputPerM: 0.4 },
  'gemini-3.1-flash': { inputPerM: 0.5, outputPerM: 3 },
  'gemini-3-pro-preview': { inputPerM: 2, outputPerM: 12 },
  'gemini-3-pro': { inputPerM: 2, outputPerM: 12 },
  'gemini-3-flash-preview': { inputPerM: 0.5, outputPerM: 3 },
  'gemini-3-flash': { inputPerM: 0.5, outputPerM: 3 },
  'gemini-2.5-pro': { inputPerM: 1.25, outputPerM: 10 },
  'gemini-2.5-flash': { inputPerM: 0.3, outputPerM: 2.5 },
  'gemini-2.0-flash': { inputPerM: 0.1, outputPerM: 0.4 },
  'gemini-2.0-pro': { inputPerM: 1.25, outputPerM: 5 },
  'gemini-1.5-pro': { inputPerM: 1.25, outputPerM: 5 },
  'gemini-1.5-flash': { inputPerM: 0.075, outputPerM: 0.3 },
};

/**
 * Per-provider model menus — source of truth for the "Model" dropdown
 * in Settings → AI integration. `recommended` floats to the top. Users
 * can still type a custom model name (the dropdown has an "Other"
 * option that switches to free-text input). Order = display order.
 *
 * Update these when new models ship. Keys correspond to provider IDs
 * in lib/ai/providers/index.ts.
 */
export interface ModelOption {
  /** Exact API model identifier */
  id: string;
  /** Human-readable label shown in the dropdown */
  label: string;
  /** Floats to the top + gets a "★" mark */
  recommended?: boolean;
}

export const MODEL_MENU: Record<string, ModelOption[]> = {
  claude: [
    { id: 'claude-opus-4-7', label: 'Claude Opus 4.7 (most capable)', recommended: true },
    { id: 'claude-sonnet-4-6', label: 'Claude Sonnet 4.6 (1M context, fast)', recommended: true },
    { id: 'claude-haiku-4-5', label: 'Claude Haiku 4.5 (cheapest, fastest)', recommended: true },
    { id: 'claude-opus-4-6', label: 'Claude Opus 4.6' },
    { id: 'claude-sonnet-4-5', label: 'Claude Sonnet 4.5' },
    { id: 'claude-3-7-sonnet-latest', label: 'Claude 3.7 Sonnet' },
  ],
  openai: [
    { id: 'gpt-5.5', label: 'GPT-5.5 (most capable)', recommended: true },
    { id: 'gpt-5.4', label: 'GPT-5.4', recommended: true },
    { id: 'gpt-5.4-mini', label: 'GPT-5.4 Mini (cheap, fast)', recommended: true },
    { id: 'gpt-5.4-nano', label: 'GPT-5.4 Nano (cheapest)' },
    { id: 'gpt-5', label: 'GPT-5' },
    { id: 'gpt-4o', label: 'GPT-4o (legacy)' },
    { id: 'o3', label: 'o3 (reasoning)' },
  ],
  gemini: [
    // Names match what Google's AI Studio dropdown shows. Both short
    // (gemini-3.1-pro) and long preview names work via the API; we
    // ship the short forms because that's what the Studio UI uses.
    { id: 'gemini-3.1-pro', label: 'Gemini 3.1 Pro (most capable)', recommended: true },
    { id: 'gemini-3.1-flash', label: 'Gemini 3.1 Flash (fast, cheap)', recommended: true },
    { id: 'gemini-3.1-flash-lite', label: 'Gemini 3.1 Flash Lite (cheapest)', recommended: true },
    { id: 'gemini-3-pro', label: 'Gemini 3 Pro' },
    { id: 'gemini-3-flash', label: 'Gemini 3 Flash' },
    { id: 'gemini-2.5-pro', label: 'Gemini 2.5 Pro' },
    { id: 'gemini-2.5-flash', label: 'Gemini 2.5 Flash' },
    { id: 'gemini-2.0-flash', label: 'Gemini 2.0 Flash (legacy)' },
  ],
  // openai-compatible + ollama: no curated menu — model names are
  // gateway- or host-specific. Ollama auto-detects via /api/tags.
  'openai-compatible': [],
  ollama: [],
};

/** Find the price entry whose key is a (case-insensitive) prefix of the model string. */
export function findPrice(model: string): PriceEntry | null {
  const m = model.toLowerCase();
  // Longest-prefix-first so e.g. "claude-sonnet-4-5" beats "claude-sonnet-4".
  const sortedKeys = Object.keys(PRICES).sort((a, b) => b.length - a.length);
  for (const key of sortedKeys) {
    if (m.startsWith(key.toLowerCase())) return PRICES[key];
  }
  return null;
}

/**
 * Estimate the USD cost of a generation. Returns null if the model
 * isn't in the price table or if either token count is missing.
 * Ollama and openai-compatible custom gateways always return null
 * (they're either free or self-priced).
 */
export function estimateCost(opts: {
  provider: string;
  model: string;
  tokensIn: number | null;
  tokensOut: number | null;
}): number | null {
  if (opts.provider === 'ollama') return 0; // self-hosted, no per-token cost
  if (opts.provider === 'openai-compatible') return null; // we don't know the gateway's pricing
  if (opts.tokensIn == null || opts.tokensOut == null) return null;
  const price = findPrice(opts.model);
  if (!price) return null;
  return (
    (opts.tokensIn / 1_000_000) * price.inputPerM +
    (opts.tokensOut / 1_000_000) * price.outputPerM
  );
}

/** Format USD to a string suitable for a UI label. Below $0.01 -> "<$0.01". */
export function formatCost(usd: number | null): string {
  if (usd == null) return '—';
  if (usd === 0) return 'free';
  if (usd < 0.01) return '<$0.01';
  if (usd < 1) return `$${usd.toFixed(3)}`;
  return `$${usd.toFixed(2)}`;
}
