import { openHippoDb, closeHippoDb } from '../../db.js';
import { ingestMessage } from './ingest.js';
function readCursor(root, tenantId, channelId) {
    const db = openHippoDb(root);
    try {
        const row = db
            .prepare(`SELECT latest_ts FROM slack_cursors WHERE tenant_id=? AND channel_id=?`)
            .get(tenantId, channelId);
        return row?.latest_ts ?? null;
    }
    finally {
        closeHippoDb(db);
    }
}
function writeCursor(root, tenantId, channelId, latestTs) {
    const db = openHippoDb(root);
    try {
        db.prepare(`INSERT INTO slack_cursors (tenant_id, channel_id, latest_ts, updated_at) VALUES (?,?,?,?)
       ON CONFLICT(tenant_id, channel_id) DO UPDATE SET latest_ts = excluded.latest_ts, updated_at = excluded.updated_at`).run(tenantId, channelId, latestTs, new Date().toISOString());
    }
    finally {
        closeHippoDb(db);
    }
}
/**
 * Page through `conversations.history` via the injected fetcher and ingest each
 * message. The cursor is persisted to `slack_cursors` after every page so a
 * crash mid-backfill resumes near where it left off.
 *
 * Each ingested message uses a synthesized eventId of the form
 * `backfill:${teamId}:${channelId}:${ts}`. Reruns dedupe via the
 * `slack_event_log` PK so calling `backfillChannel` twice is safe.
 */
export async function backfillChannel(ctx, opts) {
    // Resume bound from previous run; passed as `oldest` (numeric ts) on the
    // first page only. `cursor` starts null — Slack mints the next-page token
    // and we feed it back. Mixing the two would feed a numeric ts as an opaque
    // cursor and break against the live API on rerun.
    const resumeFrom = readCursor(ctx.hippoRoot, ctx.tenantId, opts.channel.id);
    let cursor = null;
    let ingested = 0;
    let pages = 0;
    let latestTs = resumeFrom;
    while (true) {
        const page = await opts.fetcher({
            channelId: opts.channel.id,
            cursor,
            oldest: pages === 0 && resumeFrom ? resumeFrom : undefined,
        });
        pages++;
        for (const msg of page.messages) {
            const r = ingestMessage(ctx, {
                teamId: opts.teamId,
                channel: opts.channel,
                message: msg,
                eventId: `backfill:${opts.teamId}:${opts.channel.id}:${msg.ts}`,
            });
            if (r.status === 'ingested')
                ingested++;
            if (!latestTs || msg.ts > latestTs)
                latestTs = msg.ts;
            if (opts.maxMessages && ingested >= opts.maxMessages) {
                if (latestTs)
                    writeCursor(ctx.hippoRoot, ctx.tenantId, opts.channel.id, latestTs);
                return { ingested, pages };
            }
        }
        if (latestTs)
            writeCursor(ctx.hippoRoot, ctx.tenantId, opts.channel.id, latestTs);
        if (!page.next_cursor)
            break;
        cursor = page.next_cursor;
    }
    return { ingested, pages };
}
//# sourceMappingURL=backfill.js.map