import { PROVIDER_ENV_MAP, getApiKeyFromEnv } from "../../providers/env-keys.js";
import { PROVIDER_META, getAllProviders, getSortedProviders, init_providers } from "../../providers/index.js";
import { formatExamples, register } from "../registry.js";
import { getProfile, listAllProfiles, listProfilesForProvider, removeAuthProfile, upsertAuthProfile } from "../../auth/profiles/profiles.js";
import { colors } from "../utils/colors.js";
import { SETUP_EXIT } from "./setup-shared/types.js";
import { emitOutcome } from "./setup-shared/output.js";
import { isPromptCancelled, promptSecret } from "./setup-shared/prompts.js";
import "./setup-shared/index.js";
import { Command } from "commander";
//#region src/cli/commands/providers.ts
/**
* `xopc providers` — user-friendly hub for managing LLM provider credentials.
*
* This command sits on top of the existing auth-profile store (`xopc auth …`),
* but presents a setup-style surface — `list / set-key / unset-key / schema` —
* with the same `SetupOutcome` JSON contract used by other M1 setup commands.
* Agents (M2 skills) and the WebUI (M3) can consume both shapes uniformly.
*
* Capability-provider (image / voice) settings live under `cfg.providers.<id>`
* and will be wired into this command's flags in a follow-up slice.
*/
init_providers();
const KEY_OPTION_HINT = "You can either pass --key=<value>, set the env var (e.g. OPENAI_API_KEY), or omit --key to be prompted securely.";
function defaultProfileId(provider) {
	return `${provider}:default`;
}
function maskKey(value) {
	if (!value) return null;
	if (value.length <= 8) return "*".repeat(value.length);
	return `${value.slice(0, 4)}…${value.slice(-4)}`;
}
function computeKeyStatus(id, meta, profileCount) {
	if (profileCount > 0) return "configured";
	if (getApiKeyFromEnv(id)) return "env-only";
	if (meta.supportsOAuth && !meta.supportsApiKey) return "oauth";
	return "not-configured";
}
function providerEnvVar(id) {
	return PROVIDER_ENV_MAP[id]?.[0] ?? `${id.toUpperCase().replace(/-/g, "_")}_API_KEY`;
}
function listProviders() {
	return (getSortedProviders().length > 0 ? getSortedProviders() : getAllProviders()).map((id) => {
		const meta = PROVIDER_META[id] ?? {
			name: id,
			category: "specialty",
			supportsApiKey: true
		};
		const profileCount = listProfilesForProvider(id).length;
		return {
			id,
			name: meta.name,
			category: meta.category,
			supportsApiKey: Boolean(meta.supportsApiKey),
			supportsOAuth: Boolean(meta.supportsOAuth),
			status: computeKeyStatus(id, meta, profileCount),
			profileCount,
			envVar: providerEnvVar(id)
		};
	});
}
const STATUS_BADGE = {
	configured: colors.green("● configured"),
	"env-only": colors.cyan("● env-only"),
	oauth: colors.gray("● oauth"),
	"not-configured": colors.gray("○ not set")
};
function printListText(entries) {
	const grouped = /* @__PURE__ */ new Map();
	for (const e of entries) {
		const bucket = grouped.get(e.category) ?? [];
		bucket.push(e);
		grouped.set(e.category, bucket);
	}
	for (const cat of [
		"common",
		"specialty",
		"oauth",
		"enterprise",
		"extension"
	]) {
		const list = grouped.get(cat);
		if (!list?.length) continue;
		console.log("");
		console.log(colors.bold(cat.toUpperCase()));
		const idWidth = Math.max(...list.map((e) => e.id.length));
		for (const e of list) {
			const id = e.id.padEnd(idWidth);
			const note = e.profileCount > 1 ? colors.gray(` (${e.profileCount} profiles)`) : "";
			console.log(`  ${id}  ${STATUS_BADGE[e.status]}  ${colors.gray(e.name)}${note}`);
		}
	}
	console.log("");
	console.log(colors.gray("Use: xopc providers set-key <id> --key <key>"));
}
function printListJson(entries) {
	process.stdout.write(JSON.stringify({
		ok: true,
		providers: entries
	}) + "\n");
}
function finalizeProviderOutcome(outcome, options) {
	emitOutcome(outcome, options.json);
	process.exitCode = outcome.ok ? SETUP_EXIT.OK : SETUP_EXIT.ERROR;
	return outcome;
}
function planSetKey(args) {
	const existing = getProfile(args.profileId);
	return {
		existing,
		next: {
			type: "api_key",
			provider: args.provider,
			key: args.key
		},
		willChange: !existing || existing.type !== "api_key" || existing.key !== args.key || existing.provider !== args.provider
	};
}
async function runSetKey(args) {
	const meta = PROVIDER_META[args.provider];
	if (meta && meta.supportsApiKey === false) return finalizeProviderOutcome({
		ok: false,
		action: "add",
		domain: "providers",
		target: args.provider,
		changedPaths: [],
		dryRun: args.options.dryRun,
		errors: [{ message: `Provider "${args.provider}" does not support API keys; use OAuth via \`xopc auth login ${args.provider}\`.` }]
	}, args.options);
	const { existing, willChange } = planSetKey(args);
	const changedPaths = willChange ? [`profiles.${args.profileId}.key`] : [];
	const action = existing ? "set" : "add";
	if (!willChange) return finalizeProviderOutcome({
		ok: true,
		action: "noop",
		domain: "providers",
		target: args.provider,
		changedPaths: [],
		dryRun: args.options.dryRun,
		value: {
			profileId: args.profileId,
			key: maskKey(args.key)
		},
		notes: ["Key is unchanged."]
	}, args.options);
	if (!args.options.dryRun) try {
		upsertAuthProfile({
			profileId: args.profileId,
			credential: {
				type: "api_key",
				provider: args.provider,
				key: args.key
			}
		});
	} catch (error) {
		return finalizeProviderOutcome({
			ok: false,
			action,
			domain: "providers",
			target: args.provider,
			changedPaths,
			dryRun: false,
			errors: [{ message: error.message }]
		}, args.options);
	}
	return finalizeProviderOutcome({
		ok: true,
		action,
		domain: "providers",
		target: args.provider,
		changedPaths,
		dryRun: args.options.dryRun,
		value: {
			profileId: args.profileId,
			key: maskKey(args.key)
		}
	}, args.options);
}
async function runUnsetKey(args) {
	if (!getProfile(args.profileId)) return finalizeProviderOutcome({
		ok: true,
		action: "noop",
		domain: "providers",
		target: args.provider,
		changedPaths: [],
		dryRun: args.options.dryRun,
		notes: [`No profile "${args.profileId}" to remove.`]
	}, args.options);
	const changedPaths = [`profiles.${args.profileId}`];
	if (!args.options.dryRun) removeAuthProfile(args.profileId);
	return finalizeProviderOutcome({
		ok: true,
		action: "remove",
		domain: "providers",
		target: args.provider,
		changedPaths,
		dryRun: args.options.dryRun,
		value: {
			profileId: args.profileId,
			removed: true
		}
	}, args.options);
}
function emitSchema(opts) {
	const payload = {
		ok: true,
		schema: {
			target: "auth profile (~/.xopc/auth.json)",
			action: {
				type: "string",
				enum: [
					"set-key",
					"unset-key",
					"list",
					"schema"
				]
			},
			fields: {
				provider: {
					type: "string",
					description: "Provider id (e.g. openai, anthropic, deepseek). See `xopc providers list`.",
					enum: getAllProviders()
				},
				key: {
					type: "string",
					secret: true,
					description: "API key. Prefer passing via stdin/prompt over CLI arg to avoid shell history leaks."
				},
				profile: {
					type: "string",
					default: "<provider>:default",
					description: "Optional profile id when managing multiple keys per provider."
				}
			},
			outcome: {
				ok: "boolean",
				action: "add | set | remove | noop",
				domain: "providers",
				target: "<provider>",
				changedPaths: "string[]",
				dryRun: "boolean",
				value: "{ profileId, key? }"
			}
		},
		providers: opts.providerId ? listProviders().filter((p) => p.id === opts.providerId) : listProviders()
	};
	if (opts.json) process.stdout.write(JSON.stringify(payload) + "\n");
	else console.log(JSON.stringify(payload, null, 2));
}
function createProvidersCommand(_ctx) {
	const cmd = new Command("providers").description("Manage LLM provider credentials (user-friendly hub over `xopc auth`)").addHelpText("after", formatExamples([
		"xopc providers list",
		"xopc providers list --json",
		"xopc providers set-key openai --key sk-xxx",
		"xopc providers set-key deepseek            # prompts for the key (no echo)",
		"xopc providers set-key anthropic --key sk-ant-... --profile work",
		"xopc providers unset-key openai",
		"xopc providers set-key openai --key sk-xxx --dry-run --json",
		"xopc providers schema --json"
	]));
	cmd.command("list").description("List known providers and credential status").option("--json", "Output as JSON for agents/UI", false).action((opts) => {
		const entries = listProviders();
		if (opts.json) printListJson(entries);
		else printListText(entries);
	});
	cmd.command("set-key <provider>").description("Set or update the API key for a provider (writes an auth profile)").option("--key <value>", `API key value. ${KEY_OPTION_HINT}`).option("--profile <id>", "Profile id (default: <provider>:default)").option("--dry-run", "Show the change without writing", false).option("--json", "Emit a single JSON outcome line", false).action(async (provider, opts) => {
		const profileId = opts.profile?.trim() || defaultProfileId(provider);
		let key = opts.key?.trim();
		if (!key) try {
			key = await promptSecret(`API key for ${provider}:`);
		} catch (error) {
			if (isPromptCancelled(error)) {
				emitOutcome({
					ok: false,
					action: "set",
					domain: "providers",
					target: provider,
					changedPaths: [],
					dryRun: Boolean(opts.dryRun),
					errors: [{ message: "Cancelled by user" }]
				}, Boolean(opts.json));
				process.exitCode = SETUP_EXIT.CANCELLED;
				return;
			}
			throw error;
		}
		await runSetKey({
			provider,
			profileId,
			key,
			options: {
				dryRun: Boolean(opts.dryRun),
				json: Boolean(opts.json)
			}
		});
	});
	cmd.command("unset-key <provider>").description("Remove a provider auth profile").option("--profile <id>", "Profile id (default: <provider>:default)").option("--dry-run", "Show the change without writing", false).option("--json", "Emit a single JSON outcome line", false).action(async (provider, opts) => {
		await runUnsetKey({
			provider,
			profileId: opts.profile?.trim() || defaultProfileId(provider),
			options: {
				dryRun: Boolean(opts.dryRun),
				json: Boolean(opts.json)
			}
		});
	});
	cmd.command("schema [provider]").description("Print a JSON description of provider setup fields (for agents / UIs)").option("--json", "JSON output (default human-readable JSON)", false).action((providerId, opts) => {
		emitSchema({
			providerId,
			json: Boolean(opts.json)
		});
	});
	return cmd;
}
register({
	id: "providers",
	name: "providers",
	description: "Manage LLM provider credentials",
	factory: createProvidersCommand,
	metadata: {
		category: "setup",
		examples: [
			"xopc providers list",
			"xopc providers set-key openai --key sk-xxx",
			"xopc providers unset-key openai",
			"xopc providers schema --json"
		]
	}
});
//#endregion
export { listAllProfiles, listProviders, maskKey, planSetKey, runSetKey, runUnsetKey };

//# sourceMappingURL=providers.js.map