content: import t from "../../dist/index.js";
  import stringifyValidatorJava from "../utils/stringifyValidatorJava.js";
  import fs from 'fs';
  import path from 'path';
  
  const DISCLAIMER = `//NOTE: This file is autogenerated. Do not modify.
  `;
  const packageDecl = `package org.uast;\n`;
  
  function jsonDes(types) {
      return `import com.fasterxml.jackson.annotation.JsonSubTypes;
  import com.fasterxml.jackson.annotation.JsonTypeInfo;
  @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
  @JsonSubTypes({
  ${types.map(type => {
          return `    @JsonSubTypes.Type(value = ${type}.class, name = "${type}"),`
      }).join("\n")}
  })`;
  }
  
  const ASTNodeCode = function (types) {
      return function () {
          return `
  ${DISCLAIMER}
  ${packageDecl}
  ${jsonDes(types)}
  abstract public class ASTNode {
      public ASTNode parent;
      abstract public <T> T accept(UastVisitor visitor);
  };`
      }
  };
  
  // java的每个 AST 节点的描述会作为一个类，单独写到一个文件中
  // 对于不同类型的AST节点的聚类，会作为interface，并且被具体的AST node 引入实现，例如Statement，Expression等
  export default function generateAstTypes(dir) {
      let astNodes = {};  //所生成的类或者接口的容器，key为生成的节点类型名称，value为具体生成的代码
      let defaultVisitorField = {}; //标记 ast 节点应该遍历的属性
  
      astNodes['ASTNode'] = ASTNodeCode(Object.keys(t.NODE_FIELDS)); // AST node 基类
  
      for (const type in t.NODE_FIELDS) {
          const comment = t.NODE_COMMENTS[type]
          const commentDoc = DISCLAIMER + (comment.trim().length === 0 ? '' : `/**\n${comment}\n**/\n`);
          const fields = t.NODE_FIELDS[type];
          const fieldNames = sortFieldNames(Object.keys(t.NODE_FIELDS[type]), type);
          const struct = [];
          const imports = new Set();
          const fieldNeedToVisit = [];
          defaultVisitorField[type] = fieldNeedToVisit;
          fieldNames.forEach(fieldName => {
              const field = fields[fieldName];
              const filedComment = t.NODE_FIELD_COMMENTS[type][fieldName];
              if (filedComment.trim() !== '') {
                  struct.push(`/**${t.NODE_FIELD_COMMENTS[type][fieldName]}**/`)
              }
              let typeAnnotation = stringifyValidatorJava(field.validate, "");
              const isArray = typeAnnotation.indexOf("List") !== -1;
              if (isArray) {
                  imports.add("import java.util.List;\n")
              }
  
              if ([ "String", "int", "boolean" ].every(value => typeAnnotation.indexOf(value) === -1)) {
                  fieldNeedToVisit.push({
                      fieldName,
                      isArray,
                  });
              }
              defaultVisitorField[type] = fieldNeedToVisit;
              const alphaNumeric = /^\w+$/;
              const optional = field.optional ? "?" : "";
  
              struct.push(`public ${typeAnnotation} ${fieldName};`);
          });
          // 添加 accept 方法
          struct.push(`public <T> T accept(UastVisitor visitor) {\n        return visitor.visit(this);\n    }`);
  
          astNodes[type] = function (types) {
              let importPart = ""
              imports.forEach(value => importPart += value);
              let implPart = "";
              if (types && types.length > 0) {
                  implPart = " implements " + types.reduce((ret, type) => {
                      return ret + ", " + type;
                  });
              }
              return `${commentDoc} ${packageDecl} ${importPart}import com.fasterxml.jackson.annotation.JsonTypeInfo;\n @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")\npublic class ${type} extends ASTNode ${implPart} {\n    public static final String type = "${type}";\n    ${struct.join("\n    ").trim()}\n}\n\n`;
          }
      }
  
      // 记录AstNode到Interface的反向映射关系
      let implTo = {}
  
      for (const interfaceType in t.FLIPPED_ALIAS_KEYS) {
          const types = t.FLIPPED_ALIAS_KEYS[interfaceType];
          astNodes[interfaceType] = function () {
              return `${DISCLAIMER}  ${packageDecl} ${jsonDes(types)} public interface ${interfaceType} {};`;
          }
  
          types.forEach((type) => {
              implTo[type] = implTo[type] || [];
              implTo[type].push(interfaceType);
          });
      }
  
      for (let nodeName in astNodes) {
          let types = implTo[nodeName];
          const content = astNodes[nodeName](types);
          writeto(dir, nodeName + '.java', content);
      }
  
      // 生成 UastVisitor
  
      let struct = '';
      for (let type in t.NODE_FIELDS) {
          struct += `\n    <T> T visit(${type} node); `
      }
      const visitorCode = `${DISCLAIMER} ${packageDecl}public interface UastVisitor {${struct}\n}`;
      writeto(dir, 'UastVisitor.java', visitorCode);
  
      // 生成 DefaultUastVisitor
      writeto(dir, 'DefaultUastVisitor.java', generateDefaultUastVisitor(defaultVisitorField));
  }
  
  function generateDefaultUastVisitor(defaultVisitorField) {
      const importCode = 'import java.util.List;\nimport java.util.function.Consumer;\n';
      let code = `${DISCLAIMER}${packageDecl}${importCode}public class DefaultUastVisitor implements UastVisitor{\n    protected Consumer<ASTNode> preVisit;\n    protected Consumer<ASTNode> postVisit;
      public <T> T accept(T node) {
          if (node != null) {
              if (node instanceof ASTNode) {
                  ((ASTNode) node).accept(this);
              }else if (node instanceof List){
                  ((List<?>) node).forEach(n ->{
                      ((ASTNode) n).accept(this);
                  });
              }
          }
          return node;
      }
      `;
  
      Object.keys(defaultVisitorField).forEach(type => {
  
          const fields = defaultVisitorField[type];
          let inner = fields.map(field => {
              const typeName = field.isArray ? "List" : "ASTNode";
              return `            this.accept((${typeName}) node.${field.fieldName});\n`;
          }).join('');
          inner += `\n            return node;`
          code += `\n    @Override\n    public ${type} visit(${type} node) {
          try{
              if (preVisit != null) {
                  preVisit.accept(node);
              }\n\n${inner}
          } finally {
              if (postVisit != null) {
                  postVisit.accept(node);
              }
          }
      }`;
      });
  
      code += `};`;
      return code;
  }
  
  function hasDefault(field) {
      return field.default != null;
  }
  
  function isNullable(field) {
      return field.optional || hasDefault(field);
  }
  
  function sortFieldNames(fields, type) {
      return fields.sort((fieldA, fieldB) => {
          const indexA = t.BUILDER_KEYS[type].indexOf(fieldA);
          const indexB = t.BUILDER_KEYS[type].indexOf(fieldB);
          if (indexA === indexB) return fieldA < fieldB ? -1 : 1;
          if (indexA === -1) return 1;
          if (indexB === -1) return -1;
          return indexA - indexB;
      });
  }
  
  function writeto(dir, filename, content) {
      const filePath = path.join(dir, filename);
  
      try {
          // 同步写入文件内容
          fs.writeFileSync(filePath, content);
          console.log(`File ${filename} written successfully.`);
      } catch (err) {
          console.error('Error writing file synchronously:', err);
      }
  }
  
  generateAstTypes('/Users/xxxxx/dev/uast/yasa_java/src/main/java/org/uast');
  
  
  