/**
 * Process Handler - Testable Exit Strategy
 *
 * Replaces direct process.exit() calls with a mockable handler.
 * Makes the codebase testable by allowing exit behavior to be intercepted.
 *
 * @module process-handler
 */

import chalk from 'chalk';

/**
 * Process Handler Class
 *
 * Provides testable process exit functionality.
 */
export class ProcessHandler {
  /**
   * @param {Function} exitFn - Exit function (defaults to process.exit)
   */
  constructor(exitFn = process.exit.bind(process)) {
    this.exitFn = exitFn;
  }

  /**
   * Exit the process with optional message
   *
   * @param {number} code - Exit code (0 = success, non-zero = error)
   * @param {string} [message] - Optional message to display
   */
  exit(code = 0, message = null) {
    if (message) {
      if (code === 0) {
        console.log(message);
      } else {
        console.error(message);
      }
    }
    this.exitFn(code);
  }

  /**
   * Exit with error message (code 1)
   *
   * @param {string} message - Error message
   * @param {number} [code=1] - Error code
   */
  exitWithError(message, code = 1) {
    this.exit(code, chalk.red(message));
  }

  /**
   * Exit with success message (code 0)
   *
   * @param {string} message - Success message
   */
  exitWithSuccess(message) {
    this.exit(0, chalk.green(message));
  }

  /**
   * Exit with warning message (code 0, but highlighted)
   *
   * @param {string} message - Warning message
   */
  exitWithWarning(message) {
    this.exit(0, chalk.yellow(message));
  }
}

// Default instance for general use
export const processHandler = new ProcessHandler();

/**
 * Create a test handler for unit tests
 *
 * @returns {{handler: ProcessHandler, getExitCode: Function, getExited: Function}}
 */
export function createTestHandler() {
  let exitCode = null;
  let exited = false;

  const handler = new ProcessHandler((code) => {
    exitCode = code;
    exited = true;
  });

  return {
    handler,
    getExitCode: () => exitCode,
    getExited: () => exited,
    reset: () => {
      exitCode = null;
      exited = false;
    },
  };
}
