/**
 * A persistent, process-shared session backend built on `bun:sqlite` (sync, so
 * it satisfies `SessionBackend` without a load/save wrapper). Sessions survive
 * restarts and are shared by every worker pointed at the same file.
 *
 *   import { setSessionBackend } from "@wrnexus/core";
 *   import { sqliteSessionStore } from "@wrnexus/db/session";
 *   setSessionBackend(sqliteSessionStore("./sessions.db"));
 */

import { Database } from "bun:sqlite";
import type { SessionBackend, SessionEntry } from "@wrnexus/core";

export function sqliteSessionStore(path = "sessions.db"): SessionBackend {
  const db = new Database(path);
  db.run("PRAGMA journal_mode = WAL");
  db.run(
    "CREATE TABLE IF NOT EXISTS sessions (id TEXT PRIMARY KEY, data TEXT NOT NULL, expiresAt INTEGER NOT NULL)",
  );
  const getStmt = db.query("SELECT data, expiresAt FROM sessions WHERE id = ?");
  const setStmt = db.query(
    "INSERT INTO sessions (id, data, expiresAt) VALUES (?, ?, ?) " +
      "ON CONFLICT(id) DO UPDATE SET data = excluded.data, expiresAt = excluded.expiresAt",
  );
  const delStmt = db.query("DELETE FROM sessions WHERE id = ?");
  const gcStmt = db.query("DELETE FROM sessions WHERE expiresAt <= ?");

  return {
    get(id): SessionEntry | undefined {
      const row = getStmt.get(id) as { data: string; expiresAt: number } | null;
      if (!row) return undefined;
      try {
        return { data: JSON.parse(row.data) as Record<string, unknown>, expiresAt: row.expiresAt };
      } catch (error) {
        console.warn(`[wrnexus:db] discarded corrupt session '${id}'`, error);
        return undefined;
      }
    },
    set(id, entry) {
      setStmt.run(id, JSON.stringify(entry.data), entry.expiresAt);
    },
    delete(id) {
      delStmt.run(id);
    },
    gc(now) {
      gcStmt.run(now);
    },
  };
}
