/**
 * @fileoverview OrdoJS CLI - Dev command
 */

import { Command } from 'commander';
import readline from 'readline';
import { OrdoJSDevServer } from '../dev-server/server.js';
import { logger } from '../utils/index.js';

/**
 * Register the dev command
 */
export function registerDevCommand(program: Command): void {
  program
    .command('dev')
    .description('Start development server')
    .argument('[dir]', 'Directory to serve', '.')
    .option('-p, --port <port>', 'Port to listen on', '3000')
    .option('-h, --host <host>', 'Host to listen on', 'localhost')
    .option('--hmr', 'Enable hot module replacement', true)
    .option('--no-hmr', 'Disable hot module replacement')
    .action(async (dir, options) => {
      try {
        await devCommand(dir, options);
      } catch (error) {
        logger.error(`Dev server failed: ${error instanceof Error ? error.message : String(error)}`);
        process.exit(1);
      }
    });
}

/**
 * Set up keyboard shortcuts for the dev server
 *
 * @param server - The development server instance
 */
function setupKeyboardShortcuts(server: OrdoJSDevServer): void {
  if (process.stdin.isTTY) {
    // Put stdin in raw mode to capture keystrokes
    readline.emitKeypressEvents(process.stdin);
    process.stdin.setRawMode(true);

    // Track restart state to prevent multiple restarts
    let isRestarting = false;

    process.stdin.on('keypress', async (str, key) => {
      // Ctrl+C - Exit the process
      if (key.ctrl && key.name === 'c') {
        logger.info('Shutting down...');
        await server.stop();
        process.exit(0);
      }

      // Shift+R - Restart the server with state preservation
      if (key.shift && key.name === 'r') {
        // Prevent multiple restarts from being triggered simultaneously
        if (isRestarting) {
          logger.warn('Restart already in progress, please wait...');
          return;
        }

        isRestarting = true;
        logger.info('Restart requested (Shift+R)');

        try {
          // Display progress indicator
          const startTime = Date.now();
          const progressIndicator = startProgressIndicator('Restarting server');

          // Preserve server state before restart
          const serverState = server.getServerState();

          // Perform the restart
          await server.restart();

          // Stop progress indicator
          stopProgressIndicator(progressIndicator);

          const duration = ((Date.now() - startTime) / 1000).toFixed(2);
          logger.success(`Server restarted successfully in ${duration}s`);

          // Log state preservation info if applicable
          if (Object.keys(serverState).length > 0) {
            logger.info('Server state was preserved during restart');
          }
        } catch (error) {
          logger.error(`Failed to restart server: ${error instanceof Error ? error.message : String(error)}`);
          logger.info('Try stopping and starting the server manually if issues persist');
        } finally {
          isRestarting = false;
        }
      }

      // ? - Show help
      if (key.name === '?') {
        logger.info('Keyboard shortcuts:');
        logger.info('  Ctrl+C  - Stop server and exit');
        logger.info('  Shift+R - Restart server (preserves state)');
        logger.info('  ?       - Show this help');
      }
    });
  }
}

/**
 * Start a progress indicator in the console
 *
 * @param message - The message to display
 * @returns The interval ID for the progress indicator
 */
function startProgressIndicator(message: string): NodeJS.Timeout {
  const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
  let i = 0;

  process.stdout.write('\n');

  return setInterval(() => {
    const frame = frames[i = ++i % frames.length];
    process.stdout.write(`\r${frame} ${message}...`);
  }, 80);
}

/**
 * Stop a progress indicator
 *
 * @param intervalId - The interval ID returned by startProgressIndicator
 */
function stopProgressIndicator(intervalId: NodeJS.Timeout): void {
  clearInterval(intervalId);
  process.stdout.write('\r                                        \r');
}

/**
 * Dev command implementation
 */
export async function devCommand(
  dir: string,
  options: {
    port: string;
    host: string;
    hmr: boolean;
  }
): Promise<void> {
  logger.info(`Starting development server...`);
  logger.info(`Directory: ${dir}`);
  logger.info(`Server: http://${options.host}:${options.port}`);
  logger.info(`HMR: ${options.hmr ? 'enabled' : 'disabled'}`);

  // Create and start the development server
  const server = new OrdoJSDevServer({
    dir,
    host: options.host,
    port: options.port,
    hmr: options.hmr
  });

  try {
    // Start the server
    await server.start();

    // Set up keyboard shortcuts
    setupKeyboardShortcuts(server);

    logger.info('Press ? for available commands');

    // Keep the process running until explicitly terminated
    await new Promise<void>(() => {});
  } catch (error) {
    // Ensure we stop the server if it failed to start properly
    try {
      await server.stop();
    } catch (stopError) {
      logger.debug(`Error stopping server after failed start: ${stopError instanceof Error ? stopError.message : String(stopError)}`);
    }

    throw error;
  }
}
