/**
 * Financial dual-write helper.
 *
 * Cutover mode (DUAL_WRITE=false / Mongo inactive):
 *   Never calls mongoWrite or mongoCompensate. Callers must use a MySQL-primary
 *   path (mysqlPrimaryWrite or their own *MysqlPrimary early return).
 *
 * Dual-write mode (DUAL_WRITE=true and ACTIVE_DATABASE=mongodb):
 *   Mongo primary write, then MySQL mirror. On MySQL failure, compensate Mongo.
 */
import { isDualWriteEnabled } from "@/db/dualWrite";
import { isMongoActive } from "@/db/activeDatabase";

export function isFinancialDualWriteEnabled() {
  return isDualWriteEnabled() && isMongoActive();
}

function logFail(site: string, err: unknown) {
  const msg = err instanceof Error ? err.message : String(err);
  console.error(`[dual-write-financial] FAIL ${site}: ${msg}`);
}

function maybeInjectMongoFail(site: string) {
  if ((process.env.DUAL_WRITE_MONGO_FAIL || "").trim() === "1") {
    throw new Error(`injected dual-write mongo fail at ${site}`);
  }
}

/**
 * When dual-write is enabled: mongoWrite → mysqlWrite (compensate Mongo on MySQL fail).
 * When dual-write is disabled: only mysqlPrimaryWrite runs — Mongo is never touched.
 */
export async function withFinancialDualWrite<T>(opts: {
  site: string;
  mongoWrite: () => Promise<T>;
  mysqlWrite: (result: T) => Promise<void>;
  mongoCompensate: (result: T) => Promise<void>;
  /** Required when dual-write is off; MySQL-only write path (no Mongo). */
  mysqlPrimaryWrite?: () => Promise<T>;
}): Promise<T> {
  if (!isFinancialDualWriteEnabled()) {
    if (opts.mysqlPrimaryWrite) {
      return opts.mysqlPrimaryWrite();
    }
    throw new Error(
      `[financial] ${opts.site}: dual-write disabled — Mongo writes are blocked. ` +
        `Provide mysqlPrimaryWrite or call MySQL adapters before withFinancialDualWrite.`,
    );
  }

  maybeInjectMongoFail(opts.site);
  const result = await opts.mongoWrite();
  try {
    await opts.mysqlWrite(result);
    return result;
  } catch (e) {
    logFail(opts.site, e);
    try {
      await opts.mongoCompensate(result);
    } catch (ce) {
      logFail(`${opts.site}.compensate`, ce);
    }
    throw e;
  }
}
