import { apiFetchWithStartupRetry } from '@/lib/gateway-startup-retry';
import { apiUrl } from '@/lib/url';

export type ConfiguredModel = {
  id: string;
  name: string;
  provider: string;
  contextWindow?: number;
  maxTokens?: number;
  reasoning?: boolean;
  vision?: boolean;
};

async function fetchConfiguredModels(): Promise<ConfiguredModel[]> {
  const res = await apiFetchWithStartupRetry(apiUrl('/api/models'));
  if (!res.ok) throw new Error(`Models: HTTP ${res.status}`);
  const data = (await res.json()) as { payload?: { models?: ConfiguredModel[] } };
  return data.payload?.models ?? [];
}

// Module-level cache for fetchConfiguredModels to prevent duplicate requests
let _modelsCache: ConfiguredModel[] | null = null;
let _modelsCacheExpiry = 0;
let _modelsInflight: Promise<ConfiguredModel[]> | null = null;

const MODELS_CACHE_TTL_MS = 60_000; // 60 seconds

/** SWR key used by ModelSelector and other consumers. */
export const CONFIGURED_MODELS_SWR_KEY = 'gateway-configured-models';

/**
 * Invalidate the module-level models cache so the next fetch hits the server.
 * Also revalidates the SWR key so any mounted `useSWR` hook re-renders.
 */
export async function invalidateConfiguredModelsCache(): Promise<void> {
  _modelsCache = null;
  _modelsCacheExpiry = 0;
  // Lazy import to avoid circular deps; mutate is a standalone SWR util.
  const { mutate } = await import('swr');
  await mutate(CONFIGURED_MODELS_SWR_KEY);
}

/**
 * Fetch configured models with caching and request deduplication.
 * All callers share the same cache within the TTL period.
 */
export async function fetchConfiguredModelsCached(forceRefresh = false): Promise<ConfiguredModel[]> {
  const now = Date.now();
  if (!forceRefresh && _modelsCache && now < _modelsCacheExpiry) {
    return _modelsCache;
  }
  // Bypass shared in-flight dedupe so callers that pass `true` always get a fresh list (e.g. onboarding).
  if (forceRefresh) {
    const models = await fetchConfiguredModels();
    _modelsCache = models;
    _modelsCacheExpiry = Date.now() + MODELS_CACHE_TTL_MS;
    return models;
  }
  if (_modelsInflight) return _modelsInflight;

  _modelsInflight = fetchConfiguredModels()
    .then((models) => {
      _modelsCache = models;
      _modelsCacheExpiry = Date.now() + MODELS_CACHE_TTL_MS;
      return models;
    })
    .finally(() => {
      _modelsInflight = null;
    });

  return _modelsInflight;
}
