import { DrizzleClient } from '../../types/drizzle.js';
import { DrizzleTransaction } from '../events/event-bus.protocol.js';
import 'drizzle-orm/node-postgres';

/** Channel the jobs worker LISTENs on; payload = pool name. */
declare const JOBS_WAKE_CHANNEL = "codegen_jobs_wake";
/** Channel the events drainer LISTENs on; payload = event pool (or ''). */
declare const EVENTS_WAKE_CHANNEL = "codegen_events_wake";
/**
 * Emit an in-transaction `pg_notify`. Call with the SAME `tx`/client handle as
 * the row write being announced so delivery is gated on commit. `payload` is a
 * short plain string (a pool name); it is NOT JSON — the wake is a hint and the
 * subsequent claim/drain query is authoritative. Channel names are framework
 * constants (never user input), so the `set_config`-free literal-channel form is
 * safe; the payload is bound as a parameter.
 */
declare function pgNotify(tx: DrizzleClient | DrizzleTransaction, channel: string, payload: string): Promise<void>;
/** Minimal structural view of the `pg` Client/PoolClient surface we touch. */
interface PgListenClient {
    query(text: string): Promise<unknown>;
    on(event: 'notification', cb: (msg: {
        channel: string;
        payload?: string;
    }) => void): void;
    on(event: 'error', cb: (err: Error) => void): void;
    removeAllListeners?: (event?: string) => void;
    release?: (err?: boolean) => void;
    end?: () => Promise<void>;
}
/** Minimal structural view of the `pg` Pool's `connect()`. */
interface PgPoolish {
    connect(): Promise<PgListenClient>;
}
interface PgNotifyListenerOptions {
    /** Channel to LISTEN on. */
    channel: string;
    /**
     * The underlying `pg.Pool` — obtained from `drizzleClient.$client`. A
     * dedicated `PoolClient` is checked out and held for the listener's lifetime
     * (separate from the query pool so a slow query never delays a wake).
     */
    pool: PgPoolish;
    /**
     * Called for every notification on `channel`, with the raw payload string
     * (`''` when Postgres delivers an empty payload). The owner decides whether
     * the payload is relevant (e.g. "is this one of my pools?") and debounces its
     * own claim cycle.
     */
    onNotify: (payload: string) => void;
    /** Label used in log lines (e.g. 'jobs:interactive', 'events'). */
    label: string;
    backoffMinMs?: number;
    backoffMaxMs?: number;
}
/**
 * Holds a dedicated listener connection and forwards notifications to `onNotify`.
 * Reconnects with capped exponential backoff on drop; logs the first failure +
 * the recovery exactly once each so a flapping connection doesn't flood logs.
 */
declare class PgNotifyListener {
    private readonly opts;
    private readonly logger;
    private client;
    private stopped;
    private reconnectTimer;
    private backoffMs;
    private readonly backoffMinMs;
    private readonly backoffMaxMs;
    /** WARN-once gate so a flapping listener doesn't spam the log. */
    private warnedDown;
    constructor(opts: PgNotifyListenerOptions);
    /** Begin listening. Idempotent-ish: a second call while connected is a no-op. */
    start(): Promise<void>;
    /** Stop listening + release the connection. Safe to call repeatedly. */
    stop(): Promise<void>;
    private connect;
    /** Connection dropped after being established → reconnect. */
    private handleDrop;
    /** Initial / reconnect `connect()` threw. */
    private handleConnectFailure;
    private scheduleReconnect;
    private releaseClient;
}

export { EVENTS_WAKE_CHANNEL, JOBS_WAKE_CHANNEL, PgNotifyListener, type PgNotifyListenerOptions, pgNotify };
