/**
 * W6 — tx-capable sweep drivers: wire module sweep entrypoints onto multideal db.transaction().
 */
import {
  sweepMaturation,
  sweepWithdrawable,
  type MaturityHostStore,
  type SweepMaturationResult,
} from '@platform-modules/affiliate';
import type { AffiliateSchema } from '@platform-modules/affiliate/schema';
import type { LedgerSchema } from '@platform-modules/ledger';
import type { VestingSchema } from '@platform-modules/ledger/vesting';
import type { TransactionalDatabase, Transaction } from '@platform-modules/db';
import type * as hostSchema from '@/server/db/schema';

export class SweepDriverRequiresTransactionalDatabaseError extends Error {
  readonly code = 'SWEEP_DRIVER_REQUIRES_TRANSACTIONAL_DATABASE' as const;
  readonly _sweepDriverError = true as const;

  constructor(message = 'sweep driver requires a TransactionalDatabase') {
    super(message);
    this.name = 'SweepDriverRequiresTransactionalDatabaseError';
  }
}

export type HostTransaction = Transaction<typeof hostSchema>;

/** Bridge host drizzle tx to module affiliate/ledger/vesting API (companion tables share one DB tx). */
type ModuleMoneyTx = Transaction<
  typeof hostSchema & AffiliateSchema & LedgerSchema & VestingSchema
>;

function asModuleMoneyTx(tx: HostTransaction): ModuleMoneyTx {
  return tx as unknown as ModuleMoneyTx;
}

function assertTransactionalDatabase(
  db: TransactionalDatabase<typeof hostSchema>,
): asserts db is TransactionalDatabase<typeof hostSchema> {
  if (typeof (db as { transaction?: unknown }).transaction !== 'function') {
    throw new SweepDriverRequiresTransactionalDatabaseError();
  }
}

export async function sweepMaturationDriver(
  db: TransactionalDatabase<typeof hostSchema>,
  host: MaturityHostStore,
): Promise<SweepMaturationResult> {
  assertTransactionalDatabase(db);
  return db.transaction(async (tx) => sweepMaturation(asModuleMoneyTx(tx), host));
}

export async function sweepWithdrawableDriver(
  db: TransactionalDatabase<typeof hostSchema>,
  host: MaturityHostStore,
): Promise<{ updated: number }> {
  assertTransactionalDatabase(db);
  return db.transaction(async (tx) => sweepWithdrawable(asModuleMoneyTx(tx), host));
}
