const ID_ALPHABET = "abcdefghijklmnopqrstuvwxyz0123456789";
function shortId(len = 12) {
    let s = "";
    for (let i = 0; i < len; i++) {
        s += ID_ALPHABET[Math.floor(Math.random() * ID_ALPHABET.length)];
    }
    return s;
}
const TTL_HOURS = 24;
const IN_FLIGHT = ["PENDING", "RUNNING"];
const ERROR_MESSAGE_LIMIT = 500;
export class DumpsRepo {
    db;
    constructor(db) {
        this.db = db;
    }
    async create(input) {
        const existing = await this.db
            .selectFrom("database_dumps")
            .select(["id"])
            .where("tenantId", "=", input.tenantId)
            .where("status", "in", [...IN_FLIGHT])
            .executeTakeFirst();
        if (existing)
            throw new Error("DUMP_IN_PROGRESS");
        const id = shortId();
        const expiresAt = new Date(input.now.getTime() + TTL_HOURS * 3600 * 1000);
        const row = {
            id,
            documentId: input.documentId,
            tenantId: input.tenantId,
            requestedBy: input.requestedBy.toLowerCase(),
            status: "PENDING",
            jobName: null,
            s3Key: null,
            sizeBytes: null,
            errorMessage: null,
            requestedAt: input.now.toISOString(),
            startedAt: null,
            completedAt: null,
            expiresAt: expiresAt.toISOString(),
        };
        await this.db.insertInto("database_dumps").values(row).execute();
        return row;
    }
    async setJobName(id, jobName) {
        await this.db
            .updateTable("database_dumps")
            .set({ jobName })
            .where("id", "=", id)
            .execute();
    }
    async markRunning(id, jobName, at) {
        await this.db
            .updateTable("database_dumps")
            .set({ status: "RUNNING", jobName, startedAt: at.toISOString() })
            .where("id", "=", id)
            .where("status", "=", "PENDING")
            .execute();
    }
    async markReady(id, s3Key, sizeBytes, at) {
        await this.db
            .updateTable("database_dumps")
            .set({
            status: "READY",
            s3Key,
            sizeBytes,
            completedAt: at.toISOString(),
        })
            .where("id", "=", id)
            .execute();
    }
    async markFailed(id, errorMessage, at) {
        await this.db
            .updateTable("database_dumps")
            .set({
            status: "FAILED",
            errorMessage: errorMessage.slice(0, ERROR_MESSAGE_LIMIT),
            completedAt: at.toISOString(),
        })
            .where("id", "=", id)
            .execute();
    }
    async listByTenant(tenantId, limit = 20) {
        const rows = await this.db
            .selectFrom("database_dumps")
            .selectAll()
            .where("tenantId", "=", tenantId)
            .orderBy("requestedAt", "desc")
            .limit(limit)
            .execute();
        return rows;
    }
    async getById(id) {
        const row = await this.db
            .selectFrom("database_dumps")
            .selectAll()
            .where("id", "=", id)
            .executeTakeFirst();
        return row ?? null;
    }
    async listInFlight() {
        const rows = await this.db
            .selectFrom("database_dumps")
            .selectAll()
            .where("status", "in", [...IN_FLIGHT])
            .execute();
        return rows;
    }
    async pruneOlderThan(cutoff) {
        const result = await this.db
            .deleteFrom("database_dumps")
            .where("requestedAt", "<", cutoff.toISOString())
            .executeTakeFirst();
        return Number(result.numDeletedRows ?? 0);
    }
}
