import { resolveModelsJsonPath } from "../../../config/paths.js";
import { CredentialResolver, init_credentials } from "../../../auth/credentials.js";
import { init_resolve_config_value, testApiKeyResolution } from "../../../config/resolve-config-value.js";
import { init_models_json, loadModelsJson, saveModelsJson, validateModelsConfig } from "../../../config/models-json.js";
import { getModelRegistry } from "../../../providers/model-registry.js";
import { getProviderRegistry, init_plugin_registry } from "../../../providers/plugin-registry.js";
import { PROVIDER_META, getAllModels, getAllProviders, getAvailableModels, getProviderActiveKeySource, init_providers, isProviderConfigured } from "../../../providers/index.js";
import { getImageGenerationProvider } from "../../../agent/image/generation/provider-registry.js";
import { listImageGenerationProvidersSummary } from "../../../agent/image/generation/runtime.js";
import { respondStartupUnavailable } from "../lib/startup-unavailable.js";
//#region src/gateway/hono/routes/models.ts
init_models_json();
init_resolve_config_value();
init_providers();
init_credentials();
init_plugin_registry();
function readModelsJsonProviderApiKey(providerId) {
	const { config } = loadModelsJson(resolveModelsJsonPath());
	const key = (config.providers?.[providerId.trim()])?.apiKey;
	return typeof key === "string" && key.trim() ? key.trim() : void 0;
}
/** Plaintext key only when persisted under `cfg.providers.<id>.apiKey` (not env / credential store). */
function readProviderApiKeyFromConfigFileOnly(cfg, providerId) {
	const id = providerId.trim().toLowerCase();
	const bucket = cfg.providers?.[id];
	if (!bucket || typeof bucket !== "object" || Array.isArray(bucket)) return void 0;
	const k = bucket.apiKey;
	return typeof k === "string" && k.trim() ? k.trim() : void 0;
}
/** Extension id from manifest `providers[]` (e.g. provider `demo` → extension `demo-provider`). */
function resolveExtensionIdForProvider(service, providerId) {
	const loader = service.getExtensionLoader();
	if (!loader) return void 0;
	return loader.buildManifestRegistry().findByProvider(providerId)?.id;
}
/** Effective LLM REST base URL for a provider (models.json overrides included). */
function resolveProviderApiBaseUrl(providerId) {
	const model = getModelRegistry().getAll().find((m) => m.provider === providerId);
	if (!model?.baseUrl || model.baseUrl === "extension://provider-plugin") return void 0;
	return model.baseUrl;
}
function mapPluginModel(providerId, model, available) {
	return {
		id: `${providerId}/${model.id}`,
		name: model.name,
		provider: providerId,
		contextWindow: model.contextWindow ?? 128e3,
		maxTokens: model.maxOutputTokens ?? 4096,
		reasoning: false,
		vision: model.supportsImages ?? false,
		cost: {
			input: model.pricing?.input ?? 0,
			output: model.pricing?.output ?? 0
		},
		available,
		source: "extension"
	};
}
function registerModelsRoutes(authenticated, deps) {
	const { service, strictRateLimitMiddleware } = deps;
	authenticated.get("/api/models-json", async (c) => {
		const path = resolveModelsJsonPath();
		const { config, error } = loadModelsJson(path);
		const registry = getModelRegistry();
		return c.json({
			ok: true,
			payload: {
				config,
				path,
				exists: error === void 0,
				loadError: error || registry.getError()
			}
		});
	});
	authenticated.post("/api/models-json/validate", async (c) => {
		const { config } = await c.req.json();
		const result = validateModelsConfig(config);
		return c.json({
			ok: true,
			payload: result
		});
	});
	authenticated.patch("/api/models-json", async (c) => {
		const { config } = await c.req.json();
		const result = saveModelsJson(resolveModelsJsonPath(), config);
		if (!result.success) return c.json({
			ok: false,
			error: result.error
		}, 400);
		const registry = getModelRegistry();
		registry.refresh();
		service.emit("models-json.updated", { modelCount: registry.getAll().length });
		return c.json({
			ok: true,
			payload: {
				saved: true,
				modelCount: registry.getAll().length
			}
		});
	});
	authenticated.post("/api/models-json/reload", async (c) => {
		const registry = getModelRegistry();
		registry.refresh();
		const error = registry.getError();
		const models = registry.getAll();
		service.emit("models-json.reloaded", {
			modelCount: models.length,
			error: error || void 0
		});
		return c.json({
			ok: true,
			payload: {
				modelCount: models.length,
				error
			}
		});
	});
	authenticated.post("/api/models-json/test-api-key", async (c) => {
		const { value } = await c.req.json();
		const result = testApiKeyResolution(value);
		return c.json({
			ok: true,
			payload: result
		});
	});
	authenticated.get("/api/models", async (c) => {
		if (!service.isGatewayReady()) return respondStartupUnavailable(c, "models.list");
		const pluginRegistry = getProviderRegistry();
		const models = (await getAvailableModels()).map((m) => ({
			id: `${m.provider}/${m.id}`,
			name: m.name,
			provider: m.provider,
			contextWindow: m.contextWindow ?? 128e3,
			maxTokens: m.maxTokens ?? 4096,
			reasoning: m.reasoning ?? false,
			vision: m.input?.includes("image") ?? false,
			cost: {
				input: m.cost?.input ?? 0,
				output: m.cost?.output ?? 0
			},
			...pluginRegistry.has(m.provider) ? { source: "extension" } : {}
		}));
		const existingIds = new Set(models.map((m) => m.id));
		for (const plugin of pluginRegistry.listAll()) for (const model of plugin.models) {
			const compositeId = `${plugin.id}/${model.id}`;
			if (!existingIds.has(compositeId)) {
				models.push(mapPluginModel(plugin.id, model, true));
				existingIds.add(compositeId);
			}
		}
		models.sort((a, b) => {
			if (a.provider !== b.provider) return a.provider.localeCompare(b.provider);
			return a.name.localeCompare(b.name);
		});
		return c.json({
			ok: true,
			payload: { models }
		});
	});
	authenticated.get("/api/image/providers", (c) => {
		const cfg = deps.service.currentConfig;
		const providers = listImageGenerationProvidersSummary(cfg).map((p) => {
			const provider = getImageGenerationProvider(p.id, cfg);
			let configured = false;
			try {
				configured = provider?.isConfigured?.({ cfg }) === true;
			} catch {
				configured = false;
			}
			return {
				...p,
				configured
			};
		});
		return c.json({
			ok: true,
			payload: { providers }
		});
	});
	authenticated.post("/api/image/providers/:id/test", (c) => {
		const id = c.req.param("id");
		const cfg = deps.service.currentConfig;
		const provider = getImageGenerationProvider(id, cfg);
		if (!provider) return c.json({
			ok: false,
			error: { message: `Image generation provider not found: ${id}` }
		}, 404);
		let configured = false;
		let reason;
		try {
			configured = provider.isConfigured?.({ cfg }) === true;
			if (!configured) reason = "Missing API key (set via config or environment).";
		} catch (err) {
			reason = err instanceof Error ? err.message : String(err);
		}
		return c.json({
			ok: true,
			payload: {
				id: provider.id,
				configured,
				...reason ? { reason } : {},
				defaultModel: provider.defaultModel ?? null
			}
		});
	});
	/**
	* POST /api/image/providers/:id/reveal-api-key — return `cfg.providers.<id>.apiKey` plaintext for the
	* gateway console (same auth as PATCH /api/config). Does not resolve env vars or credential files.
	*/
	authenticated.post("/api/image/providers/:id/reveal-api-key", strictRateLimitMiddleware, async (c) => {
		const rawId = c.req.param("id");
		const cfg = deps.service.currentConfig;
		const provider = getImageGenerationProvider(rawId, cfg);
		if (!provider) return c.json({
			ok: false,
			error: { message: `Image generation provider not found: ${rawId}` }
		}, 404);
		const apiKey = readProviderApiKeyFromConfigFileOnly(cfg, provider.id);
		return c.json({
			ok: true,
			payload: {
				id: provider.id,
				apiKey: apiKey ?? null,
				source: apiKey ? "config" : "none"
			}
		});
	});
	authenticated.get("/api/providers", async (c) => {
		const pluginRegistry = getProviderRegistry();
		const allModels = getAllModels();
		const availableModels = await getAvailableModels();
		const configured = new Set(availableModels.map((m) => `${m.provider}/${m.id}`));
		const models = allModels.map((m) => ({
			id: `${m.provider}/${m.id}`,
			name: m.name,
			provider: m.provider,
			contextWindow: m.contextWindow ?? 128e3,
			maxTokens: m.maxTokens ?? 4096,
			reasoning: m.reasoning ?? false,
			vision: m.input?.includes("image") ?? false,
			cost: {
				input: m.cost?.input ?? 0,
				output: m.cost?.output ?? 0
			},
			available: configured.has(`${m.provider}/${m.id}`),
			...pluginRegistry.has(m.provider) ? { source: "extension" } : {}
		}));
		const existingIds = new Set(models.map((m) => m.id));
		for (const plugin of pluginRegistry.listAll()) for (const model of plugin.models) {
			const compositeId = `${plugin.id}/${model.id}`;
			if (!existingIds.has(compositeId)) {
				models.push(mapPluginModel(plugin.id, model, configured.has(compositeId)));
				existingIds.add(compositeId);
			}
		}
		models.sort((a, b) => {
			if (a.provider !== b.provider) return a.provider.localeCompare(b.provider);
			return a.name.localeCompare(b.name);
		});
		return c.json({
			ok: true,
			payload: { models }
		});
	});
	authenticated.get("/api/providers/meta", async (c) => {
		const providers = getAllProviders();
		const pluginRegistry = getProviderRegistry();
		const meta = await Promise.all(providers.map(async (provider) => {
			const plugin = pluginRegistry.get(provider);
			const extensionId = plugin ? resolveExtensionIdForProvider(service, provider) : void 0;
			return {
				id: provider,
				name: plugin?.name ?? PROVIDER_META[provider]?.name ?? provider,
				category: plugin ? "extension" : PROVIDER_META[provider]?.category || "specialty",
				supportsOAuth: plugin ? false : PROVIDER_META[provider]?.supportsOAuth ?? false,
				supportsApiKey: plugin ? false : PROVIDER_META[provider]?.supportsApiKey ?? true,
				configured: await isProviderConfigured(provider),
				activeKeySource: await getProviderActiveKeySource(provider),
				baseUrl: resolveProviderApiBaseUrl(provider),
				...extensionId ? { extensionId } : {}
			};
		}));
		const knownProviderIds = new Set(providers);
		for (const plugin of pluginRegistry.listAll()) if (!knownProviderIds.has(plugin.id)) {
			const extensionId = resolveExtensionIdForProvider(service, plugin.id);
			meta.push({
				id: plugin.id,
				name: plugin.name,
				category: "extension",
				supportsOAuth: false,
				supportsApiKey: false,
				configured: true,
				activeKeySource: "extension",
				baseUrl: resolveProviderApiBaseUrl(plugin.id),
				...extensionId ? { extensionId } : {}
			});
		}
		return c.json({
			ok: true,
			payload: { providers: meta }
		});
	});
	/**
	* POST /api/providers/:providerId/reveal-api-key — plaintext key when stored in the
	* gateway credential store or models.json (not env vars or OAuth tokens).
	*/
	authenticated.post("/api/providers/:providerId/reveal-api-key", strictRateLimitMiddleware, async (c) => {
		const rawId = c.req.param("providerId")?.trim();
		if (!rawId) return c.json({
			ok: false,
			error: { message: "Missing providerId" }
		}, 400);
		const providerId = rawId.toLowerCase();
		const stored = await new CredentialResolver().revealGatewayStoredApiKey(providerId);
		if (stored) return c.json({
			ok: true,
			payload: {
				id: providerId,
				apiKey: stored,
				source: "credential"
			}
		});
		const fromModelsJson = readModelsJsonProviderApiKey(providerId);
		if (fromModelsJson) return c.json({
			ok: true,
			payload: {
				id: providerId,
				apiKey: fromModelsJson,
				source: "models_json"
			}
		});
		return c.json({
			ok: true,
			payload: {
				id: providerId,
				apiKey: null,
				source: "none"
			}
		});
	});
	authenticated.delete("/api/providers/:providerId/key", strictRateLimitMiddleware, async (c) => {
		const providerId = c.req.param("providerId");
		if (!providerId) return c.json({
			ok: false,
			error: { message: "Missing providerId" }
		}, 400);
		const normalizedProvider = providerId.toLowerCase();
		const profileId = `${normalizedProvider}:default`;
		const resolver = new CredentialResolver();
		try {
			await resolver.deleteProfile(profileId);
			return c.json({
				ok: true,
				payload: { deleted: normalizedProvider }
			});
		} catch (error) {
			const errorMessage = error instanceof Error ? error.message : String(error);
			return c.json({
				ok: false,
				error: { message: `Failed to delete key: ${errorMessage}` }
			}, 500);
		}
	});
}
//#endregion
export { registerModelsRoutes };

//# sourceMappingURL=models.js.map