/**
 * T2 — Postgres pool + typed `query` wrapper. PARAMETERIZED ONLY: the wrapper accepts
 * `(sql, params)` and passes params to the driver separately — there is NO string-interpolation
 * path, so SQL injection via value concatenation is structurally impossible (INV5-adjacent, §7).
 *
 * The client is injected (`Queryable`) so the wrapper is unit-testable without a live DB; the real
 * `pg.Pool` is constructed by `createPgPool`. Applying the migrations + mapping the repository ports
 * to SQL over this wrapper is the Testcontainers integration seam (PLAN §10).
 */
import pg from 'pg'

/** Minimal driver surface the wrapper needs — satisfied by `pg.Pool` and `pg.PoolClient`. */
export interface Queryable {
  query(text: string, params: readonly unknown[]): Promise<{ rows: unknown[] }>
}

export type QueryFn = <T>(sql: string, params: readonly unknown[]) => Promise<readonly T[]>

/** Build a parameterized-only query function over any `Queryable`. */
export function createQuery(client: Queryable): QueryFn {
  return async <T>(sql: string, params: readonly unknown[]): Promise<readonly T[]> => {
    // Params ALWAYS travel separately from the SQL text — never interpolated into it.
    const result = await client.query(sql, params)
    return result.rows as T[]
  }
}

/** Construct a real Postgres connection pool (production). */
export function createPgPool(connectionString: string): pg.Pool & Queryable {
  return new pg.Pool({ connectionString })
}
