import { createRequire } from "node:module";

import type BetterSqlite3 from "better-sqlite3";

const require = createRequire(import.meta.url);
const Database = require("better-sqlite3") as typeof BetterSqlite3;

export class RetentionCleanup {
  private readonly clock: () => number;
  private readonly database: BetterSqlite3.Database;
  private retentionPurgeActive = false;
  private retentionPurgeNow = 0;

  constructor(input: { clock?: () => number; databasePath: string }) {
    this.clock = input.clock ?? Date.now;
    const nativeBinding = process.env.DADA_SQLITE_NATIVE_BINDING;
    this.database = new Database(input.databasePath, nativeBinding ? { nativeBinding } : undefined);
    this.database.pragma("foreign_keys = ON");
    this.database.pragma("busy_timeout = 5000");
    this.database.function("dada_allow_privacy_purge", { deterministic: false }, () => 0);
    this.database.function("dada_allow_retention_purge", { deterministic: false }, () => this.retentionPurgeActive ? 1 : 0);
    this.database.function("dada_retention_purge_now", { deterministic: false }, () => this.retentionPurgeNow);
  }

  purgeExpired() {
    const now = this.clock();
    this.database.exec("BEGIN IMMEDIATE");
    try {
      this.retentionPurgeActive = true;
      this.retentionPurgeNow = now;
      const adminOperations = this.database.prepare("DELETE FROM admin_operation_logs WHERE expires_at <= ?").run(now);
      const privateAccess = this.database.prepare("DELETE FROM private_content_access_logs WHERE expires_at <= ?").run(now);
      const anonymous = this.database.prepare("DELETE FROM anonymous_retained_events WHERE expires_at <= ?").run(now);
      this.retentionPurgeActive = false;
      this.retentionPurgeNow = 0;
      this.database.exec("COMMIT");
      return {
        admin_operation_logs: adminOperations.changes,
        anonymous_events: anonymous.changes,
        private_access_logs: privateAccess.changes,
      };
    } catch (error) {
      this.retentionPurgeActive = false;
      this.retentionPurgeNow = 0;
      if (this.database.inTransaction) this.database.exec("ROLLBACK");
      throw error;
    }
  }

  close() {
    this.database.close();
  }
}
