/**
 * Unified Worker Entry Point
 *
 * This module serves as a single entry point for all worker types in Repomix.
 * It enables full bundling support by allowing the bundled file to spawn workers
 * using itself (import.meta.url), eliminating path resolution issues.
 *
 * When running as a worker, it dynamically imports the appropriate worker handler
 * based on the workerType specified in workerData.
 */

import { workerData } from 'node:worker_threads';

// Worker type definitions
export type WorkerType = 'fileProcess' | 'securityCheck' | 'calculateMetrics';

// Worker handler type - uses 'any' to accommodate different worker signatures
// biome-ignore lint/suspicious/noExplicitAny: Worker handlers have varying signatures
type WorkerHandler = (task: any) => Promise<any>;
type WorkerCleanup = () => void | Promise<void>;

// Cache loaded handlers by worker type
const handlerCache = new Map<WorkerType, { handler: WorkerHandler; cleanup?: WorkerCleanup }>();

/**
 * Dynamically load the appropriate worker handler based on workerType.
 * Uses dynamic imports to avoid loading all worker code when not needed.
 * Results are cached for reuse.
 */
const loadWorkerHandler = async (
  workerType: WorkerType,
): Promise<{ handler: WorkerHandler; cleanup?: WorkerCleanup }> => {
  // Check cache first
  const cached = handlerCache.get(workerType);
  if (cached) {
    return cached;
  }

  let result: { handler: WorkerHandler; cleanup?: WorkerCleanup };

  switch (workerType) {
    case 'fileProcess': {
      const module = await import('../core/file/workers/fileProcessWorker.js');
      result = { handler: module.default as WorkerHandler, cleanup: module.onWorkerTermination };
      break;
    }
    case 'securityCheck': {
      const module = await import('../core/security/workers/securityCheckWorker.js');
      result = { handler: module.default as WorkerHandler, cleanup: module.onWorkerTermination };
      break;
    }
    case 'calculateMetrics': {
      const module = await import('../core/metrics/workers/calculateMetricsWorker.js');
      result = { handler: module.default as WorkerHandler, cleanup: module.onWorkerTermination };
      break;
    }
    default:
      throw new Error(`Unknown worker type: ${workerType}`);
  }

  // Cache the result
  handlerCache.set(workerType, result);
  return result;
};

/**
 * Infer worker type from task structure.
 * This is used in bundled environments where Tinypool may reuse child processes
 * across different worker pools.
 */
const inferWorkerTypeFromTask = (task: unknown): WorkerType | null => {
  if (!task || typeof task !== 'object') {
    return null;
  }

  const taskObj = task as Record<string, unknown>;

  // fileProcess: has rawFile (nested object) and config
  if ('rawFile' in taskObj && 'config' in taskObj) {
    return 'fileProcess';
  }

  // calculateMetrics: single mode has content+encoding, batch mode has items+encoding
  if ('encoding' in taskObj && ('content' in taskObj || 'items' in taskObj)) {
    return 'calculateMetrics';
  }

  // securityCheck: has items array without encoding (distinguishes from batch calculateMetrics)
  if ('items' in taskObj && !('encoding' in taskObj)) {
    return 'securityCheck';
  }

  return null;
};

/**
 * Get workerType from workerData.
 * In Tinypool child_process mode, workerData is an array.
 */
const getWorkerTypeFromWorkerData = (): WorkerType | undefined => {
  if (!workerData) {
    return undefined;
  }

  // Handle array format (Tinypool child_process mode)
  if (Array.isArray(workerData)) {
    for (const item of workerData) {
      if (item && typeof item === 'object' && 'workerType' in item) {
        return item.workerType as WorkerType;
      }
    }
    return undefined;
  }

  // Handle object format (worker_threads mode)
  if (typeof workerData === 'object' && 'workerType' in workerData) {
    return (workerData as { workerType?: WorkerType }).workerType;
  }

  return undefined;
};

/**
 * Default export for Tinypool.
 * This function is called for each task and delegates to the appropriate handler.
 *
 * In bundled environments where Tinypool may reuse child processes across different
 * worker pools, we use task-based inference to determine the correct handler.
 */
export default async (task: unknown): Promise<unknown> => {
  // Determine worker type: try workerData/env first, then infer from task
  let workerType: WorkerType | undefined =
    getWorkerTypeFromWorkerData() ?? (process.env.REPOMIX_WORKER_TYPE as WorkerType | undefined);

  // In bundled environments, Tinypool may reuse child processes.
  // If the task doesn't match the initially configured worker type, infer from task.
  const inferredType = inferWorkerTypeFromTask(task);

  // Use inferred type if available (more reliable in bundled env)
  if (inferredType) {
    workerType = inferredType;
  }

  if (!workerType) {
    throw new Error('Cannot determine worker type from workerData, env, or task structure');
  }

  // Load handler (cached)
  const { handler } = await loadWorkerHandler(workerType);
  return handler(task);
};

/**
 * Cleanup function for Tinypool teardown.
 * Cleans up all cached handlers.
 */
export const onWorkerTermination = async (): Promise<void> => {
  for (const { cleanup } of handlerCache.values()) {
    if (cleanup) {
      await cleanup();
    }
  }
  handlerCache.clear();
};
