/**
 * Unit test for `runPgDump` in backup.service.ts.
 *
 * Regression: the dump promise must resolve once BOTH (a) the child process
 * exits 0 and (b) the output file is fully flushed — regardless of which event
 * fires first. The original implementation attached the file's `finish`
 * listener *inside* the child `close` handler, but `stdout.pipe(out)`
 * auto-ends the file when the child's stdout closes, so `finish` frequently
 * fired before the listener was attached → the promise hung forever (observed
 * end-to-end against a real pg_dump).
 *
 * We drive the spawn with `node` instead of `pg_dump` (injected via opts) so
 * the test is deterministic and needs no database.
 */

import { readFileSync, mkdtempSync, rmSync } from 'node:fs';
import { tmpdir } from 'node:os';
import path from 'node:path';

import { afterEach, beforeEach, describe, expect, it } from 'vitest';

import { runPgDump } from '@/lib/services/backup.service';

describe('runPgDump', () => {
  let dir: string;

  beforeEach(() => {
    dir = mkdtempSync(path.join(tmpdir(), 'pn-pgdump-'));
  });

  afterEach(() => {
    rmSync(dir, { recursive: true, force: true });
  });

  it('resolves and writes the child stdout to the output file on exit 0', async () => {
    const out = path.join(dir, 'a.dump');
    await runPgDump('ignored://url', out, {
      command: process.execPath,
      buildArgs: () => ['-e', 'process.stdout.write("DUMP-CONTENTS-1234")'],
    });
    expect(readFileSync(out, 'utf8')).toBe('DUMP-CONTENTS-1234');
  });

  it('rejects with the captured stderr when the child exits non-zero', async () => {
    const out = path.join(dir, 'b.dump');
    await expect(
      runPgDump('ignored://url', out, {
        command: process.execPath,
        buildArgs: () => ['-e', 'process.stderr.write("kaboom"); process.exit(3)'],
      }),
    ).rejects.toThrow(/exited 3.*kaboom/s);
  });

  it('rejects when the command cannot be spawned', async () => {
    const out = path.join(dir, 'c.dump');
    await expect(
      runPgDump('ignored://url', out, {
        command: '/nonexistent/definitely-not-a-real-binary-xyz',
        buildArgs: () => [],
      }),
    ).rejects.toBeTruthy();
  });
});
