import * as drizzle_orm_pg_core from 'drizzle-orm/pg-core';
import { OnModuleInit, OnModuleDestroy } from '@nestjs/common';
import { ModuleRef } from '@nestjs/core';
import { DrizzleClient } from '../../types/drizzle.js';
import { JobRunRow } from './job-orchestration.schema.js';
import { I as IJobOrchestrator, R as RetryPolicy } from '../../../job-orchestrator.protocol-ZuJ3ow-O.js';
import { IJobRunService } from './job-run-service.protocol.js';
import { IJobStepService } from './job-step-service.protocol.js';
import 'drizzle-orm/node-postgres';
import 'drizzle-orm';
import '../events/event-bus.protocol.js';
import '../events/event-registry.js';

/**
 * Options accepted by `JobWorker`. JOB-5 threads these through module
 * `.forRoot()` config; supplied here as a plain DI-constructor argument
 * so the worker compiles standalone.
 */
interface JobWorkerOptions {
    /** Pool name this worker claims from. Matches `job.pool`. */
    pool: string;
    /** Max concurrent in-flight `processRun` calls. */
    concurrency: number;
    /** Poll interval in ms. Default 1000. */
    pollIntervalMs?: number;
    /** Stale sweep interval in ms. Default 60_000. */
    staleSweeperIntervalMs?: number;
    /**
     * Threshold beyond which a `running` row is presumed stranded by a
     * crashed worker. Default 5 min. Must be >= 2× max handler duration.
     */
    staleThresholdMs?: number;
    /** Max ms to wait for in-flight drain on SIGTERM. Default 30_000. */
    shutdownTimeoutMs?: number;
    /**
     * LISTEN-NOTIFY-1 — when true, hold a dedicated listener connection and
     * LISTEN on `codegen_jobs_wake`. A notification naming this worker's `pool`
     * triggers an immediate (debounced) claim cycle, so an enqueue is claimed in
     * milliseconds instead of waiting for the next `pollIntervalMs` tick. Polling
     * continues unchanged as the fallback heartbeat. Default false.
     */
    listenNotify?: boolean;
}
declare const JOB_WORKER_OPTIONS: unique symbol;
declare const TERMINAL_STATUSES: JobRunRow['status'][];
/**
 * Backoff delay in ms for the Nth attempt (1-indexed). Supports both
 * policy modes. Exponential is capped at `Number.MAX_SAFE_INTEGER` so
 * pathological attempt counts don't overflow.
 */
declare function computeBackoff(policy: RetryPolicy, attempts: number): number;
/**
 * Decide whether an error should be retried under the given policy.
 * Matches `nonRetryableErrors` by `.name` OR `.code`. Returns
 *   - `'retry'` if attempts remain and the error isn't blacklisted,
 *   - `'fail'` otherwise (terminal failure).
 */
declare function classifyError(err: unknown, policy: RetryPolicy | undefined, currentAttempts: number): 'retry' | 'fail';
/**
 * Build the raw claim-candidate select. Exported so tests can inspect
 * `.toSQL()` without spinning up the full worker. Matches JOB-3 §4 and
 * ADR-022 "Claim query (Drizzle backend)".
 */
declare function buildClaimQuery(db: DrizzleClient, pool: string): Omit<drizzle_orm_pg_core.PgSelectBase<"job_run", {
    id: drizzle_orm_pg_core.PgColumn<{
        name: "id";
        tableName: "job_run";
        dataType: "string";
        columnType: "PgUUID";
        data: string;
        driverParam: string;
        notNull: true;
        hasDefault: true;
        isPrimaryKey: true;
        isAutoincrement: false;
        hasRuntimeDefault: false;
        enumValues: undefined;
        baseColumn: never;
        identity: undefined;
        generated: undefined;
    }, {}, {}>;
}, "partial", Record<"job_run", "not-null">, false, "where" | "orderBy" | "limit" | "for", {
    id: string;
}[], {
    id: drizzle_orm_pg_core.PgColumn<{
        name: "id";
        tableName: "job_run";
        dataType: "string";
        columnType: "PgUUID";
        data: string;
        driverParam: string;
        notNull: true;
        hasDefault: true;
        isPrimaryKey: true;
        isAutoincrement: false;
        hasRuntimeDefault: false;
        enumValues: undefined;
        baseColumn: never;
        identity: undefined;
        generated: undefined;
    }, {}, {}>;
}>, "where" | "orderBy" | "limit" | "for">;
/**
 * Build the stale-claim sweep candidate select. `FOR UPDATE SKIP LOCKED`
 * per OQ-2 resolution (2026-04-19): per-worker sweeper, safe without
 * leader election because the update is self-gating.
 */
declare function buildStaleSweepQuery(db: DrizzleClient, staleThresholdMs: number): Omit<drizzle_orm_pg_core.PgSelectBase<"job_run", {
    id: drizzle_orm_pg_core.PgColumn<{
        name: "id";
        tableName: "job_run";
        dataType: "string";
        columnType: "PgUUID";
        data: string;
        driverParam: string;
        notNull: true;
        hasDefault: true;
        isPrimaryKey: true;
        isAutoincrement: false;
        hasRuntimeDefault: false;
        enumValues: undefined;
        baseColumn: never;
        identity: undefined;
        generated: undefined;
    }, {}, {}>;
}, "partial", Record<"job_run", "not-null">, false, "where" | "for", {
    id: string;
}[], {
    id: drizzle_orm_pg_core.PgColumn<{
        name: "id";
        tableName: "job_run";
        dataType: "string";
        columnType: "PgUUID";
        data: string;
        driverParam: string;
        notNull: true;
        hasDefault: true;
        isPrimaryKey: true;
        isAutoincrement: false;
        hasRuntimeDefault: false;
        enumValues: undefined;
        baseColumn: never;
        identity: undefined;
        generated: undefined;
    }, {}, {}>;
}>, "where" | "for">;
declare class JobWorker implements OnModuleInit, OnModuleDestroy {
    private readonly db;
    private readonly orchestrator;
    private readonly runService;
    private readonly stepService;
    private readonly options;
    private readonly moduleRef;
    private readonly logger;
    private shuttingDown;
    private readonly inFlight;
    private pollTimer;
    private sweeperTimer;
    private sigtermHandled;
    private readonly sigtermHandler;
    private readonly pollIntervalMs;
    private readonly staleSweeperIntervalMs;
    private readonly staleThresholdMs;
    private readonly shutdownTimeoutMs;
    private readonly listenNotifyEnabled;
    private notifyListener;
    /** True while a wake-driven claim cycle is in flight (debounce gate). */
    private wakeDraining;
    /** A notify arrived mid-cycle → re-check once when the cycle ends. */
    private wakeRecheckPending;
    constructor(db: DrizzleClient, orchestrator: IJobOrchestrator, runService: IJobRunService, stepService: IJobStepService, options: JobWorkerOptions, moduleRef: ModuleRef);
    onModuleInit(): void;
    /**
     * Wake handler — a `codegen_jobs_wake` notification arrived. Only payloads
     * naming THIS worker's pool are relevant (other pools have their own workers).
     * Debounced: if a claim cycle is already running we just flag a re-check so a
     * burst of N enqueues collapses to at most one extra cycle (D3).
     */
    private onWake;
    /**
     * Claim-until-empty on a wake. Unlike the interval `pollAndProcess` (one
     * claim per tick), a wake drains greedily up to the concurrency ceiling so a
     * burst that arrived together is dispatched without waiting for N ticks. The
     * `wakeRecheckPending` flag coalesces notifies that land mid-drain.
     */
    private drainOnWake;
    onModuleDestroy(): Promise<void>;
    private drainInFlight;
    pollAndProcess(): Promise<void>;
    /**
     * Claim the next runnable row from the pool. Transaction ensures the
     * select-candidate + update-to-running pair is atomic; FOR UPDATE SKIP
     * LOCKED lets multiple workers share the table without serialising.
     */
    claimNext(pool: string): Promise<JobRunRow | null>;
    /**
     * Release rows whose `claimed_at` is older than the threshold. Safe to
     * run concurrently across workers — the two-phase tx (select-for-update
     * then update) guarantees each stranded row is only reset once.
     */
    sweepStaleClaims(): Promise<void>;
    private processRun;
    private markFailed;
    private makeStepFn;
    private makeSpawnFn;
    /**
     * Allocate the next `seq` for a given run. SELECT-max approach — runs
     * typically have <100 steps so the scan is cheap, and correctness across
     * retries is more important than the microseconds saved by an in-memory
     * counter (which would drift if the worker crashes mid-run and another
     * worker resumes via stale-claim sweep).
     */
    private nextStepSeq;
}

export { JOB_WORKER_OPTIONS, JobWorker, type JobWorkerOptions, TERMINAL_STATUSES, buildClaimQuery, buildStaleSweepQuery, classifyError, computeBackoff };
