// 格式化错误并统一打印异常与帮助信息。

#include "utils/Log.h"

#include <ostream>
#include <string>

namespace {

bool IsCLIError(const std::string_view msg) {
  return HasErrorPrefix(msg, "cli");
}

}  // namespace

void LogInfo(const std::string_view msg, std::ostream& os) {
  os << "[info] " << msg << "\n";
}

void LogError(const std::string_view msg, std::ostream& os) {
  os << "[error] " << msg << "\n";
}

std::string FormatError(const std::string_view stage,
                        const std::string_view msg) {
  return "[" + std::string(stage) + "] " + std::string(msg);
}

std::string FormatErrorAt(const std::string_view stage, const std::size_t line,
                          const std::size_t column,
                          const std::string_view msg) {
  return "[" + std::string(stage) + "] @" + std::to_string(line) + ":" +
         std::to_string(column) + " - " + std::string(msg);
}

bool HasErrorPrefix(const std::string_view msg, const std::string_view stage) {
  const std::string prefix = "[" + std::string(stage) + "]";
  return msg.rfind(prefix, 0) == 0;
}

void PrintException(std::ostream& os, const std::exception& ex) {
  LogError(ex.what(), os);
  if (IsCLIError(ex.what())) {
    os << "\n";
    PrintHelp(os);
  }
}

void PrintHelp(std::ostream& os) {
  os << "SysY Compiler (课程实验最小可运行示例)\n"
     << "\n"
     << "用法:\n"
     << "  compiler [--help] [--emit-parse-tree] [--emit-ir] [--emit-asm] <input.sy>\n"
     << "\n"
     << "选项:\n"
     << "  -h, --help        打印帮助信息并退出\n"
     << "  --emit-parse-tree 仅在显式模式下启用语法树输出\n"
     << "  --emit-ir         仅在显式模式下启用 IR 输出\n"
     << "  --emit-asm        仅在显式模式下启用 AArch64 汇编输出\n"
     << "\n"
     << "说明:\n"
     << "  - 默认输出 IR\n"
     << "  - 若使用 --emit-parse-tree/--emit-ir/--emit-asm，则仅输出显式选择的阶段\n"
     << "  - 可使用重定向写入文件:\n"
     << "      compiler --emit-asm test/test_case/simple_add.sy > out.s\n";
}
