import {
  JobWorker
} from "./chunk-FWRL7BZ5.js";
import {
  JobsDomainModule
} from "./chunk-HOIRY5XP.js";
import {
  BootValidationError,
  ReservedPoolViolationError
} from "./chunk-T4BIIU5E.js";
import {
  BULLMQ_CONNECTION,
  BULLMQ_RESOLVED_CONFIG,
  resolvePoolQueueName
} from "./chunk-I6MVCB5A.js";
import {
  allNonReservedPoolNames,
  allPoolNames,
  loadPoolConfig
} from "./chunk-RHVN6NA7.js";
import {
  JOB_ORCHESTRATOR,
  JOB_RUN_SERVICE,
  JOB_STEP_SERVICE
} from "./chunk-ZPL74UQN.js";
import {
  HandlerRegistry
} from "./chunk-7P5ODGLA.js";
import {
  tokenKey
} from "./chunk-GYGNEQSC.js";
import {
  DRIZZLE
} from "./chunk-U64T4YZE.js";
import {
  __decorateClass,
  __decorateParam
} from "./chunk-2E224ZSN.js";

// runtime/subsystems/jobs/job-worker.module.ts
import {
  Inject,
  Injectable,
  Logger,
  Module,
  Optional
} from "@nestjs/common";
import { ModuleRef } from "@nestjs/core";
var DEFAULT_SHUTDOWN_TIMEOUT_MS = 3e4;
var JOB_WORKER_MODULE_OPTIONS = Symbol.for(tokenKey("jobs", "worker-module-options"));
var JobWorkerOrchestrator = class {
  constructor(orchestrator, runService, stepService, options, db = null, moduleRef, bullConnection = null, bullConfig = null) {
    this.orchestrator = orchestrator;
    this.runService = runService;
    this.stepService = stepService;
    this.options = options;
    this.db = db;
    this.moduleRef = moduleRef;
    this.bullConnection = bullConnection;
    this.bullConfig = bullConfig;
  }
  orchestrator;
  runService;
  stepService;
  options;
  db;
  moduleRef;
  bullConnection;
  bullConfig;
  logger = new Logger(JobWorkerOrchestrator.name);
  workers = [];
  // ============================================================================
  // Lifecycle
  // ============================================================================
  async onModuleInit() {
    const backend = this.options.backend ?? "drizzle";
    const poolConfig = loadPoolConfig(this.options.configPath);
    const entries = HandlerRegistry.getAll();
    this.assertNoReservedPoolHandlers(entries, poolConfig);
    const { orphaned } = await this.orchestrator.upsertJobRows(
      entries,
      poolConfig
    );
    if (backend !== "memory" && orphaned.length > 0) {
      throw new BootValidationError(orphaned);
    }
    const activePools = this.options.pools ? this.options.pools : this.options.allPools ? allPoolNames(poolConfig) : allNonReservedPoolNames(poolConfig);
    for (const poolName of activePools) {
      const def = poolConfig.get(poolName);
      if (!def) {
        throw new Error(
          `JobWorkerModule: active pool '${poolName}' is not defined in the resolved pool config. Configured pools: [${[...poolConfig.keys()].join(", ")}].`
        );
      }
      const drizzleExt = backend === "drizzle" ? this.options.domainModuleExtensions?.drizzle : void 0;
      const workerOptions = {
        pool: poolName,
        concurrency: def.concurrency,
        shutdownTimeoutMs: this.options.shutdownTimeoutMs ?? DEFAULT_SHUTDOWN_TIMEOUT_MS,
        pollIntervalMs: drizzleExt?.pollIntervalMs,
        listenNotify: drizzleExt?.listenNotify
      };
      const worker = this.options.workerFactory ? this.options.workerFactory(workerOptions) : backend === "bullmq" ? await this.spawnBullMQWorker(poolName, def.queue, def.concurrency, poolConfig) : this.spawnWorker(workerOptions);
      await worker.onModuleInit();
      this.workers.push(worker);
      this.logger.log(
        `JobWorker started: pool='${poolName}' (queue='${def.queue}') concurrency=${def.concurrency} backend='${backend}'`
      );
    }
  }
  async onModuleDestroy() {
    for (let i = this.workers.length - 1; i >= 0; i--) {
      const worker = this.workers[i];
      if (!worker) continue;
      try {
        await worker.onModuleDestroy();
      } catch (err) {
        this.logger.error(
          `JobWorker shutdown failed: ${err.message}`
        );
      }
    }
    this.workers.length = 0;
    const orch = this.orchestrator;
    if (typeof orch.closeConnections === "function") {
      try {
        await orch.closeConnections();
      } catch (err) {
        this.logger.error(
          `BullMQ orchestrator connection close failed: ${err.message}`
        );
      }
    }
  }
  // ============================================================================
  // Internals
  // ============================================================================
  /**
   * 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.
   */
  assertNoReservedPoolHandlers(entries, poolConfig) {
    const offenders = [];
    for (const entry of entries) {
      if (entry.type.startsWith("@framework/")) continue;
      const declaredPool = entry.meta.pool ?? "batch";
      const def = poolConfig.get(declaredPool);
      if (def?.reserved) {
        offenders.push({
          handlerClass: entry.handlerClass.name,
          pool: declaredPool
        });
      }
    }
    if (offenders.length > 0) {
      throw new ReservedPoolViolationError(offenders);
    }
  }
  /**
   * 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).
   */
  spawnWorker(workerOptions) {
    if (!this.db) {
      throw new Error(
        `JobWorkerModule: in-process worker spawning requires the Drizzle backend (no DRIZZLE provider available). Memory-mode tests must pass 'workerFactory' to inject a stub.`
      );
    }
    if (!this.moduleRef) {
      throw new Error(
        `JobWorkerModule: ModuleRef not available \u2014 cannot construct JobWorker with handler DI support. Ensure the orchestrator is resolved through the Nest container (not instantiated manually in tests).`
      );
    }
    return new JobWorker(
      this.db,
      this.orchestrator,
      this.runService,
      this.stepService,
      workerOptions,
      this.moduleRef
    );
  }
  /**
   * 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.
   */
  async spawnBullMQWorker(pool, _queueAlias, concurrency, poolConfig) {
    if (!this.db) {
      throw new Error(
        `JobWorkerModule: BullMQ worker spawning requires the Drizzle client (no DRIZZLE provider available) \u2014 job_run remains the source of truth.`
      );
    }
    if (!this.bullConnection) {
      throw new Error(
        `JobWorkerModule: BullMQ worker spawning requires a resolved BULLMQ_CONNECTION. Ensure JobsDomainModule was booted with backend: 'bullmq'.`
      );
    }
    if (!this.moduleRef) {
      throw new Error(
        `JobWorkerModule: ModuleRef not available \u2014 cannot construct BullMQJobWorker with handler DI support.`
      );
    }
    const queueName = resolvePoolQueueName(pool, this.bullConfig, poolConfig);
    const specifier = "./job-worker.bullmq-backend";
    const mod = await import(specifier);
    return new mod.BullMQJobWorker(
      this.db,
      this.orchestrator,
      this.stepService,
      {
        pool,
        queueName,
        concurrency,
        connection: this.bullConnection
      },
      this.moduleRef
    );
  }
};
JobWorkerOrchestrator = __decorateClass([
  Injectable(),
  __decorateParam(0, Inject(JOB_ORCHESTRATOR)),
  __decorateParam(1, Inject(JOB_RUN_SERVICE)),
  __decorateParam(2, Inject(JOB_STEP_SERVICE)),
  __decorateParam(3, Inject(JOB_WORKER_MODULE_OPTIONS)),
  __decorateParam(4, Optional()),
  __decorateParam(4, Inject(DRIZZLE)),
  __decorateParam(5, Inject(ModuleRef)),
  __decorateParam(6, Optional()),
  __decorateParam(6, Inject(BULLMQ_CONNECTION)),
  __decorateParam(7, Optional()),
  __decorateParam(7, Inject(BULLMQ_RESOLVED_CONFIG))
], JobWorkerOrchestrator);
var JobWorkerModule = class {
  static forRoot(opts) {
    return {
      module: JobWorkerModule,
      imports: [
        JobsDomainModule.forRoot({
          backend: opts.backend ?? "drizzle",
          extensions: opts.domainModuleExtensions,
          multiTenant: opts.multiTenant
        })
      ],
      providers: [
        { provide: JOB_WORKER_MODULE_OPTIONS, useValue: opts },
        JobWorkerOrchestrator
      ],
      // BULLMQ-1 Phase 1 — export the options token so `BridgeModule`'s
      // reserved-pool guard (`onModuleInit`) can actually inject it.
      // Previously `exports: []` left the `@Optional()` inject resolving to
      // `undefined` and the guard silently no-opped (a dead check). With the
      // token exported the guard fires for real; consumers that omit the
      // reserved pools (and don't set `allPools`) now fail fast with
      // `BridgeReservedPoolsNotPolledError` — which is correct.
      exports: [JOB_WORKER_MODULE_OPTIONS]
    };
  }
};
JobWorkerModule = __decorateClass([
  Module({})
], JobWorkerModule);

export {
  JOB_WORKER_MODULE_OPTIONS,
  JobWorkerOrchestrator,
  JobWorkerModule
};
//# sourceMappingURL=chunk-HPS554L4.js.map