import { fork, type ChildProcess } from 'node:child_process';
import { fileURLToPath } from 'node:url';
import type { CachedResult } from '@wordle/shared';

interface SolverTask {
  target: string;
  allWords: string[];
  mode: 'fast' | 'full';
}

interface WorkerMessage {
  ok: boolean;
  value?: CachedResult;
  error?: string;
}

const workerPath = fileURLToPath(new URL('./solver-worker.ts', import.meta.url));

/**
 * Run solver computation in a forked child process so long-running entropy
 * calculations never block the main event loop.
 *
 * Uses child_process.fork() rather than worker_threads because the solver
 * modules are TypeScript and need tsx's --import hook — which fork() can
 * inject via execArgv while worker_threads cannot.
 *
 * Spawns a short-lived child per call; ~100 ms overhead is negligible
 * compared to the 14 s entropy run.
 */
export function runSolverInWorker(task: SolverTask): Promise<CachedResult> {
  return new Promise((resolve, reject) => {
    let child: ChildProcess | null = null;

    const done = (err: Error | null, result?: CachedResult) => {
      if (child) { child.kill(); child = null; }
      if (err) reject(err);
      else resolve(result!);
    };

    child = fork(workerPath, [], {
      execArgv: ['--import', 'tsx'],
      stdio: 'pipe',
    });

    child.on('message', (msg: WorkerMessage) => {
      if (msg.ok) done(null, msg.value);
      else done(new Error(msg.error ?? 'unknown worker error'));
    });

    child.on('error', (err) => done(err));
    child.on('exit', (code, signal) => {
      if (child) done(new Error(`Worker exited code=${code} signal=${signal}`));
    });

    child.send(task);
  });
}
