// Robust pg.Client cleanup for SSE-routes that hold a long-running LISTEN-
// connection. Without this helper, `pgClient.end()` can hang silently when
// the underlying socket is in a weird state (Fast Refresh, abrupt browser
// close, Vercel function recycle), leaving the connection in 'idle' on the
// Postgres server. After ~10-20 reconnects the Neon connection-pool fills
// up and new SSE-connections fail with ERR_INCOMPLETE_CHUNKED_ENCODING.
//
// Strategy: race `pgClient.end()` against a short timeout; if the timeout
// wins, force-destroy the underlying socket so the OS releases the FD and
// Neon notices the disconnect.

import type { Client } from 'pg'

const END_TIMEOUT_MS = 2_000

interface PgClientWithStream {
  connection?: { stream?: { destroy?: (err?: Error) => void } }
}

export async function closePgClientSafely(
  client: Client,
  label: string,
): Promise<void> {
  // Drop notification/error handlers so a late event from the dying
  // connection cannot trigger downstream cleanup again.
  client.removeAllListeners('notification')
  client.removeAllListeners('error')
  client.on('error', () => {
    // Swallow: connection is being torn down on purpose.
  })

  let timer: ReturnType<typeof setTimeout> | null = null
  const timeout = new Promise<'timeout'>((resolve) => {
    timer = setTimeout(() => resolve('timeout'), END_TIMEOUT_MS)
  })

  const result = await Promise.race([
    client.end().then(() => 'ended' as const),
    timeout,
  ]).catch(() => 'error' as const)

  if (timer) clearTimeout(timer)

  if (result !== 'ended') {
    if (process.env.NODE_ENV !== 'production') {
      console.warn(`[${label}] pgClient.end() did not finish in ${END_TIMEOUT_MS}ms — forcing socket destroy`)
    }
    const stream = (client as unknown as PgClientWithStream).connection?.stream
    try {
      stream?.destroy?.(new Error(`forced socket destroy from ${label}`))
    } catch {
      // best-effort
    }
  }
}
