import { updateDocument } from '../actions.js';
import { layoutTreeToSections } from './bridge.js';
function isPlainObject(v) {
    return !!v && typeof v === 'object' && !Array.isArray(v);
}
/** A document already has authoritative sections when the array is non-empty. */
function hasStoredSections(data) {
    return Array.isArray(data.sections) && data.sections.length > 0;
}
/**
 * Backfill `data.sections` for legacy `_layout`-only documents.
 *
 * @param ctx  An admin {@link ActionContext} (role must be allowed to update the
 *   target collections — use a system/admin user).
 */
export async function migratePageBuilderSections(ctx, options = {}) {
    const dryRun = options.dryRun ?? false;
    const batchSize = options.batchSize && options.batchSize > 0 ? options.batchSize : 100;
    // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Prisma client is intentionally untyped at the core/config boundary (see ActionContext).
    const db = ctx.db;
    const result = {
        scanned: 0,
        migrated: 0,
        skipped: 0,
        migratedIds: [],
    };
    let cursor;
    // Keyset pagination on the primary key keeps memory flat and is stable even
    // as we mutate rows mid-scan (we only ever move forward past `cursor`).
    for (;;) {
        const batch = await db.document.findMany({
            where: { deletedAt: null },
            orderBy: { id: 'asc' },
            take: batchSize,
            ...(cursor ? { skip: 1, cursor: { id: cursor } } : {}),
            select: { id: true, collection: true, data: true },
        });
        if (batch.length === 0)
            break;
        cursor = batch[batch.length - 1].id;
        for (const doc of batch) {
            result.scanned++;
            const data = isPlainObject(doc.data) ? doc.data : null;
            if (!data || !isPlainObject(data._layout) || hasStoredSections(data)) {
                result.skipped++;
                continue;
            }
            const sections = layoutTreeToSections(data._layout);
            if (sections.length === 0) {
                // A layout that compiles to nothing (empty/unmappable) — leave it for the
                // read-time bridge rather than persisting an empty array.
                result.skipped++;
                continue;
            }
            if (!dryRun) {
                await updateDocument(doc.collection, doc.id, { sections }, ctx);
            }
            result.migrated++;
            result.migratedIds.push(doc.id);
        }
        if (batch.length < batchSize)
            break;
    }
    return result;
}
//# sourceMappingURL=migrate.js.map