import { appendAllowFromIdSync } from "./allow-from-file.js";
import "./pairing-constants.js";
import crypto from "node:crypto";
import fs from "node:fs";
import path from "node:path";
//#region src/channels/pairing/pairing-store.ts
const PAIRING_CODE_LENGTH = 8;
const PAIRING_CODE_ALPHABET = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
const PAIRING_PENDING_TTL_MS = 3600 * 1e3;
function randomCode() {
	let out = "";
	for (let i = 0; i < PAIRING_CODE_LENGTH; i++) {
		const idx = crypto.randomInt(0, 32);
		out += PAIRING_CODE_ALPHABET[idx];
	}
	return out;
}
function parseTs(iso) {
	if (!iso) return null;
	const n = Date.parse(iso);
	return Number.isFinite(n) ? n : null;
}
function isExpired(entry, nowMs) {
	const t = parseTs(entry.createdAt);
	if (t == null) return true;
	return nowMs - t > PAIRING_PENDING_TTL_MS;
}
function pruneExpired(reqs, nowMs) {
	return reqs.filter((r) => !isExpired(r, nowMs));
}
function normalizeAccountId(accountId) {
	return (accountId ?? "default").trim().toLowerCase() || "default";
}
function requestAccountId(entry) {
	return entry.meta?.accountId?.trim().toLowerCase() || "default";
}
function readStore(filePath) {
	try {
		if (!fs.existsSync(filePath)) return {
			version: 1,
			requests: []
		};
		const raw = fs.readFileSync(filePath, "utf-8");
		const parsed = JSON.parse(raw);
		if (parsed && Array.isArray(parsed.requests)) return {
			version: 1,
			requests: parsed.requests
		};
	} catch {}
	return {
		version: 1,
		requests: []
	};
}
function writeStore(filePath, store) {
	const dir = path.dirname(filePath);
	fs.mkdirSync(dir, { recursive: true });
	fs.writeFileSync(filePath, JSON.stringify(store, null, 2), "utf-8");
	try {
		fs.chmodSync(filePath, 384);
	} catch {}
}
/**
* Create or refresh a pending pairing request for `id` (e.g. Telegram user id).
* Returns `created: true` when a new code was minted (caller should notify the user).
*/
function upsertPairingRequestSync(params) {
	const now = (/* @__PURE__ */ new Date()).toISOString();
	const nowMs = Date.now();
	const id = String(params.id).trim();
	if (!id) return {
		code: "",
		created: false
	};
	const normalizedAccountId = normalizeAccountId(params.accountId);
	const meta = {
		...params.meta && typeof params.meta === "object" ? Object.fromEntries(Object.entries(params.meta).map(([k, v]) => [k, typeof v === "string" ? v.trim() : ""]).filter(([, v]) => Boolean(v))) : {},
		accountId: normalizedAccountId
	};
	let reqs = pruneExpired(readStore(params.pairingFilePath).requests, nowMs);
	const idx = reqs.findIndex((r) => r.id === id && requestAccountId(r) === normalizedAccountId);
	const existingCodes = new Set(reqs.map((r) => r.code.toUpperCase()));
	if (idx >= 0) {
		const existing = reqs[idx];
		const code = existing.code || randomCode();
		reqs[idx] = {
			id,
			code,
			createdAt: existing.createdAt || now,
			lastSeenAt: now,
			meta: {
				...existing.meta,
				...meta
			}
		};
		writeStore(params.pairingFilePath, {
			version: 1,
			requests: reqs
		});
		return {
			code,
			created: false
		};
	}
	if (reqs.filter((r) => requestAccountId(r) === normalizedAccountId).length >= 3) {
		writeStore(params.pairingFilePath, {
			version: 1,
			requests: reqs
		});
		return {
			code: "",
			created: false
		};
	}
	let code = randomCode();
	for (let attempt = 0; attempt < 50 && existingCodes.has(code.toUpperCase()); attempt++) code = randomCode();
	existingCodes.add(code.toUpperCase());
	reqs = [...reqs, {
		id,
		code,
		createdAt: now,
		lastSeenAt: now,
		meta
	}];
	writeStore(params.pairingFilePath, {
		version: 1,
		requests: reqs
	});
	return {
		code,
		created: true
	};
}
/**
* Approve a pairing code: remove pending request and append sender id to allowFrom file.
*/
/** Non-expired pending requests; prunes expired entries from disk. */
function listPendingPairingRequestsSync(pairingFilePath) {
	const nowMs = Date.now();
	let store = readStore(pairingFilePath);
	const reqs = pruneExpired(store.requests, nowMs);
	if (reqs.length !== store.requests.length) writeStore(pairingFilePath, {
		version: 1,
		requests: reqs
	});
	return reqs;
}
function approvePairingCodeSync(params) {
	const want = (params.code ?? "").trim().toUpperCase();
	if (!want) return null;
	const normalizedAccount = normalizeAccountId(params.accountId);
	let reqs = pruneExpired(readStore(params.pairingFilePath).requests, Date.now());
	const idx = reqs.findIndex((r) => r.code.toUpperCase() === want && requestAccountId(r) === normalizedAccount);
	if (idx < 0) {
		writeStore(params.pairingFilePath, {
			version: 1,
			requests: reqs
		});
		return null;
	}
	const entry = reqs[idx];
	reqs.splice(idx, 1);
	writeStore(params.pairingFilePath, {
		version: 1,
		requests: reqs
	});
	appendAllowFromIdSync(params.allowFromFilePath, entry.id);
	return { senderId: entry.id };
}
/** Approve a pending request by sender id (gateway-authenticated quick approve). */
function approvePairingBySenderIdSync(params) {
	const normalizedAccount = normalizeAccountId(params.accountId);
	const wantId = String(params.senderId ?? "").trim();
	if (!wantId) return null;
	let reqs = pruneExpired(readStore(params.pairingFilePath).requests, Date.now());
	const idx = reqs.findIndex((r) => r.id === wantId && requestAccountId(r) === normalizedAccount);
	if (idx < 0) {
		writeStore(params.pairingFilePath, {
			version: 1,
			requests: reqs
		});
		return null;
	}
	const entry = reqs[idx];
	reqs.splice(idx, 1);
	writeStore(params.pairingFilePath, {
		version: 1,
		requests: reqs
	});
	appendAllowFromIdSync(params.allowFromFilePath, entry.id);
	return { senderId: entry.id };
}
/** Remove a pending request without approving (admin dismiss). */
function dismissPairingBySenderIdSync(params) {
	const normalizedAccount = normalizeAccountId(params.accountId);
	const wantId = String(params.senderId ?? "").trim();
	if (!wantId) return null;
	let reqs = pruneExpired(readStore(params.pairingFilePath).requests, Date.now());
	const idx = reqs.findIndex((r) => r.id === wantId && requestAccountId(r) === normalizedAccount);
	if (idx < 0) {
		writeStore(params.pairingFilePath, {
			version: 1,
			requests: reqs
		});
		return null;
	}
	const entry = reqs[idx];
	reqs.splice(idx, 1);
	writeStore(params.pairingFilePath, {
		version: 1,
		requests: reqs
	});
	return { senderId: entry.id };
}
//#endregion
export { PAIRING_PENDING_TTL_MS, approvePairingBySenderIdSync, approvePairingCodeSync, dismissPairingBySenderIdSync, listPendingPairingRequestsSync, upsertPairingRequestSync };

//# sourceMappingURL=pairing-store.js.map