/**
 * provider-catalog-config.js — per-provider runtime configuration.
 *
 * Single source of truth for provider-level settings that go beyond key
 * management: API format, base URL, model-discovery endpoint, and rate-limit
 * semantics. Consumers: model-catalog-cache.js, doctor-providers.js (test
 * endpoints), and the backoff/retry layer.
 *
 * Adding a provider:
 *   1. Add an entry here.
 *   2. If it needs a key, add it to PROVIDER_REGISTRY in key-manager.js.
 *   3. Run `npm run copy-resources` to rebuild dist.
 */

/**
 * API format families.
 * - "openai"     — OpenAI REST: Bearer auth, POST /v1/chat/completions, GET /v1/models returns { data: [{id}] }
 * - "anthropic"  — Anthropic REST: x-api-key header, POST /v1/messages, no public GET /v1/models
 * - "google"     — Gemini REST: x-goog-api-key header, GET /v1beta/models returns { models: [{name}] }
 * - "custom"     — Non-standard; model discovery not supported
 */

/**
 * Rate-limit scope.
 * - "provider"  — a single 429 takes down the whole provider (back off all models)
 * - "model"     — 429 is per-model; other models on the same provider remain usable
 */

export const PROVIDER_CATALOG_CONFIG = {
	// ─── Anthropic ────────────────────────────────────────────────────────────
	anthropic: {
		type: "anthropic",
		baseUrl: "https://api.anthropic.com",
		modelsPath: null,
		auth: { type: "x-api-key", header: "x-api-key" },
		rateLimits: { scope: "model" },
	},

	// ─── OpenAI family ───────────────────────────────────────────────────────
	openai: {
		type: "openai",
		baseUrl: "https://api.openai.com",
		modelsPath: "/v1/models",
		auth: { type: "bearer" },
		rateLimits: { scope: "model" },
		modelFilter: {
			// exclude embedding, moderation, image, audio, realtime, and legacy models
			excludePatterns: [
				/embed/i,
				/moderation/i,
				/dall-e/i,
				/tts/i,
				/whisper/i,
				/realtime/i,
				/instruct/i,
				/babbage/i,
				/davinci/i,
				/ada/i,
				/curie/i,
			],
		},
	},

	groq: {
		type: "openai",
		baseUrl: "https://api.groq.com",
		modelsPath: "/openai/v1/models",
		auth: { type: "bearer" },
		rateLimits: { scope: "model" },
		modelFilter: {
			excludePatterns: [/whisper/i, /guard/i, /tool-use/i, /vision-preview/i],
		},
	},

	mistral: {
		type: "openai",
		baseUrl: "https://api.mistral.ai",
		modelsPath: "/v1/models",
		auth: { type: "bearer" },
		rateLimits: { scope: "provider" },
		modelFilter: {
			excludePatterns: [
				/embed/i,
				/moderation/i,
				/ocr/i,
				/voxtral/i,
				/transcribe/i,
				/tts/i,
				/realtime/i,
				/^ft:/,
			],
		},
	},

	openrouter: {
		type: "openai",
		baseUrl: "https://openrouter.ai",
		modelsPath: "/api/v1/models",
		auth: { type: "bearer" },
		// OpenRouter aggregates many providers — 429 varies by upstream but
		// the router itself rate-limits per-account, not per-model.
		rateLimits: { scope: "provider" },
		modelFilter: {
			// Only free-tier models pass the built-in policy (isModelAllowedByBuiltInProviderPolicy)
			// so no additional filter needed here; handled in preferences-models.js.
			excludePatterns: [],
		},
	},

	cerebras: {
		type: "openai",
		baseUrl: "https://api.cerebras.ai",
		modelsPath: "/v1/models",
		auth: { type: "bearer" },
		rateLimits: { scope: "provider" },
		modelFilter: {
			excludePatterns: [],
		},
	},

	// ─── Google ──────────────────────────────────────────────────────────────
	google: {
		type: "google",
		baseUrl: "https://generativelanguage.googleapis.com",
		// Returns { models: [{name: "models/gemini-..."}] } — non-standard format.
		modelsPath: "/v1beta/models",
		auth: { type: "query-param", param: "key" },
		rateLimits: { scope: "model" },
		modelFilter: {
			// Gemini model list includes embedding and vision-only models.
			excludePatterns: [/embed/i, /aqa/i],
		},
	},

	// ─── Azure OpenAI ─────────────────────────────────────────────────────────
	// Base URL is deployment-specific; model discovery via /openai/deployments.
	"azure-openai": {
		type: "openai",
		baseUrl: null,
		modelsPath: null,
		auth: { type: "bearer" },
		rateLimits: { scope: "model" },
	},

	// ─── MiniMax ─────────────────────────────────────────────────────────────
	// International endpoint (api.minimax.io) — Chinese-network endpoint
	// (api.minimaxi.com/anthropic) is handled separately in the SDK layer.
	minimax: {
		type: "openai",
		baseUrl: "https://api.minimax.io",
		modelsPath: "/v1/models",
		auth: { type: "bearer" },
		rateLimits: { scope: "provider" },
		modelFilter: {
			excludePatterns: [],
		},
	},

	// ─── OpenCode Zen ─────────────────────────────────────────────────────────
	// Free-tier routing layer — all models are zero-cost. IDs may use "-free"
	// suffix or unconventional names (e.g. "big-pickle"); no additional filter.
	opencode: {
		type: "openai",
		baseUrl: "https://opencode.ai/zen",
		modelsPath: "/v1/models",
		auth: { type: "bearer" },
		rateLimits: { scope: "provider" },
		modelFilter: {
			// All opencode entries are intended to be free-tier; the wire IDs
			// typically end in "-free" but also include experimental zero-cost
			// models (e.g. big-pickle). No additional filtering needed.
			excludePatterns: [],
		},
	},

	// ─── OpenCode Go ─────────────────────────────────────────────────────────
	// Paid/commercial tier at /zen/go — exposes upstream model IDs directly
	// (minimax-m2.7, kimi-k2.6, deepseek-v4-pro, etc.) without a "-free" suffix.
	"opencode-go": {
		type: "openai",
		baseUrl: "https://opencode.ai/zen/go",
		modelsPath: "/v1/models",
		auth: { type: "bearer" },
		rateLimits: { scope: "provider" },
		modelFilter: { excludePatterns: [] },
	},

	// ─── Kimi Coding ──────────────────────────────────────────────────────────────
	// Moonshot AI coding endpoint. Returns { data: [{id}] } (OpenAI compatible).
	// A KimiCLI/* User-Agent is documented as required but the /v1/models endpoint
	// works with plain Bearer auth at discovery time (tested live).
	// Key: KIMI_API_KEY  Dashboard: platform.moonshot.ai
	"kimi-coding": {
		type: "openai",
		baseUrl: "https://api.kimi.com/coding",
		modelsPath: "/v1/models",
		auth: { type: "bearer" },
		rateLimits: { scope: "provider" },
		modelFilter: { excludePatterns: [] },
	},

	// ─── Z.AI (ZAI) ───────────────────────────────────────────────────────────────────
	// Zhipu AI coding plan endpoint. Returns { data: [{id}] } (OpenAI compat).
	// Per-model quirk: GLM reasoning models use thinkingFormat: zai — that is
	// handled in the openai-completions adapter, not at catalog level.
	// Key: ZAI_API_KEY  Dashboard: bigmodel.cn
	zai: {
		type: "openai",
		baseUrl: "https://api.z.ai/api/coding/paas",
		modelsPath: "/v4/models",
		auth: { type: "bearer" },
		rateLimits: { scope: "provider" },
		modelFilter: { excludePatterns: [] },
	},

	// ─── Ollama Cloud ───────────────────────────────────────────────────────────
	// ollama.com hosted inference. Returns { data: [{id}] } (OpenAI compat).
	// The local Ollama extension uses /api/tags via OLLAMA_HOST; this catalog
	// entry covers the cloud API only (ollama.com/v1/models, confirmed live).
	// Key: OLLAMA_CLOUD_API_KEY (fallback: OLLAMA_API_KEY)
	"ollama-cloud": {
		type: "openai",
		baseUrl: "https://ollama.com",
		modelsPath: "/v1/models",
		auth: { type: "bearer" },
		rateLimits: { scope: "provider" },
		modelFilter: { excludePatterns: [] },
	},

	// ─── Xiaomi MiMo ────────────────────────────────────────────────────────────
	// Discovery uses OpenAI-shaped GET /v1/models. Auth is x-api-key header
	// (NOT Bearer) — verified empirically: Bearer → 401, x-api-key → 200.
	// Inference uses the Anthropic-messages wire format at /anthropic.
	// Key: XIAOMI_API_KEY  Dashboard: token-plan-ams.xiaomimimo.com
	xiaomi: {
		type: "openai",
		baseUrl: "https://token-plan-ams.xiaomimimo.com",
		modelsPath: "/v1/models",
		auth: { type: "x-api-key", header: "x-api-key" },
		rateLimits: { scope: "provider" },
		modelFilter: { excludePatterns: [] },
	},
};

/**
 * Provider IDs that support live model-list discovery (have a modelsPath).
 */
export const DISCOVERABLE_PROVIDER_IDS = Object.entries(PROVIDER_CATALOG_CONFIG)
	.filter(([, cfg]) => cfg.modelsPath !== null)
	.map(([id]) => id);

/**
 * Returns the catalog config for a provider, or null if not configured.
 */
export function getProviderCatalogConfig(providerId) {
	return PROVIDER_CATALOG_CONFIG[providerId] ?? null;
}

/**
 * Returns true if a 429 from this provider should back off all models on the
 * provider rather than just the one that triggered the response.
 */
export function isProviderScopedRateLimit(providerId) {
	return PROVIDER_CATALOG_CONFIG[providerId]?.rateLimits?.scope === "provider";
}

/**
 * Returns the exclude patterns for a provider's model list, or [].
 */
export function getProviderModelExcludePatterns(providerId) {
	return (
		PROVIDER_CATALOG_CONFIG[providerId]?.modelFilter?.excludePatterns ?? []
	);
}
