/**
 * gemini-catalog.js — SF-side cache writer for gemini-cli model discovery.
 *
 * The OAuth + Code Assist plumbing lives in the dedicated
 * @singularity-forge/google-gemini-cli-provider package (where the rest of the
 * gemini-cli-core integration is centralized). This module only handles the
 * SF-specific concerns: where on disk to cache the result, how often to
 * refresh, and the session_start lifecycle hook.
 *
 * Why a separate cache from the generic model-catalog-cache: that cache is
 * keyed off providers with REST /v1/models and API-key auth. google-gemini-cli
 * has neither — it uses OAuth via gemini-cli-core and surfaces models implicit
 * in the per-model quota table. Cache file shape stays compatible with
 * model-catalog-cache.getKnownModelIds so consumers read both transparently.
 */
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
import { join } from "node:path";
import { sfHome } from "./sf-home.js";

const GEMINI_CLI_PROVIDER_ID = "google-gemini-cli";
const CATALOG_TTL_MS = 6 * 60 * 60 * 1000;

function cacheDir() {
	return join(sfHome(), "model-catalog");
}

function cacheFilePath() {
	return join(cacheDir(), `${GEMINI_CLI_PROVIDER_ID}.json`);
}

function isCacheFresh() {
	try {
		const path = cacheFilePath();
		if (!existsSync(path)) return false;
		const entry = JSON.parse(readFileSync(path, "utf-8"));
		if (!entry?.fetchedAt || !Array.isArray(entry.modelIds)) return false;
		return Date.now() - new Date(entry.fetchedAt).getTime() <= CATALOG_TTL_MS;
	} catch {
		return false;
	}
}

function writeCacheEntry(modelIds) {
	try {
		mkdirSync(cacheDir(), { recursive: true });
		writeFileSync(
			cacheFilePath(),
			JSON.stringify({
				fetchedAt: new Date().toISOString(),
				modelIds,
			}),
			"utf-8",
		);
	} catch {
		// Best-effort — never fail the caller.
	}
}

/**
 * Discover and cache the gemini-cli model list. Returns the model IDs on
 * success, null on any failure.
 *
 * Consumer: scheduleGeminiCatalogRefresh during session_start.
 */
export async function refreshGeminiCatalog(basePath) {
	try {
		const { discoverGeminiCliModels } = await import(
			"@singularity-forge/google-gemini-cli-provider"
		);
		const modelIds = await discoverGeminiCliModels(basePath);
		if (!modelIds || modelIds.length === 0) return null;
		writeCacheEntry(modelIds);
		return modelIds;
	} catch {
		return null;
	}
}

/**
 * Awaitable refresh — only fetches when the cache is stale. Returns the
 * fresh model id list, the existing-stale list, or null on failure / when
 * gemini-cli isn't available.
 */
export async function runGeminiCatalogRefreshIfStale(basePath) {
	if (isCacheFresh()) return null;
	try {
		return await refreshGeminiCatalog(basePath);
	} catch {
		return null;
	}
}

/**
 * Fire-and-forget background refresh. Skipped if the on-disk cache is fresh.
 *
 * Consumer: bootstrap/register-hooks.js session_start hook.
 */
export function scheduleGeminiCatalogRefresh(basePath) {
	if (isCacheFresh()) return;
	setImmediate(() => runGeminiCatalogRefreshIfStale(basePath));
}
