#include SINGLE_CUSTOM_REG_OP
#include <fstream>
#include <sys/stat.h>

bool IsSymlink(const char* filePath) {
  struct stat buf;
  if (lstat(filePath, &buf) != 0) {
    return false;
  }
  return S_ISLNK(buf.st_mode);
}

int main(int argc, char** argv) {
  if (argc != 2) {
    std::cerr << "Usage: " << argv[0] << " <output_dir>" << kEnd;
    return 1;
  }
  if (IsSymlink(argv[1])) {
    std::cerr << "[Error]: Target file path " << argv[1] << " should not be an symbolic link." << kEnd;
    return 1;
  }
  std::fstream file;
  file.open(argv[1], std::ios::out);

  if (!file.is_open()) {
    std::cerr << "[Error]: Open file " << argv[1] << " failed." << kEnd;
    return 1;
  }

  Code code;
  std::stringstream ss;
  size_t unsupported = 0U;
  for (auto& def : OpDef::defs) {
    if (!def.Err().empty()) {
      unsupported++;
      ss << "# IR " << def.op << " skipped as " << def.Err() << kEnd;
      continue;
    }
    def.Gen(code);
  }

  file << "# This file is auto-generated by " << SINGLE_CUSTOM_REG_OP << kEnd;
  file << "# Summary: total " << OpDef::defs.size() << ", generated " << (OpDef::defs.size() - unsupported)
       << ", skipped " << unsupported << kEnd;

  file << "from typing import Any, Dict, List, Tuple, Union, Callable, Optional" << kEnd;
  file << "from torchair.ge._ge_graph import auto_convert_to_tensor, TensorType" << kEnd;
  file << "from torchair.ge import Tensor, DataType, attr" << kEnd;
  file << "from torchair._ge_concrete_graph.ge_converter import ge_op, IrDef" << kEnd;
  file << ss.str() << kEnd;
  file << code.str() << kEnd;

  file.close();
}