import { FlyNotConfiguredError, deleteSecret, getCurrentProvider, isFlyControlAvailable, listMachines, listSecrets, scheduleRestart, setProvider, setSecrets } from "../services/fly-control-service.mjs";
//#region extensions/crypto/src/commands/fly-commands.ts
/**
* Fly control commands — manage the Fly.io deployment from Telegram.
*
* /provider             — Show current LLM provider + switch options
* /provider anthropic   — Switch to Anthropic (direct)
* /provider bankr       — Switch to Bankr LLM Gateway
* /provider openrouter  — Switch to OpenRouter
*
* /flykeys              — List configured secrets (names only, never values)
* /flykeys set KEY val  — Set a secret
* /flykeys rm KEY       — Remove a secret
*
* /flystatus            — Machine status, region, uptime
*
* /flyrestart           — Restart the machine (picks up new secrets)
*
* SECURITY:
* - All commands require auth (requireAuth: true)
* - Requires FLY_API_TOKEN set as a Fly secret
* - Secret values are write-only (Fly never returns plaintext)
* - The bot restarts after provider/secret changes (entrypoint.sh re-reads config)
*/
const SETUP_TEXT = [
	"**Fly Control not configured**",
	"",
	"To manage your deploy from Telegram, set a Fly API token:",
	"",
	"```",
	"fly tokens create deploy -a openclawnch-tg",
	"# Copy the token, then:",
	"fly secrets set FLY_API_TOKEN=\"FlyV1 ...\" -a openclawnch-tg",
	"```",
	"",
	"After that, /provider, /flykeys, /flystatus, and /flyrestart will work."
].join("\n");
function notConfigured() {
	return { text: SETUP_TEXT };
}
function formatError(err) {
	if (err instanceof FlyNotConfiguredError) return SETUP_TEXT;
	return err instanceof Error ? err.message : String(err);
}
const PROVIDER_LABELS = {
	anthropic: "Anthropic (direct)",
	bankr: "Bankr LLM Gateway (pay with crypto)",
	openrouter: "OpenRouter",
	openai: "OpenAI (direct)"
};
const PROVIDER_KEYS = {
	anthropic: "ANTHROPIC_API_KEY",
	bankr: "BANKR_LLM_KEY",
	openrouter: "OPENROUTER_API_KEY",
	openai: "OPENAI_API_KEY"
};
const providerCommand = {
	name: "provider",
	description: "View current LLM provider and switch options",
	acceptsArgs: false,
	requireAuth: true,
	handler: async (_ctx) => {
		const current = getCurrentProvider();
		const currentLabel = PROVIDER_LABELS[current] ?? current;
		if (!isFlyControlAvailable()) return { text: [
			`**LLM Provider:** ${currentLabel}`,
			"",
			"**Switch provider:**",
			"  /provider_anthropic — Claude direct",
			"  /provider_bankr — Bankr Gateway (pay with crypto)",
			"  /provider_openrouter — OpenRouter",
			"  /provider_openai — OpenAI direct",
			"",
			"Switching requires Fly control. Set FLY_API_TOKEN first.",
			"",
			"Current model: /llm"
		].join("\n") };
		return { text: [
			`**LLM Provider:** ${currentLabel}`,
			"",
			"**Switch provider:**",
			"  /provider_anthropic — Claude direct",
			"  /provider_bankr — Bankr Gateway (pay with crypto)",
			"  /provider_openrouter — OpenRouter (multi-model)",
			"  /provider_openai — OpenAI direct",
			"",
			"Switching restarts the bot (~40s). Model resets to default for the new provider.",
			"",
			"Current model: /llm"
		].join("\n") };
	}
};
/** Shared handler for /provider_<name> commands. */
async function handleProviderSwitch(providerArg) {
	if (!isFlyControlAvailable()) return notConfigured();
	const current = getCurrentProvider();
	const currentLabel = PROVIDER_LABELS[current] ?? current;
	if (providerArg === current) return { text: `Already using ${currentLabel}. No change needed.` };
	const requiredKey = PROVIDER_KEYS[providerArg];
	if (requiredKey && !process.env[requiredKey]) {
		let keyExistsInFly = false;
		try {
			keyExistsInFly = (await listSecrets()).some((s) => s.name === requiredKey);
		} catch {}
		if (!keyExistsInFly) return { text: [
			`**Missing API key for ${PROVIDER_LABELS[providerArg] ?? providerArg}**`,
			"",
			`Set \`${requiredKey}\` first, then try again.`,
			`(Use /flykeys to manage API keys)`
		].join("\n") };
	}
	try {
		const targetLabel = PROVIDER_LABELS[providerArg] ?? providerArg;
		scheduleRestart(2e3, await setProvider(providerArg));
		return { text: `Switching to **${targetLabel}**. Restarting agent, please wait...\n\nThe bot will be back in ~40 seconds.` };
	} catch (err) {
		return { text: `Failed to switch provider: ${formatError(err)}` };
	}
}
const providerAnthropicCommand = {
	name: "provider_anthropic",
	description: "Switch LLM to Anthropic (direct)",
	acceptsArgs: false,
	requireAuth: true,
	handler: async () => handleProviderSwitch("anthropic")
};
const providerBankrCommand = {
	name: "provider_bankr",
	description: "Switch LLM to Bankr Gateway (pay with crypto)",
	acceptsArgs: false,
	requireAuth: true,
	handler: async () => handleProviderSwitch("bankr")
};
const providerOpenrouterCommand = {
	name: "provider_openrouter",
	description: "Switch LLM to OpenRouter",
	acceptsArgs: false,
	requireAuth: true,
	handler: async () => handleProviderSwitch("openrouter")
};
const providerOpenaiCommand = {
	name: "provider_openai",
	description: "Switch LLM to OpenAI (direct)",
	acceptsArgs: false,
	requireAuth: true,
	handler: async () => handleProviderSwitch("openai")
};
const PROTECTED_SECRETS = new Set(["FLY_API_TOKEN", "TELEGRAM_BOT_TOKEN"]);
const KNOWN_SECRETS = {
	ANTHROPIC_API_KEY: "Anthropic direct key",
	BANKR_LLM_KEY: "Bankr LLM Gateway key",
	BANKR_API_KEY: "Bankr Agent API key",
	OPENROUTER_API_KEY: "OpenRouter key",
	OPENAI_API_KEY: "OpenAI direct key",
	OPENCLAWNCH_LLM_PROVIDER: "LLM provider (anthropic/bankr/openrouter)",
	WALLETCONNECT_PROJECT_ID: "WalletConnect project ID",
	CLAWNCHER_PRIVATE_KEY: "Private key (autosign)",
	CLAWNCHER_RPC_URL: "Custom RPC URL",
	ALLOW_PRIVATE_KEY_MODE: "Enable private key mode (true/false)",
	BASESCAN_API_KEY: "Basescan API key",
	ETHERSCAN_API_KEY: "Etherscan API key",
	ALCHEMY_API_KEY: "Alchemy API key",
	COINGECKO_API_KEY: "CoinGecko API key",
	HERD_ACCESS_TOKEN: "Herd Intelligence token",
	HUMMINGBOT_API_URL: "Hummingbot API URL",
	MOLTEN_API_KEY: "Molten API key",
	LIFI_API_KEY: "LI.FI bridge API key",
	X_API_KEY: "X/Twitter API key",
	X_API_SECRET: "X/Twitter API secret",
	X_ACCESS_TOKEN: "X/Twitter access token",
	X_ACCESS_TOKEN_SECRET: "X/Twitter access token secret",
	X_BEARER_TOKEN: "X/Twitter bearer token (optional)"
};
const flykeysCommand = {
	name: "flykeys",
	description: "List, set, or remove Fly secrets (e.g. /flykeys set KEY value)",
	acceptsArgs: true,
	requireAuth: true,
	handler: async (ctx) => {
		if (!isFlyControlAvailable()) return notConfigured();
		const parts = (ctx?.args ?? ctx?.text ?? "").trim().replace(/^\/flykeys\s*/, "").trim().split(/\s+/);
		const action = parts[0]?.toLowerCase() ?? "";
		if (!action) try {
			const secrets = await listSecrets();
			if (secrets.length === 0) return { text: "No secrets configured." };
			const lines = ["**Configured Secrets:**", ""];
			for (const s of secrets) {
				const label = KNOWN_SECRETS[s.name];
				const protected_ = PROTECTED_SECRETS.has(s.name) ? " (protected)" : "";
				lines.push(`  \`${s.name}\`${label ? ` — ${label}` : ""}${protected_}`);
			}
			lines.push("", "**Set a secret:**", "  `/flykeys set KEY value`", "", "**Remove a secret:**", "  `/flykeys rm KEY`", "", "Changes take effect after /flyrestart");
			return { text: lines.join("\n") };
		} catch (err) {
			return { text: `Failed to list secrets: ${formatError(err)}` };
		}
		if (action === "set") {
			const key = parts[1]?.toUpperCase();
			const value = parts.slice(2).join(" ");
			if (!key || !value) return { text: [
				"**Usage:** `/flykeys set KEY value`",
				"",
				"**Examples:**",
				"  `/flykeys set BANKR_LLM_KEY bk_abc123`",
				"  `/flykeys set ANTHROPIC_API_KEY sk-ant-abc123`",
				"  `/flykeys set OPENCLAWNCH_LLM_PROVIDER bankr`"
			].join("\n") };
			if (PROTECTED_SECRETS.has(key)) return { text: `\`${key}\` is protected and cannot be modified from Telegram. Use the Fly CLI.` };
			if (!KNOWN_SECRETS[key]) return { text: `\`${key}\` is not a recognized secret. Only these keys can be set:\n\n${Object.entries(KNOWN_SECRETS).map(([k, v]) => `  \`${k}\` — ${v}`).join("\n")}` };
			try {
				await setSecrets({ [key]: value });
				return { text: `Secret \`${key}\` set successfully.${key !== "OPENCLAWNCH_LLM_PROVIDER" ? "\n\nRun /flyrestart to pick up the new value." : "\n\nUse /provider to switch (it auto-restarts)."}\n\n**Security:** Delete your message above — it contains the secret value in plaintext.` };
			} catch (err) {
				return { text: `Failed to set secret: ${formatError(err)}` };
			}
		}
		if (action === "rm" || action === "remove" || action === "delete") {
			const key = parts[1]?.toUpperCase();
			if (!key) return { text: "**Usage:** `/flykeys rm KEY`" };
			if (PROTECTED_SECRETS.has(key)) return { text: `\`${key}\` is protected and cannot be removed from Telegram. Use the Fly CLI.` };
			try {
				await deleteSecret(key);
				return { text: `Secret \`${key}\` removed.\n\nRun /flyrestart to pick up the change.` };
			} catch (err) {
				return { text: `Failed to remove secret: ${formatError(err)}` };
			}
		}
		return { text: [
			"**Unknown action:** " + action,
			"",
			"**Usage:**",
			"  /flykeys — list all secrets",
			"  `/flykeys set KEY value` — set a secret",
			"  `/flykeys rm KEY` — remove a secret"
		].join("\n") };
	}
};
const flystatusCommand = {
	name: "flystatus",
	description: "Show machine status, region, and uptime",
	acceptsArgs: false,
	requireAuth: true,
	handler: async (_ctx) => {
		if (!isFlyControlAvailable()) return notConfigured();
		try {
			const machines = await listMachines();
			if (machines.length === 0) return { text: "No machines found for this app." };
			const lines = [
				`**OpenClawnch Deploy Status**`,
				`App: \`${process.env.FLY_APP_NAME}\``,
				""
			];
			for (const m of machines) {
				const uptime = m.updatedAt ? timeSince(m.updatedAt) : "unknown";
				const stateEmoji = m.state === "started" ? "running" : m.state;
				lines.push(`**Machine:** \`${m.id}\``, `  State: ${stateEmoji}`, `  Region: ${m.region}`, `  CPU: ${m.cpuKind} ${m.cpus}x / ${m.memoryMb}MB RAM`, `  Last update: ${uptime} ago`, "");
			}
			lines.push("**Quick actions:**", "  /flyrestart — restart the bot", "  /provider — switch LLM provider", "  /flykeys — manage API keys");
			return { text: lines.join("\n") };
		} catch (err) {
			return { text: `Failed to get status: ${formatError(err)}` };
		}
	}
};
const flyrestartCommand = {
	name: "flyrestart",
	description: "Restart the bot (picks up new secrets)",
	acceptsArgs: false,
	requireAuth: true,
	handler: async (_ctx) => {
		if (!isFlyControlAvailable()) return notConfigured();
		scheduleRestart(2e3);
		return { text: "Restarting agent, please wait...\n\nThe bot will be back in ~40 seconds." };
	}
};
function timeSince(dateStr) {
	try {
		const diff = Date.now() - new Date(dateStr).getTime();
		if (diff < 0) return "just now";
		const seconds = Math.floor(diff / 1e3);
		if (seconds < 60) return `${seconds}s`;
		const minutes = Math.floor(seconds / 60);
		if (minutes < 60) return `${minutes}m`;
		const hours = Math.floor(minutes / 60);
		if (hours < 24) return `${hours}h ${minutes % 60}m`;
		return `${Math.floor(hours / 24)}d ${hours % 24}h`;
	} catch {
		return "unknown";
	}
}
//#endregion
export { flykeysCommand, flyrestartCommand, flystatusCommand, providerAnthropicCommand, providerBankrCommand, providerCommand, providerOpenaiCommand, providerOpenrouterCommand };

//# sourceMappingURL=fly-commands.mjs.map