import { DynamicModule, OnModuleInit, OnModuleDestroy } from '@nestjs/common';
import { ModuleRef } from '@nestjs/core';
import { DrizzleClient } from '../../types/drizzle.js';
import { JobsDomainModuleOptions } from './jobs-domain.module.js';
import { I as IJobOrchestrator } from '../../../job-orchestrator.protocol-DubMVbm9.js';
import { IJobRunService } from './job-run-service.protocol.js';
import { IJobStepService } from './job-step-service.protocol.js';
import { JobWorkerOptions, JobWorker } from './job-worker.js';
import { BullMqConnectionOptions, BullMqResolvedConfig } from './bullmq.config.js';
import 'drizzle-orm/node-postgres';
import '../events/event-bus.protocol.js';
import './job-orchestration.schema.js';
import 'drizzle-orm/pg-core';
import 'drizzle-orm';
import '../events/event-registry.js';
import './pool-config.loader.js';

/**
 * JobWorkerModule — `DynamicModule.forRoot({ mode, pools? })` factory that
 * boots one `JobWorker` per active pool and runs the boot-time validator
 * (Drizzle only) (ADR-022, JOB-5).
 *
 * Imports `JobsDomainModule` internally so call sites only need to add
 * `JobWorkerModule.forRoot(...)` to `AppModule.imports` — the protocol
 * tokens become available transitively via `global: true`.
 *
 * Lifecycle (`onModuleInit`, **order-critical** per JOB-5 spec):
 *   1. `loadPoolConfig()`                        → resolved `PoolConfig`
 *   2. `HandlerRegistry.getAll()`                → registered entries
 *   3. Reserved-pool validation                  → throws `ReservedPoolViolationError`
 *   4. `orchestrator.upsertJobRows(entries, …)`  → persist `job` definitions
 *   5. Boot validator (Drizzle only)             → throws `BootValidationError`
 *      (skipped entirely in memory mode — Q4 resolution 2026-04-19)
 *   6. Spawn one `JobWorker` per active pool     → start polling loops
 *
 * `onModuleDestroy` calls `gracefulStop` on each worker (drains in-flight,
 * resets `running` rows, removes SIGTERM handler).
 */

interface JobWorkerModuleOptions {
    mode: 'embedded' | 'standalone';
    /**
     * Threads into the internal `JobsDomainModule.forRoot({ backend })`
     * import. Default `'drizzle'`. The boot-time validator runs for both
     * `'drizzle'` and `'bullmq'` (both persist `job` rows to Postgres);
     * `'memory'` skips it.
     */
    backend?: 'drizzle' | 'memory' | 'bullmq';
    /**
     * Active pool names. Defaults to every non-reserved pool in the resolved
     * config (i.e. `interactive`, `batch`, plus any user-defined pools).
     * Operators reduce this to one or two pools per worker process to scale
     * horizontally.
     */
    pools?: string[];
    /**
     * BULLMQ-1 Phase 1 — when `true`, `onModuleInit` activates **every** pool
     * in the resolved config, including the reserved `events_*` lanes. This is
     * how the standalone worker (`worker.ts`) drains bridge wrappers without
     * the consumer hand-listing `...BRIDGE_RESERVED_POOLS`. Mutually exclusive
     * with an explicit `pools` list — when both are set, `pools` wins (explicit
     * beats blanket) and `allPools` is ignored.
     *
     * `BridgeModule`'s reserved-pool guard short-circuits to "pass" when this
     * is `true`, since every reserved pool is provably being polled.
     */
    allPools?: boolean;
    /** SIGTERM drain budget. Default 30_000 ms. */
    shutdownTimeoutMs?: number;
    /**
     * Test-only — point the pool config loader at a specific YAML file.
     * Production code reads `${process.cwd()}/codegen.config.yaml`.
     */
    configPath?: string;
    /**
     * Forwarded into the inner `JobsDomainModule.forRoot()` call so the
     * worker module's caller can configure backend extensions in one place.
     */
    domainModuleExtensions?: JobsDomainModuleOptions['extensions'];
    /** Forwarded into `JobsDomainModule.forRoot()`. JOB-8 wires this. */
    multiTenant?: boolean;
    /**
     * Test-only escape hatch — when set, the module uses this factory
     * instead of `new JobWorker(...)` so unit tests can stub the worker
     * without spinning up the polling loop.
     */
    workerFactory?: (options: JobWorkerOptions) => Pick<JobWorker, 'onModuleInit' | 'onModuleDestroy'>;
}
/**
 * DI token for the resolved `JobWorkerModuleOptions`. Exported so other
 * subsystems can inject it `@Optional()` and inspect the active
 * configuration — e.g. `BridgeModule.onModuleInit` checks
 * `options.pools` against `BRIDGE_RESERVED_POOLS` to fail fast when a
 * reserved pool isn't being polled (BRIDGE-8).
 *
 * ADR-037: namespaced `Symbol.for(...)` (via `tokenKey()`) — matches by value
 * across runtime copies.
 */
declare const JOB_WORKER_MODULE_OPTIONS: unique symbol;
/**
 * The lifecycle holder. Named `JobWorkerOrchestrator` in the spec to avoid
 * collision with `JobWorker` and `IJobOrchestrator`. Registered as a
 * provider on `JobWorkerModule`; Nest invokes `onModuleInit` /
 * `onModuleDestroy` automatically.
 */
declare class JobWorkerOrchestrator implements OnModuleInit, OnModuleDestroy {
    private readonly orchestrator;
    private readonly runService;
    private readonly stepService;
    private readonly options;
    /**
     * Drizzle client is only required when `backend === 'drizzle'`. Made
     * `@Optional()` so memory-mode boots in `Test.createTestingModule`
     * without supplying a `DRIZZLE` provider.
     */
    private readonly db;
    /**
     * ADR-037 (package-mode DI): inject `ModuleRef` EXPLICITLY via `@Inject`
     * rather than relying on `design:paramtypes` reflection. The published
     * package bundle is built without `emitDecoratorMetadata` (tsup/esbuild
     * default), so a by-type injection here would resolve to `undefined` at
     * boot in package mode — breaking the worker entirely (the
     * `ModuleRef not available` throw). Vendored mode happened to work only
     * because the consumer's own `tsc` (emitDecoratorMetadata: true)
     * recompiled the source and emitted the metadata. The explicit token is
     * mode-agnostic. `ModuleRef` is always provided by `@nestjs/core`, so no
     * `@Optional()` is needed (it's a hard dependency of the worker path).
     */
    private readonly moduleRef?;
    /**
     * BULLMQ-1 — resolved BullMQ connection + config, only bound when the
     * inner `JobsDomainModule` was booted with `backend: 'bullmq'`. `@Optional()`
     * so drizzle/memory boots see `null`.
     */
    private readonly bullConnection;
    private readonly bullConfig;
    private readonly logger;
    private readonly workers;
    constructor(orchestrator: IJobOrchestrator, runService: IJobRunService, stepService: IJobStepService, options: JobWorkerModuleOptions, 
    /**
     * Drizzle client is only required when `backend === 'drizzle'`. Made
     * `@Optional()` so memory-mode boots in `Test.createTestingModule`
     * without supplying a `DRIZZLE` provider.
     */
    db?: DrizzleClient | null, 
    /**
     * ADR-037 (package-mode DI): inject `ModuleRef` EXPLICITLY via `@Inject`
     * rather than relying on `design:paramtypes` reflection. The published
     * package bundle is built without `emitDecoratorMetadata` (tsup/esbuild
     * default), so a by-type injection here would resolve to `undefined` at
     * boot in package mode — breaking the worker entirely (the
     * `ModuleRef not available` throw). Vendored mode happened to work only
     * because the consumer's own `tsc` (emitDecoratorMetadata: true)
     * recompiled the source and emitted the metadata. The explicit token is
     * mode-agnostic. `ModuleRef` is always provided by `@nestjs/core`, so no
     * `@Optional()` is needed (it's a hard dependency of the worker path).
     */
    moduleRef?: ModuleRef | undefined, 
    /**
     * BULLMQ-1 — resolved BullMQ connection + config, only bound when the
     * inner `JobsDomainModule` was booted with `backend: 'bullmq'`. `@Optional()`
     * so drizzle/memory boots see `null`.
     */
    bullConnection?: BullMqConnectionOptions | null, bullConfig?: BullMqResolvedConfig | null);
    onModuleInit(): Promise<void>;
    onModuleDestroy(): Promise<void>;
    /**
     * Walk every registered handler; collect any whose declared `pool`
     * targets a reserved pool from the resolved config. If non-empty,
     * throw `ReservedPoolViolationError` with the offender list so the
     * operator sees every violating class on a single boot.
     */
    private assertNoReservedPoolHandlers;
    /**
     * Production worker spawn. `JobWorker` requires `DRIZZLE` so this only
     * succeeds when the module was booted with `backend: 'drizzle'`. Memory
     * mode tests must supply `workerFactory` — the memory backend has no
     * polling loop equivalent (`MemoryJobOrchestrator` is direct-invocation
     * only).
     *
     * We instantiate outside the Nest container because the module spawns
     * N workers from a single options shape, which doesn't fit Nest's
     * "one provider per token" model. The dependencies are passed
     * positionally; the constructor's `@Inject` decorators are unused on
     * this path (Nest still uses them when `JobWorker` is a provider — e.g.
     * in JOB-6's standalone `worker.ts` entrypoint).
     */
    private spawnWorker;
    /**
     * BULLMQ-1 — spawn a per-pool `BullMQJobWorker`. Requires the Drizzle
     * client (the worker drives `job_run` as the source of truth) AND the
     * resolved BullMQ connection (bound by `JobsDomainModule` when
     * `backend: 'bullmq'`). The queue name is derived identically to the
     * orchestrator's `dispatch` via `resolvePoolQueueName(pool, …)` so producer
     * and consumer agree.
     */
    /**
     * #6 — async + dynamic-import. The `job-worker.bullmq-backend.ts` file is
     * filtered out of the vendor set for drizzle/memory installs (no `bullmq`
     * peer dep needed). The non-literal import specifier makes TS treat the
     * module as `any` so the consumer's tsc never tries to resolve an absent
     * file. This method is only entered when `backend === 'bullmq'` — at which
     * point the file IS vendored.
     */
    private spawnBullMQWorker;
}
declare class JobWorkerModule {
    static forRoot(opts: JobWorkerModuleOptions): DynamicModule;
}

export { JOB_WORKER_MODULE_OPTIONS, JobWorkerModule, type JobWorkerModuleOptions, JobWorkerOrchestrator };
