// 解析帮助、输入文件和输出阶段选项。

#include "utils/CLI.h"

#include <cstring>
#include <stdexcept>
#include <string>

#include "utils/Log.h"

CLIOptions ParseCLI(int argc, char** argv) {
  CLIOptions opt;
  bool explicit_emit = false;

  if (argc <= 1) {
    throw std::runtime_error(FormatError(
        "cli",
        "用法: compiler [--help] [--emit-parse-tree] [--emit-ir] [--emit-asm] <input.sy>"));
  }

  for (int i = 1; i < argc; ++i) {
    const char* arg = argv[i];
    if (std::strcmp(arg, "-h") == 0 || std::strcmp(arg, "--help") == 0) {
      opt.show_help = true;
      return opt;
    }

    if (std::strcmp(arg, "--emit-parse-tree") == 0) {
      if (!explicit_emit) {
        opt.emit_parse_tree = false;
        opt.emit_ir = false;
        opt.emit_asm = false;
        explicit_emit = true;
      }
      opt.emit_parse_tree = true;
      continue;
    }

    if (std::strcmp(arg, "--emit-ir") == 0) {
      if (!explicit_emit) {
        opt.emit_parse_tree = false;
        opt.emit_ir = false;
        opt.emit_asm = false;
        explicit_emit = true;
      }
      opt.emit_ir = true;
      continue;
    }

    if (std::strcmp(arg, "--emit-asm") == 0) {
      if (!explicit_emit) {
        opt.emit_parse_tree = false;
        opt.emit_ir = false;
        opt.emit_asm = false;
        explicit_emit = true;
      }
      opt.emit_asm = true;
      continue;
    }

    if (arg[0] == '-') {
      throw std::runtime_error(
          FormatError("cli", std::string("未知参数: ") + arg +
                                 "（使用 --help 查看用法）"));
    }

    if (!opt.input.empty()) {
      throw std::runtime_error(FormatError(
          "cli", "参数过多：当前只支持 1 个输入文件（使用 --help 查看用法）"));
    }
    opt.input = arg;
  }

  if (opt.input.empty() && !opt.show_help) {
    throw std::runtime_error(
        FormatError("cli", "缺少输入文件：请提供 <input.sy>（使用 --help 查看用法）"));
  }
  if (!opt.emit_parse_tree && !opt.emit_ir && !opt.emit_asm) {
    throw std::runtime_error(FormatError(
        "cli", "未选择任何输出：请使用 --emit-parse-tree / --emit-ir / --emit-asm"));
  }
  return opt;
}
