// Engine-neutral transactional writes.
//
// better-sqlite3 transactions take a *synchronous* callback (awaiting inside one
// silently breaks atomicity), while node-postgres takes an async one. Rather than
// fork every multi-write route into two near-identical branches, callers build a
// plain list of operations and hand it here: the business logic stays in one
// place and only the six lines below know which driver is underneath.

import { db, isSqlite } from '../db/index.js';

export type TxOp =
  | { kind: 'insert'; table: any; values: any }
  | { kind: 'update'; table: any; values: any; where: any }
  | { kind: 'delete'; table: any; where: any };

export const insertOp = (table: any, values: any): TxOp => ({ kind: 'insert', table, values });
export const updateOp = (table: any, values: any, where: any): TxOp => ({ kind: 'update', table, values, where });
export const deleteOp = (table: any, where: any): TxOp => ({ kind: 'delete', table, where });

/** Apply every op inside a single transaction; any throw rolls back all of them. */
export async function runOps(ops: TxOp[]): Promise<void> {
  if (ops.length === 0) return;

  if (isSqlite()) {
    (db as any).transaction((tx: any) => {
      for (const op of ops) {
        if (op.kind === 'insert') tx.insert(op.table).values(op.values).run();
        else if (op.kind === 'update') tx.update(op.table).set(op.values).where(op.where).run();
        else tx.delete(op.table).where(op.where).run();
      }
    });
    return;
  }

  await (db as any).transaction(async (tx: any) => {
    for (const op of ops) {
      if (op.kind === 'insert') await tx.insert(op.table).values(op.values);
      else if (op.kind === 'update') await tx.update(op.table).set(op.values).where(op.where);
      else await tx.delete(op.table).where(op.where);
    }
  });
}
