export function createReconciler(deps) {
    const { repo, k8s, transit, managedLabelValue } = deps;
    async function decryptSecrets(tenantId, rows) {
        const out = {};
        // Decrypt in parallel with the tenant's own transit key; isolate per-key
        // failures so one bad ciphertext doesn't break the whole Secret.
        const results = await Promise.all(rows.map(async (r) => {
            if (r.ciphertext == null) {
                return { key: r.key, value: null, error: null };
            }
            try {
                const value = await transit.decrypt(tenantId, r.ciphertext);
                return { key: r.key, value, error: null };
            }
            catch (err) {
                return {
                    key: r.key,
                    value: null,
                    error: err instanceof Error ? err.message : String(err),
                };
            }
        }));
        for (const r of results) {
            if (r.error) {
                console.error(`[reconciler] decrypt failed for key '${r.key}': ${r.error} — omitting from Secret`);
                continue;
            }
            if (r.value != null)
                out[r.key] = r.value;
        }
        return out;
    }
    async function reconcileTenant(tenantId) {
        const [envRows, secretRows] = await Promise.all([
            repo.envVarsForTenant(tenantId),
            repo.secretsForTenant(tenantId),
        ]);
        const envData = {};
        for (const row of envRows)
            envData[row.key] = row.value;
        const secretData = await decryptSecrets(tenantId, secretRows);
        const cmResult = await k8s.upsertConfigMap({
            namespace: tenantId,
            name: `${tenantId}-env`,
            managedLabel: managedLabelValue,
        }, envData);
        const secretResult = await k8s.upsertSecret({
            namespace: tenantId,
            name: `${tenantId}-secrets`,
            managedLabel: managedLabelValue,
        }, secretData);
        console.info(`[reconciler] tenant=${tenantId} env=${Object.keys(envData).length}:${cmResult} secrets=${Object.keys(secretData).length}:${secretResult}`);
    }
    async function reconcileAll() {
        const tenantIds = (await repo.allTenantIds()).sort();
        console.info(`[reconciler] full reconcile: ${tenantIds.length} tenant(s)`);
        const errors = [];
        for (const tenantId of tenantIds) {
            try {
                await reconcileTenant(tenantId);
            }
            catch (err) {
                errors.push({
                    tenantId,
                    error: err instanceof Error ? err.message : String(err),
                });
            }
        }
        if (errors.length > 0) {
            console.error(`[reconciler] full reconcile finished with ${errors.length} error(s): ${JSON.stringify(errors)}`);
        }
    }
    return { reconcileTenant, reconcileAll };
}
