/**
 * Deterministic OpenRouter pricing match + arithmetic (SET 9 / SET 12).
 * Never guess: no match → price unavailable; private host → $0 local.
 */
import { isPrivateHost } from '../core/netHost';

export interface ModelPrice {
  promptUsdPerTok: number;
  completionUsdPerTok: number;
  /** Unix seconds when present on the feed — used to pick newest family member. */
  created?: number;
}

export type PricingTable = Record<string, ModelPrice>;

export interface PricingFeed {
  table: PricingTable;
  fetchedAt: string;
  stale?: boolean;
  unavailable?: boolean;
}

export type MatchPricingResult =
  | { matched: true; id: string; price: ModelPrice; how: 'exact' | 'normalized' }
  | { matched: false; reason: string };

/** Strip provider prefix, lowercase, drop :free / -it / other :routing suffixes. */
export function normalizeModelId(id: string): string {
  let s = id.trim().toLowerCase();
  const slash = s.lastIndexOf('/');
  if (slash >= 0) s = s.slice(slash + 1);
  s = s.replace(/:free$/i, '');
  const colon = s.indexOf(':');
  if (colon >= 0) s = s.slice(0, colon);
  s = s.replace(/-it$/i, '');
  return s;
}

export function matchPricing(modelId: string, table: PricingTable): MatchPricingResult {
  if (!modelId?.trim()) return { matched: false, reason: 'price unavailable for (empty model)' };
  if (table[modelId]) {
    return { matched: true, id: modelId, price: table[modelId], how: 'exact' };
  }
  const want = normalizeModelId(modelId);
  if (!want) return { matched: false, reason: `price unavailable for ${modelId}` };
  const hits: string[] = [];
  for (const id of Object.keys(table)) {
    if (normalizeModelId(id) === want) hits.push(id);
  }
  if (hits.length === 1) {
    return { matched: true, id: hits[0], price: table[hits[0]], how: 'normalized' };
  }
  if (hits.length > 1) {
    return { matched: false, reason: `price unavailable for ${modelId}` };
  }
  return { matched: false, reason: `price unavailable for ${modelId}` };
}

export interface CostLine {
  kind: 'local' | 'estimated' | 'unavailable';
  label: string;
  usdTotal: number | null;
  usdIn: number | null;
  usdOut: number | null;
  matchedId?: string;
}

export function estimateCost(opts: {
  modelId: string;
  tokensIn: number;
  tokensOut: number;
  table: PricingTable;
  /** Provider base URL — private → $0 local compute. */
  baseURL?: string;
  /** Explicit local/private override. */
  privateHost?: boolean;
}): CostLine {
  const local = opts.privateHost === true
    || (!!opts.baseURL && isPrivateHost(opts.baseURL));
  if (local) {
    return {
      kind: 'local',
      label: '$0.00 (local compute)',
      usdTotal: 0,
      usdIn: 0,
      usdOut: 0,
    };
  }
  const m = matchPricing(opts.modelId, opts.table);
  if (!m.matched) {
    return {
      kind: 'unavailable',
      label: m.reason,
      usdTotal: null,
      usdIn: null,
      usdOut: null,
    };
  }
  const usdIn = opts.tokensIn * m.price.promptUsdPerTok;
  const usdOut = opts.tokensOut * m.price.completionUsdPerTok;
  return {
    kind: 'estimated',
    label: `estimated $${(usdIn + usdOut).toFixed(4)}`,
    usdTotal: usdIn + usdOut,
    usdIn,
    usdOut,
    matchedId: m.id,
  };
}

/** SET 12 family patterns — members resolved from the live feed, never hardcoded. */
export const COST_FAMILIES: { key: string; label: string; test: (id: string) => boolean }[] = [
  { key: 'claude', label: 'Claude', test: id => /^anthropic\/claude-/i.test(id) },
  { key: 'chatgpt', label: 'ChatGPT', test: id => /^openai\/gpt-/i.test(id) },
  { key: 'gemini', label: 'Gemini', test: id => /^google\/gemini-/i.test(id) },
  { key: 'grok', label: 'Grok', test: id => /^x-ai\/grok-/i.test(id) },
  { key: 'kimi', label: 'Kimi', test: id => /^moonshotai\/kimi-/i.test(id) },
  { key: 'glm', label: 'Z.ai GLM', test: id => /^z-ai\/glm-/i.test(id) },
  { key: 'deepseek', label: 'DeepSeek', test: id => /^deepseek\/deepseek-/i.test(id) },
  { key: 'qwen', label: 'Qwen', test: id => /^qwen\/qwen/i.test(id) },
];

/** True for :free or other :routing / -it tagged variants we skip for the roster. */
export function isSuffixVariant(id: string): boolean {
  if (/:free\b/i.test(id)) return true;
  if (/:[a-z0-9_-]+$/i.test(id)) return true;
  if (/-it$/i.test(id.split('/').pop() || '')) return true;
  return false;
}

/**
 * Newest non-:free non-suffix member per family from the feed.
 * Absent families are omitted (never invent ids).
 */
export function pickFamilyRefs(table: PricingTable): { key: string; label: string; id: string; price: ModelPrice }[] {
  const out: { key: string; label: string; id: string; price: ModelPrice }[] = [];
  for (const fam of COST_FAMILIES) {
    let best: { id: string; price: ModelPrice; created: number } | null = null;
    for (const [id, price] of Object.entries(table)) {
      if (!fam.test(id) || isSuffixVariant(id)) continue;
      const created = price.created ?? 0;
      if (!best || created > best.created || (created === best.created && id > best.id)) {
        best = { id, price, created };
      }
    }
    if (best) out.push({ key: fam.key, label: fam.label, id: best.id, price: best.price });
  }
  return out;
}

export function comparativeCosts(
  tokensIn: number,
  tokensOut: number,
  table: PricingTable,
): { label: string; id: string; usdTotal: number; usdIn: number; usdOut: number }[] {
  return pickFamilyRefs(table).map(r => {
    const usdIn = tokensIn * r.price.promptUsdPerTok;
    const usdOut = tokensOut * r.price.completionUsdPerTok;
    return {
      label: r.label,
      id: r.id,
      usdTotal: usdIn + usdOut,
      usdIn,
      usdOut,
    };
  });
}

export function formatUsd(n: number | null | undefined, digits = 4): string {
  if (n == null || !Number.isFinite(n)) return '—';
  if (n === 0) return '$0.00';
  if (Math.abs(n) < 0.0001) return `$${n.toExponential(2)}`;
  return `$${n.toFixed(digits)}`;
}

/** Persistable cost snapshot for a run record. */
export interface RunCostSnapshot {
  kind: CostLine['kind'];
  label: string;
  usdTotal: number | null;
  usdIn: number | null;
  usdOut: number | null;
  matchedId?: string;
  modelId: string;
  tokensIn: number;
  tokensOut: number;
  comparative: { label: string; id: string; usdTotal: number; usdIn: number; usdOut: number }[];
  provenance: string;
  fetchedAt: string;
  stale?: boolean;
}

export function buildRunCostSnapshot(opts: {
  modelId: string;
  tokensIn: number;
  tokensOut: number;
  feed: PricingFeed;
  baseURL?: string;
  privateHost?: boolean;
}): RunCostSnapshot | null {
  if (opts.feed.unavailable || !opts.feed.table || !Object.keys(opts.feed.table).length) {
    return null;
  }
  const line = estimateCost({
    modelId: opts.modelId,
    tokensIn: opts.tokensIn,
    tokensOut: opts.tokensOut,
    table: opts.feed.table,
    baseURL: opts.baseURL,
    privateHost: opts.privateHost,
  });
  const comparative = line.kind === 'local'
    ? []
    : comparativeCosts(opts.tokensIn, opts.tokensOut, opts.feed.table);
  const provenance = `prices: openrouter.ai @ ${opts.feed.fetchedAt}${opts.feed.stale ? ' — stale' : ''}`;
  return {
    kind: line.kind,
    label: line.label,
    usdTotal: line.usdTotal,
    usdIn: line.usdIn,
    usdOut: line.usdOut,
    matchedId: line.matchedId,
    modelId: opts.modelId,
    tokensIn: opts.tokensIn,
    tokensOut: opts.tokensOut,
    comparative,
    provenance,
    fetchedAt: opts.feed.fetchedAt,
    stale: opts.feed.stale,
  };
}
