import { Ct as resolveStateDir } from "./entry.js";
import { t as ensureWalletStateDir } from "./wallet-runtime-config-TjiNNY9x.js";
import path from "node:path";
import fs from "node:fs";
import { randomBytes } from "node:crypto";

//#region src/wallet/wallet-provider-registry.ts
const REGISTRY_FILE_MODE = 384;
const PROVIDER_REGISTRY_FILENAME = "provider-registry.v1.json";
const WALLET_PROVIDER_IDS = [
	"embedded-keystore",
	"local-socket-signer",
	"alchemy",
	"turnkey",
	"privy"
];
function normalizeWalletUserRole(value) {
	switch (typeof value === "string" ? value.trim().toLowerCase() : "") {
		case "agent": return "agent";
		case "vault": return "vault";
		case "mining": return "mining";
		default: return;
	}
}
function resolveWalletUserRole(wallet) {
	if (!wallet?.metadata || typeof wallet.metadata !== "object" || Array.isArray(wallet.metadata)) return;
	return normalizeWalletUserRole(wallet.metadata.purpose) ?? normalizeWalletUserRole(wallet.metadata.role);
}
var WalletDeletionBlockedError = class extends Error {
	constructor(message, details) {
		super(message);
		this.code = "wallet_delete_blocked_mining";
		this.name = "WalletDeletionBlockedError";
		this.details = details;
	}
};
function nowIso() {
	return (/* @__PURE__ */ new Date()).toISOString();
}
function registryPath(env = process.env) {
	const walletState = ensureWalletStateDir(env);
	return path.join(walletState.rootDir, PROVIDER_REGISTRY_FILENAME);
}
function newWalletId() {
	return `w_${randomBytes(8).toString("hex")}`;
}
function normalizeProviderId(value) {
	const raw = typeof value === "string" ? value.trim() : "";
	switch (raw) {
		case "embedded-keystore":
		case "local-socket-signer":
		case "alchemy":
		case "turnkey":
		case "privy": return raw;
		default: return null;
	}
}
function normalizeSatWalletStateKey(walletId) {
	const trimmed = String(walletId ?? "").trim();
	if (!trimmed) return "unattached";
	return trimmed.replace(/[^a-zA-Z0-9._-]+/g, "_");
}
function readRecord(value) {
	return value && typeof value === "object" && !Array.isArray(value) ? value : null;
}
function readBoolean(value) {
	return value === true;
}
function readString(value) {
	return typeof value === "string" && value.trim() ? value.trim() : null;
}
function readNonNegativeBigInt(value) {
	if (typeof value === "bigint") return value > 0n ? value : 0n;
	if (typeof value === "number" && Number.isFinite(value)) return value > 0 ? BigInt(Math.trunc(value)) : 0n;
	if (typeof value === "string") {
		const trimmed = value.trim();
		if (/^\d+$/.test(trimmed)) return BigInt(trimmed);
	}
	return 0n;
}
function readNonNegativeNumber(value) {
	if (typeof value === "number" && Number.isFinite(value)) return value > 0 ? Math.trunc(value) : 0;
	if (typeof value === "string" && /^\d+$/.test(value.trim())) return Number(value);
	return 0;
}
function anySatWorkerEnabledOrRunning(value) {
	const workers = readRecord(value);
	if (!workers) return {
		enabled: false,
		running: false
	};
	let enabled = false;
	let running = false;
	for (const worker of Object.values(workers)) {
		const record = readRecord(worker);
		if (!record) continue;
		enabled ||= readBoolean(record.enabled);
		running ||= readBoolean(record.running);
	}
	return {
		enabled,
		running
	};
}
function formatLamportsAsSolExact(lamportsValue) {
	const lamports = readNonNegativeBigInt(lamportsValue);
	const whole = lamports / 1000000000n;
	const fraction = (lamports % 1000000000n).toString().padStart(9, "0").replace(/0+$/, "");
	return fraction ? `${whole}.${fraction}` : `${whole}`;
}
function buildMiningDeleteBlockedMessage(details) {
	const reasons = [];
	if (details.enabledWanted) reasons.push("mining is enabled");
	if (details.workerRunning) reasons.push("a mining worker is running");
	if (details.capitalFundedLamports !== "0") reasons.push(`miner capital remains funded (${details.capitalFundedLamports} lamports)`);
	if (details.capitalLockedLamports !== "0") reasons.push(`locked capital remains (${details.capitalLockedLamports} lamports)`);
	if (details.capitalFreeLamports !== "0") reasons.push(`withdrawable miner capital remains (${details.capitalFreeLamports} lamports / ${formatLamportsAsSolExact(details.capitalFreeLamports)} SOL)`);
	if (details.pendingCycleCount > 0) reasons.push(`${details.pendingCycleCount} pending mining cycle(s) remain`);
	if (details.claimBacklogCount > 0) reasons.push(`${details.claimBacklogCount} claim backlog item(s) remain`);
	const onlyFreeCapitalRemains = !details.enabledWanted && !details.workerRunning && details.capitalLockedLamports === "0" && details.capitalFreeLamports !== "0" && details.pendingCycleCount === 0 && details.claimBacklogCount === 0;
	return [
		"Cannot delete this wallet while SAT mining still has active state.",
		reasons.length ? `Reason: ${reasons.join("; ")}.` : void 0,
		onlyFreeCapitalRemains ? `Withdraw exactly ${formatLamportsAsSolExact(details.capitalFreeLamports)} SOL from Mining capital, then delete it.` : "Stop mining, let Clearing finish, claim pending rewards, withdraw all miner capital back to the wallet, then delete it."
	].filter(Boolean).join(" ");
}
function readSatMiningRuntimeDeletionDetails(walletId, env) {
	const runtimeStorePath = path.join(resolveStateDir(env), "sat-mining", "wallets", normalizeSatWalletStateKey(walletId), "runtime-store.json");
	if (!fs.existsSync(runtimeStorePath)) return null;
	let parsed;
	try {
		parsed = JSON.parse(fs.readFileSync(runtimeStorePath, "utf8"));
	} catch {
		return null;
	}
	const status = readRecord(parsed.lastKnownStatus);
	const workers = anySatWorkerEnabledOrRunning(parsed.workers);
	const capitalFundedLamports = readNonNegativeBigInt(status?.currentCapitalFundedLamports).toString();
	const capitalLockedLamports = readNonNegativeBigInt(status?.currentCapitalLockedLamports).toString();
	const capitalFreeLamports = readNonNegativeBigInt(status?.currentCapitalFreeLamports).toString();
	const claimBacklog = Array.isArray(parsed.claimBacklog) ? parsed.claimBacklog.length : 0;
	return {
		runtimeStorePath,
		enabledWanted: readBoolean(parsed.enabledWanted),
		workerEnabled: workers.enabled,
		workerRunning: workers.running,
		capitalFundedLamports,
		capitalLockedLamports,
		capitalFreeLamports,
		pendingCycleCount: readNonNegativeNumber(status?.currentCapitalPendingCycleCount),
		claimBacklogCount: claimBacklog,
		currentRunStartedAt: readString(parsed.currentRunStartedAt)
	};
}
function hasMiningDeletionRisk(details) {
	return details.enabledWanted || details.workerRunning || details.capitalFundedLamports !== "0" || details.capitalLockedLamports !== "0" || details.capitalFreeLamports !== "0" || details.pendingCycleCount > 0 || details.claimBacklogCount > 0;
}
function checkNamedWalletDeletionSafety(params) {
	const env = params.env ?? process.env;
	const details = readSatMiningRuntimeDeletionDetails(params.walletId.trim(), env);
	if (!details || !hasMiningDeletionRisk(details)) return {
		ok: true,
		details
	};
	return {
		ok: false,
		code: "wallet_delete_blocked_mining",
		message: buildMiningDeleteBlockedMessage(details),
		details
	};
}
function assertNamedWalletDeletionSafe(params) {
	const safety = checkNamedWalletDeletionSafety(params);
	if (!safety.ok) throw new WalletDeletionBlockedError(safety.message, safety.details);
}
function normalizeWalletEntry(raw) {
	if (!raw || typeof raw !== "object" || Array.isArray(raw)) return null;
	const value = raw;
	const id = typeof value.id === "string" ? value.id.trim() : "";
	const name = typeof value.name === "string" ? value.name.trim() : "";
	const providerId = normalizeProviderId(value.providerId);
	const createdAt = typeof value.createdAt === "string" ? value.createdAt : "";
	const updatedAt = typeof value.updatedAt === "string" ? value.updatedAt : "";
	if (!id || !name || !providerId || !createdAt || !updatedAt) return null;
	const addressesRaw = value.addresses && typeof value.addresses === "object" && !Array.isArray(value.addresses) ? value.addresses : null;
	return {
		id,
		name,
		providerId,
		addresses: addressesRaw ? { solana: typeof addressesRaw.solana === "string" ? addressesRaw.solana.trim() || void 0 : void 0 } : void 0,
		metadata: value.metadata && typeof value.metadata === "object" && !Array.isArray(value.metadata) ? value.metadata : void 0,
		createdAt,
		updatedAt
	};
}
function isLegacySelfHostedWallet(wallet) {
	if (wallet.providerId !== "embedded-keystore") return false;
	if ((wallet.metadata && typeof wallet.metadata === "object" && !Array.isArray(wallet.metadata) ? wallet.metadata : void 0)?.selfHosted === true) return true;
	if (/^solana-\d+$/i.test(wallet.id)) return true;
	if (/^solana\s+\d+$/i.test(wallet.name)) return true;
	return false;
}
function makeDefaultRegistry() {
	const ts = nowIso();
	return {
		version: 1,
		providers: {
			"embedded-keystore": {
				enabled: true,
				updatedAt: ts,
				label: "Self-hosted"
			},
			"local-socket-signer": {
				enabled: false,
				updatedAt: ts,
				label: "Local signer"
			},
			alchemy: {
				enabled: false,
				updatedAt: ts
			},
			turnkey: {
				enabled: true,
				updatedAt: ts,
				label: "Turnkey (recommended hosted)"
			},
			privy: {
				enabled: true,
				updatedAt: ts
			}
		},
		wallets: [],
		assignments: {},
		updatedAt: ts
	};
}
function normalizeRegistry(raw) {
	const defaults = makeDefaultRegistry();
	if (!raw || typeof raw !== "object" || Array.isArray(raw)) return {
		registry: defaults,
		changed: false
	};
	let changed = false;
	const value = raw;
	const providersRaw = value.providers && typeof value.providers === "object" && !Array.isArray(value.providers) ? value.providers : {};
	const providers = { ...defaults.providers };
	for (const providerId of WALLET_PROVIDER_IDS) {
		const entryRaw = providersRaw[providerId];
		if (!entryRaw || typeof entryRaw !== "object" || Array.isArray(entryRaw)) continue;
		const entry = entryRaw;
		const enabled = Boolean(entry.enabled);
		let label = typeof entry.label === "string" ? entry.label.trim() || void 0 : void 0;
		if (providerId === "embedded-keystore") {
			if (!label || label === "Embedded keystore (default)" || label === "Self-hosted wallet") label = "Self-hosted";
		}
		if (providerId === "local-socket-signer") {
			if (!label || label === "Local signer daemon") label = "Local signer";
		}
		const updatedAt = typeof entry.updatedAt === "string" ? entry.updatedAt : defaults.updatedAt;
		providers[providerId] = {
			enabled,
			label,
			updatedAt
		};
	}
	const wallets = (Array.isArray(value.wallets) ? value.wallets.map(normalizeWalletEntry).filter((entry) => Boolean(entry)) : []).map((wallet) => {
		if (!isLegacySelfHostedWallet(wallet)) return wallet;
		changed = true;
		const metadata = wallet.metadata && typeof wallet.metadata === "object" && !Array.isArray(wallet.metadata) ? wallet.metadata : void 0;
		return {
			...wallet,
			providerId: "local-socket-signer",
			metadata: {
				...metadata,
				selfHosted: true,
				migratedFromProviderId: metadata?.migratedFromProviderId ?? "embedded-keystore"
			},
			updatedAt: nowIso()
		};
	});
	if (wallets.some((wallet) => wallet.providerId === "local-socket-signer")) {
		const current = providers["local-socket-signer"];
		if (!current.enabled) {
			providers["local-socket-signer"] = {
				...current,
				enabled: true,
				updatedAt: nowIso()
			};
			changed = true;
		}
	}
	const assignmentsRaw = value.assignments && typeof value.assignments === "object" && !Array.isArray(value.assignments) ? value.assignments : {};
	const assignments = {};
	for (const [agentId, walletIdRaw] of Object.entries(assignmentsRaw)) {
		const normalizedAgentId = agentId.trim();
		const walletId = typeof walletIdRaw === "string" ? walletIdRaw.trim() : "";
		if (!normalizedAgentId || !walletId) continue;
		if (!wallets.some((wallet) => wallet.id === walletId)) continue;
		assignments[normalizedAgentId] = walletId;
	}
	const defaultWalletIdRaw = typeof value.defaultWalletId === "string" ? value.defaultWalletId.trim() : void 0;
	const defaultWalletId = defaultWalletIdRaw && wallets.some((wallet) => wallet.id === defaultWalletIdRaw) ? defaultWalletIdRaw : void 0;
	const updatedAt = typeof value.updatedAt === "string" ? value.updatedAt : defaults.updatedAt;
	return {
		changed,
		registry: {
			version: 1,
			providers,
			wallets,
			assignments,
			defaultWalletId,
			updatedAt
		}
	};
}
function readWalletProviderRegistry(env = process.env) {
	const file = registryPath(env);
	if (!fs.existsSync(file)) return makeDefaultRegistry();
	try {
		const normalized = normalizeRegistry(JSON.parse(fs.readFileSync(file, "utf8")));
		if (normalized.changed) writeWalletProviderRegistry(normalized.registry, env);
		return normalized.registry;
	} catch {
		return makeDefaultRegistry();
	}
}
function writeWalletProviderRegistry(registry, env = process.env) {
	const file = registryPath(env);
	const payload = {
		...registry,
		version: 1,
		updatedAt: nowIso()
	};
	fs.writeFileSync(file, `${JSON.stringify(payload, null, 2)}\n`, {
		encoding: "utf8",
		mode: REGISTRY_FILE_MODE
	});
	try {
		fs.chmodSync(file, REGISTRY_FILE_MODE);
	} catch {}
}
function setWalletProviderEnabled(params) {
	const env = params.env ?? process.env;
	const registry = readWalletProviderRegistry(env);
	registry.providers[params.providerId] = {
		enabled: Boolean(params.enabled),
		label: params.label?.trim() || void 0,
		updatedAt: nowIso()
	};
	writeWalletProviderRegistry(registry, env);
	return registry;
}
function setWalletProvidersEnabled(params) {
	const env = params.env ?? process.env;
	const registry = readWalletProviderRegistry(env);
	const enabledSet = new Set(params.enabledProviders);
	const now = nowIso();
	for (const providerId of WALLET_PROVIDER_IDS) {
		const current = registry.providers[providerId] ?? {
			enabled: false,
			updatedAt: now
		};
		const nextEnabled = enabledSet.has(providerId);
		registry.providers[providerId] = {
			...current,
			enabled: nextEnabled,
			updatedAt: current.enabled === nextEnabled ? current.updatedAt : now
		};
	}
	writeWalletProviderRegistry(registry, env);
	return registry;
}
function upsertNamedWallet(params) {
	const env = params.env ?? process.env;
	const registry = readWalletProviderRegistry(env);
	const name = params.name.trim();
	const providedWalletId = params.walletId?.trim();
	if (!name) throw new Error("wallet name is required");
	if (providedWalletId && !/^[a-zA-Z0-9_-]+$/.test(providedWalletId)) throw new Error("walletId must contain only letters, numbers, hyphens, or underscores");
	const existing = providedWalletId ? registry.wallets.find((entry) => entry.id === providedWalletId) : void 0;
	const now = nowIso();
	const next = {
		id: existing?.id ?? providedWalletId ?? newWalletId(),
		name,
		providerId: params.providerId,
		addresses: params.addresses ?? existing?.addresses,
		metadata: params.metadata ?? existing?.metadata,
		createdAt: existing?.createdAt ?? now,
		updatedAt: now
	};
	registry.wallets = [...registry.wallets.filter((entry) => entry.id !== next.id), next].toSorted((a, b) => a.createdAt.localeCompare(b.createdAt));
	if (!registry.defaultWalletId || !registry.wallets.some((wallet) => wallet.id === registry.defaultWalletId)) registry.defaultWalletId = resolveWalletUserRole(next) === "agent" ? next.id : void 0;
	writeWalletProviderRegistry(registry, env);
	return next;
}
function deleteNamedWallet(params) {
	const env = params.env ?? process.env;
	const registry = readWalletProviderRegistry(env);
	const walletId = params.walletId.trim();
	if (new Set((params.protectedWalletIds ?? []).map((value) => value.trim()).filter(Boolean)).has(walletId)) throw new Error("walletId is protected from deletion");
	assertNamedWalletDeletionSafe({
		walletId,
		env
	});
	const before = registry.wallets.length;
	registry.wallets = registry.wallets.filter((entry) => entry.id !== walletId);
	for (const [agentId, assignedWalletId] of Object.entries(registry.assignments)) if (assignedWalletId === walletId) delete registry.assignments[agentId];
	if (registry.defaultWalletId === walletId) registry.defaultWalletId = void 0;
	const removed = registry.wallets.length !== before;
	writeWalletProviderRegistry(registry, env);
	return {
		removed,
		registry
	};
}
function setAgentWalletAssignment(params) {
	const env = params.env ?? process.env;
	const registry = readWalletProviderRegistry(env);
	const agentId = params.agentId.trim();
	if (!agentId) throw new Error("agentId is required");
	const walletId = params.walletId?.trim();
	if (!walletId) {
		delete registry.assignments[agentId];
		writeWalletProviderRegistry(registry, env);
		return registry;
	}
	if (!registry.wallets.some((wallet) => wallet.id === walletId)) throw new Error("walletId does not exist");
	registry.assignments[agentId] = walletId;
	writeWalletProviderRegistry(registry, env);
	return registry;
}
function setDefaultWallet(params) {
	const env = params.env ?? process.env;
	const registry = readWalletProviderRegistry(env);
	const walletId = params.walletId?.trim();
	if (!walletId) {
		registry.defaultWalletId = void 0;
		writeWalletProviderRegistry(registry, env);
		return registry;
	}
	const targetWallet = registry.wallets.find((wallet) => wallet.id === walletId);
	if (!targetWallet) throw new Error("walletId does not exist");
	const purpose = resolveWalletUserRole(targetWallet);
	if (purpose && purpose !== "agent") throw new Error("only Agent wallets can become the primary Agent fallback");
	registry.wallets = registry.wallets.map((wallet) => {
		if (wallet.id !== walletId) return wallet;
		return {
			...wallet,
			metadata: {
				...wallet.metadata,
				role: "agent",
				purpose: "agent"
			},
			updatedAt: nowIso()
		};
	});
	registry.defaultWalletId = walletId;
	writeWalletProviderRegistry(registry, env);
	return registry;
}
function setNamedWalletRole(params) {
	const env = params.env ?? process.env;
	const registry = readWalletProviderRegistry(env);
	const walletId = params.walletId.trim();
	if (!walletId) throw new Error("walletId is required");
	if (!registry.wallets.some((wallet) => wallet.id === walletId)) throw new Error("walletId does not exist");
	registry.wallets = registry.wallets.map((wallet) => wallet.id === walletId ? {
		...wallet,
		metadata: {
			...wallet.metadata,
			role: params.role,
			purpose: params.role
		},
		updatedAt: nowIso()
	} : wallet);
	if (params.role === "agent" && !registry.defaultWalletId) registry.defaultWalletId = walletId;
	if (params.role === "vault" && registry.defaultWalletId === walletId) registry.defaultWalletId = registry.wallets.find((wallet) => wallet.id !== walletId && resolveWalletUserRole(wallet) === "agent")?.id;
	writeWalletProviderRegistry(registry, env);
	return registry;
}
function resolveWalletSelectionForAgent(params) {
	const registry = readWalletProviderRegistry(params.env ?? process.env);
	const directAgent = params.agentId?.trim();
	const walletId = (directAgent ? registry.assignments[directAgent] : void 0) ?? registry.defaultWalletId;
	if (!walletId) return {};
	const wallet = registry.wallets.find((entry) => entry.id === walletId);
	if (!wallet) return {};
	return {
		walletId: wallet.id,
		walletName: wallet.name,
		providerId: wallet.providerId
	};
}
function resolveWalletSelection(params) {
	const env = params.env ?? process.env;
	const registry = readWalletProviderRegistry(env);
	const walletId = params.walletId?.trim();
	const walletName = params.walletName?.trim();
	const providerId = params.providerId;
	if (walletId || walletName || providerId) {
		let matchedWallet;
		if (walletId) {
			matchedWallet = registry.wallets.find((entry) => entry.id === walletId);
			if (!matchedWallet) throw new Error(`walletId not found: ${walletId}`);
		}
		if (walletName) {
			const normalizedName = walletName.toLowerCase();
			const byName = registry.wallets.filter((entry) => entry.name.toLowerCase() === normalizedName);
			if (!byName.length) throw new Error(`walletName not found: ${walletName}`);
			if (matchedWallet) {
				const matchedWalletId = matchedWallet.id;
				if (!byName.find((entry) => entry.id === matchedWalletId)) throw new Error("walletId and walletName do not refer to the same wallet");
			} else if (providerId) {
				const byProvider = byName.filter((entry) => entry.providerId === providerId);
				if (!byProvider.length) throw new Error(`walletName ${walletName} is not available for provider ${providerId}`);
				if (byProvider.length > 1) throw new Error(`walletName ${walletName} is ambiguous for provider ${providerId}; use walletId`);
				matchedWallet = byProvider[0];
			} else if (byName.length > 1) throw new Error(`walletName ${walletName} is ambiguous; include providerId or walletId`);
			else matchedWallet = byName[0];
		}
		if (matchedWallet && providerId && matchedWallet.providerId !== providerId) throw new Error(`wallet ${matchedWallet.name} (${matchedWallet.id}) belongs to provider ${matchedWallet.providerId}, not ${providerId}`);
		if (matchedWallet) return {
			walletId: matchedWallet.id,
			walletName: matchedWallet.name,
			providerId: matchedWallet.providerId,
			source: "explicit"
		};
		return {
			providerId,
			source: "explicit"
		};
	}
	const fallback = resolveWalletSelectionForAgent({
		agentId: params.agentId,
		env
	});
	if (fallback.walletId || fallback.providerId) return {
		...fallback,
		source: "fallback"
	};
	return { source: "none" };
}

//#endregion
export { readWalletProviderRegistry as a, setAgentWalletAssignment as c, setWalletProviderEnabled as d, setWalletProvidersEnabled as f, normalizeWalletUserRole as i, setDefaultWallet as l, checkNamedWalletDeletionSafety as n, resolveWalletSelection as o, upsertNamedWallet as p, deleteNamedWallet as r, resolveWalletUserRole as s, WALLET_PROVIDER_IDS as t, setNamedWalletRole as u };