/**
 * E2E test pinning the PostgresEngine.disconnect() idempotency invariant.
 *
 * Background: when commit 671ef099 added engine.disconnect() to
 * MinionWorker.start()'s finally block, every test that calls worker.start()
 * AND then engine.disconnect() in its own finally was double-disconnecting
 * the same engine instance. Pre-fix, the second disconnect found _sql=null
 * and fell through to the `else` branch which calls db.disconnect() — but
 * db.disconnect() clears the GLOBAL module-level connection, breaking
 * unrelated downstream tests (their getConn() throws "no database
 * connection" on the next beforeEach).
 *
 * The fix: PostgresEngine tracks `_connectionStyle` ('instance' | 'module')
 * and only calls db.disconnect() when it actually owns the module-level
 * connection. Second disconnect on an instance-pool engine is a no-op.
 *
 * This test pins the contract so future refactors of disconnect() can't
 * silently regress (it's exactly the bug class that took an hour of E2E
 * debugging to find). Two cases:
 *   1. instance-pool engine: connect → disconnect → disconnect must NOT
 *      affect the module-level connection.
 *   2. module-singleton engine: connect → disconnect → disconnect is safe
 *      (second call no-ops).
 */

import { describe, test, expect, beforeAll, afterAll } from 'bun:test';
import { PostgresEngine } from '../../src/core/postgres-engine.ts';
import * as db from '../../src/core/db.ts';

const DATABASE_URL = process.env.DATABASE_URL;
const skip = !DATABASE_URL;

if (skip) {
  // eslint-disable-next-line no-console
  console.log('Skipping postgres-engine-disconnect-idempotency E2E (DATABASE_URL not set)');
}

describe.skipIf(skip)('PostgresEngine.disconnect idempotency', () => {
  beforeAll(async () => {
    // Establish the module-level connection so we can verify it survives
    // the instance-pool engine's double-disconnect.
    await db.disconnect();
    await db.connect({ database_url: DATABASE_URL! });
  }, 30_000);

  afterAll(async () => {
    await db.disconnect();
  });

  test('instance-pool engine: second disconnect() does NOT clobber module singleton', async () => {
    const engine = new PostgresEngine();
    await engine.connect({ database_url: DATABASE_URL!, poolSize: 2 });

    // First disconnect — closes the engine's own pool.
    await engine.disconnect();

    // Sanity: module-level connection still alive (this is what
    // helpers.ts's getConn() returns).
    const before = await db.getConnection().unsafe('SELECT 1 as ok');
    expect((before[0] as unknown as { ok: number }).ok).toBe(1);

    // Second disconnect — pre-fix, this fell through to db.disconnect()
    // and cleared the module-level singleton. Post-fix, it's a no-op.
    await engine.disconnect();

    // Module-level connection MUST still be alive.
    const after = await db.getConnection().unsafe('SELECT 1 as ok');
    expect((after[0] as unknown as { ok: number }).ok).toBe(1);
  });

  test('module-singleton engine: second disconnect() is a no-op', async () => {
    // Re-establish module-level connection (idempotent; no-op if still
    // connected from beforeAll).
    await db.connect({ database_url: DATABASE_URL! });

    const engine = new PostgresEngine();
    // No poolSize → uses the module-level singleton.
    await engine.connect({ database_url: DATABASE_URL! });

    // First disconnect closes module-level singleton (this engine owned it).
    await engine.disconnect();

    // Second disconnect must NOT throw — should be a no-op since
    // _connectionStyle was reset to null.
    await expect(engine.disconnect()).resolves.toBeUndefined();
  });
});
