import { substituteAliases } from "../Alias";
// Helper function that checks if an argument (which is a string) is a valid number
function isNumber(str: string): boolean {
  if (typeof str != "string") {
    return false;
  } // Only process strings
  return !isNaN(str as unknown as number) && !isNaN(parseFloat(str));
}
export function ParseCommands(commands: string): string[] {
  // Sanitize input
  commands = commands.trim();
  // Replace all extra whitespace in command with a single space
  commands = commands.replace(/\s\s+/g, " ");

  const match = commands.match(/(?:'[^']*'|"[^"]*"|[^;"])*/g);
  if (!match) return [];
  // Split commands and execute sequentially
  const allCommands = match
    .map(substituteAliases)
    .map((c) => c.match(/(?:'[^']*'|"[^"]*"|[^;"])*/g))
    .flat();

  const out: string[] = [];
  for (const c of allCommands) {
    if (c === null) continue;
    if (c.match(/^\s*$/)) {
      continue;
    } // Don't run commands that only have whitespace
    out.push(c.trim());
  }
  return out;
}

export function ParseCommand(command: string): (string | number)[] {
  // This will be used to keep track of whether we're in a quote. This is for situations
  // like the alias command:
  //      alias run="run NUKE.exe"
  // We want the run="run NUKE.exe" to be parsed as a single command, so this flag
  // will keep track of whether we have a quote in
  let inQuote = ``;

  // Returns an array with the command and its arguments in each index
  // Properly handles quotation marks (e.g. `run foo.script "the sun"` will return [run, foo.script, the sun])
  const args = [];
  let start = 0,
    i = 0;
  let prevChar = ""; // Previous character
  while (i < command.length) {
    let escaped = false; // Check for escaped quotation marks
    if (i >= 1) {
      prevChar = command.charAt(i - 1);
      if (prevChar === "\\") {
        escaped = true;
      }
    }

    const c = command.charAt(i);
    if (c === '"') {
      // Double quotes
      if (!escaped && prevChar === " ") {
        const endQuote = command.indexOf('"', i + 1);
        if (endQuote !== -1 && (endQuote === command.length - 1 || command.charAt(endQuote + 1) === " ")) {
          args.push(command.substr(i + 1, endQuote - i - 1));
          if (endQuote === command.length - 1) {
            start = i = endQuote + 1;
          } else {
            start = i = endQuote + 2; // Skip the space
          }
          continue;
        }
      } else {
        if (inQuote === ``) {
          inQuote = `"`;
        } else if (inQuote === `"`) {
          inQuote = ``;
        }
      }
    } else if (c === "'") {
      // Single quotes, same thing as above
      if (!escaped && prevChar === " ") {
        const endQuote = command.indexOf("'", i + 1);
        if (endQuote !== -1 && (endQuote === command.length - 1 || command.charAt(endQuote + 1) === " ")) {
          args.push(command.substr(i + 1, endQuote - i - 1));
          if (endQuote === command.length - 1) {
            start = i = endQuote + 1;
          } else {
            start = i = endQuote + 2; // Skip the space
          }
          continue;
        }
      } else {
        if (inQuote === ``) {
          inQuote = `'`;
        } else if (inQuote === `'`) {
          inQuote = ``;
        }
      }
    } else if (c === " " && inQuote === ``) {
      const arg = command.substr(start, i - start);

      // If this is a number, convert it from a string to number
      if (isNumber(arg)) {
        args.push(parseFloat(arg));
      } else {
        args.push(arg);
      }

      start = i + 1;
    }
    ++i;
  }

  // Add the last argument
  if (start !== i) {
    const arg = command.substr(start, i - start);

    // If this is a number, convert it from string to number
    if (isNumber(arg)) {
      args.push(parseFloat(arg));
    } else {
      args.push(arg);
    }
  }

  return args;
}
