content: package org.ruoyi.generator.impl;
  
  import cn.hutool.core.collection.CollUtil;
  import cn.hutool.core.util.IdUtil;
  import cn.hutool.core.util.StrUtil;
  import lombok.RequiredArgsConstructor;
  import lombok.extern.slf4j.Slf4j;
  import org.apache.velocity.Template;
  import org.apache.velocity.VelocityContext;
  import org.apache.velocity.app.Velocity;
  import org.ruoyi.common.core.constant.Constants;
  import org.ruoyi.generator.config.GenConfig;
  import org.ruoyi.generator.domain.vo.SchemaFieldVo;
  import org.ruoyi.generator.domain.vo.SchemaGroupVo;
  import org.ruoyi.generator.domain.vo.SchemaVo;
  import org.ruoyi.generator.service.IGenTableService;
  import org.ruoyi.generator.service.SchemaFieldService;
  import org.ruoyi.generator.service.SchemaGroupService;
  import org.ruoyi.generator.service.SchemaService;
  import org.ruoyi.generator.util.VelocityInitializer;
  import org.ruoyi.generator.util.VelocityUtils;
  import org.springframework.stereotype.Service;
  
  import java.io.*;
  import java.nio.charset.StandardCharsets;
  import java.util.*;
  
  /**
   * 业务 服务层实现
   *
   * @author Lion Li
   */
  @Slf4j
  @RequiredArgsConstructor
  @Service
  public class GenTableServiceImpl implements IGenTableService {
  
      private final SchemaService schemaService;
      private final SchemaFieldService schemaFieldService;
      private final SchemaGroupService schemaGroupService;
  
      /**
       * 基于表名称批量生成代码到classpath路径
       *
       * @param tableName 表名称数组
       */
      @Override
      public void generateCodeToClasspathByTableNames(String tableName) {
          try {
              generateSchemaCodeToClasspathByTableName(tableName);
          } catch (Exception e) {
              throw new RuntimeException("基于表名称生成代码失败", e);
          }
      }
  
      @Override
      public void generateFrontendTemplateFiles(String workPath, String previewCode) {
          String os = System.getProperty("os.name").toLowerCase();
  
          ProcessBuilder builder;
          if (os.contains("win")) {
              // Windows下用 cmd /c 执行 previewCode
              builder = new ProcessBuilder("cmd.exe", "/c", previewCode);
          } else {
              // macOS/Linux 用 bash -c 执行 previewCode
              builder = new ProcessBuilder("bash", "-c", previewCode);
          }
  
          // 设置工作目录
          builder.directory(new File(workPath));
          builder.redirectErrorStream(true);
  
          try (BufferedReader reader = new BufferedReader(
                  new InputStreamReader(
                          builder.start().getInputStream(),
                          StandardCharsets.UTF_8
                  )
          )) {
              String line;
              log.info("执行结果：");
              while ((line = reader.readLine()) != null) {
                  log.info(line);
              }
  
          } catch (Exception e) {
              log.error("生成前端代码出错", e);
              throw new RuntimeException("生成前端代码失败", e);
          }
      }
  
      /**
       * 根据表名称生成代码到classpath
       */
      private void generateSchemaCodeToClasspathByTableName(String tableName) {
          // 查询Schema信息
          SchemaVo schema = schemaService.queryByTableName(tableName);
          if (Objects.isNull(schema)) {
              log.warn("Schema不存在，表名: {}", tableName);
              return;
          }
  
          // 查询Schema字段信息
          List<SchemaFieldVo> fields = schemaFieldService.queryListByTableName(tableName);
          if (CollUtil.isEmpty(fields)) {
              log.warn("Schema字段为空，表名: {}", tableName);
              return;
          }
          generateCodeFromSchemaData(schema, fields);
      }
  
      /**
       * 根据Schema数据生成代码
       */
      private void generateCodeFromSchemaData(SchemaVo schema, List<SchemaFieldVo> fields) {
  
          // 初始化Velocity
          VelocityInitializer.initVelocity();
  
          // 准备Velocity上下文 - 直接基于Schema数据
          VelocityContext context = prepareSchemaContext(schema, fields);
  
          // 获取模板列表
          List<String> templates = VelocityUtils.getTemplateList();
  
          // 获取项目根路径
          String projectPath = getProjectRootPath();
  
          for (String template : templates) {
              try {
                  // 渲染模板
                  StringWriter sw = new StringWriter();
                  Template tpl = Velocity.getTemplate(template, Constants.UTF8);
                  tpl.merge(context, sw);
  
                  // 获取文件路径 - 直接基于Schema数据
                  String fileName = getSchemaFileName(template, schema);
                  String fullPath = projectPath + File.separator + fileName;
  
                  // 创建目录
                  File file = new File(fullPath);
                  File parentDir = file.getParentFile();
                  if (!parentDir.exists()) {
                      parentDir.mkdirs();
                  }
                  // 写入文件
                  try (FileWriter writer = new FileWriter(file, StandardCharsets.UTF_8)) {
                      writer.write(sw.toString());
                  }
                  log.info("生成文件: {}", fullPath);
              } catch (Exception e) {
                  log.error("生成文件失败，模板: {}, Schema: {}", template, schema.getName(), e);
              }
          }
      }
  
      /**
       * 准备基于Schema的Velocity上下文
       */
      private VelocityContext prepareSchemaContext(SchemaVo schema, List<SchemaFieldVo> fields) {
          VelocityContext context = new VelocityContext();
  
          // 从配置文件读取基本配置
          String packageName = GenConfig.getPackageName();
          String author = GenConfig.getAuthor();
          String tablePrefix = GenConfig.getTablePrefix();
          boolean autoRemovePre = GenConfig.getAutoRemovePre();
  
          // 处理表名和类名
          Long schemaGroupId = schema.getSchemaGroupId();
          SchemaGroupVo schemaGroupVo = schemaGroupService.queryById(schemaGroupId);
          String tableName = schema.getTableName();
          String baseClassName = schema.getTableName();
  
          // 自动去除表前缀
          if (autoRemovePre && StrUtil.isNotBlank(tablePrefix)) {
              String[] prefixes = tablePrefix.split(",");
              for (String prefix : prefixes) {
                  if (baseClassName.startsWith(prefix.trim())) {
                      baseClassName = baseClassName.substring(prefix.trim().length());
                      break;
                  }
              }
          }
  
          String className = toCamelCase(baseClassName, true);  // 首字母大写的类名，如：SysRole
          String classname = toCamelCase(baseClassName, false); // 首字母小写的类名，如：sysRole
          String businessName = toCamelCase(baseClassName, false);
          String moduleName = schemaGroupVo.getCode();
  
          // 基本信息
          context.put("tableName", tableName);
          context.put("tableComment", schema.getComment());
          context.put("className", classname);  // 首字母小写
          context.put("classname", classname);  // 首字母小写（兼容性）
          context.put("ClassName", className);  // 首字母大写
          context.put("functionName", schema.getName());
          context.put("functionAuthor", author);
          context.put("author", author);
          context.put("datetime", new Date());
          context.put("packageName", packageName);
          context.put("moduleName", moduleName);
          context.put("businessName", businessName);
  
          // 权限相关
          context.put("permissionPrefix", moduleName + ":" + businessName);
          context.put("parentMenuId", "2000");  // 默认父菜单ID，可配置
  
          // 生成菜单ID
          List<Long> menuIds = new ArrayList<>();
          for (int i = 0; i < 6; i++) {
              menuIds.add(IdUtil.getSnowflakeNextId());
          }
          context.put("menuIds", menuIds);
  
          // 创建table对象，包含menuIds等信息和方法
          Map<String, Object> table = new HashMap<>();
          table.put("menuIds", menuIds);
          table.put("tableName", tableName);
          table.put("tableComment", schema.getComment());
          table.put("className", className);
          table.put("classname", classname);
          table.put("functionName", schema.getName());
  
          // 添加表类型属性（默认为crud类型）
          table.put("crud", true);
          table.put("sub", false);
          table.put("tree", false);
  
          context.put("table", table);
  
          // 处理字段信息
          List<Map<String, Object>> columns = new ArrayList<>();
          Map<String, Object> pkColumn = null;
          Set<String> importList = new HashSet<>();
  
          // 添加基础导入
          importList.add("java.io.Serializable");
  
          for (SchemaFieldVo field : fields) {
              Map<String, Object> column = new HashMap<>();
              String javaType = getJavaType(field.getType());
              String javaField = StrUtil.toCamelCase(field.getCode());
  
              column.put("columnName", field.getCode());
              column.put("columnComment", field.getName());
              column.put("comment", field.getName());  // 添加comment别名
              column.put("columnType", field.getType());
              column.put("javaType", javaType);
              column.put("javaField", javaField);
              column.put("capJavaField", toCamelCase(field.getCode(), true));
  
              // 布尔值dictType属性（兼容两种格式）
              boolean isPk = "1".equals(field.getIsPk());
              boolean isRequired = "1".equals(field.getIsRequired());
              boolean isInsert = "1".equals(field.getIsInsert());
              boolean isEdit = "1".equals(field.getIsEdit());
              boolean isList = "1".equals(field.getIsList());
              boolean isQuery = "1".equals(field.getIsQuery());
  
              column.put("isPk", isPk ? 1 : 0);
              column.put("pk", isPk);  // 添加pk别名
              column.put("isRequired", isRequired);
              column.put("required", isRequired);  // 添加required别名
              column.put("isInsert", isInsert);
              column.put("insert", isInsert);  // 添加insert别名
              column.put("isEdit", isEdit);
              column.put("edit", isEdit);  // 添加edit别名
              column.put("isList", isList);
              column.put("list", isList);  // 添加list别名
              column.put("isQuery", isQuery);
              column.put("query", isQuery);  // 添加query别名
  
              column.put("queryType", field.getQueryType());
              column.put("htmlType", field.getHtmlType());
              column.put("dictType", field.getDictType());
              column.put("sort", field.getSort());
  
              // 添加readConverterExp方法
              column.put("readConverterExp", new Object() {
              });
  
              // 根据Java类型添加相应的导入
              addImportForJavaType(javaType, importList);
  
              columns.add(column);
  
              // 设置主键列
              if (isPk) {
                  pkColumn = column;
              }
          }
  
          // 如果没有主键，使用第一个字段作为主键
          if (pkColumn == null && !columns.isEmpty()) {
              pkColumn = columns.get(0);
              // 将第一个字段设置为主键
              pkColumn.put("isPk", 1);
              pkColumn.put("pk", true);
          }
  
          context.put("columns", columns);
          context.put("pkColumn", pkColumn);
          context.put("importList", new ArrayList<>(importList));
  
          return context;
      }
  
      /**
       * 根据Java类型添加相应的导入
       */
      private void addImportForJavaType(String javaType, Set<String> importList) {
          switch (javaType) {
              case "BigDecimal" -> importList.add("java.math.BigDecimal");
              case "Date" -> importList.add("java.util.Date");
              case "LocalDateTime" -> importList.add("java.time.LocalDateTime");
              case "LocalDate" -> importList.add("java.time.LocalDate");
              case "LocalTime" -> importList.add("java.time.LocalTime");
              default -> {
              }
          }
      }
  
      /**
       * 从包名中提取模块名
       */
      private String getModuleName(String packageName) {
          if (StrUtil.isBlank(packageName)) {
              return "generator";
          }
          String[] parts = packageName.split("\\.");
          if (parts.length >= 3) {
              return parts[2]; // org.ruoyi.system -> system
          }
          return "generator";
      }
  
      /**
       * 获取基于Schema的文件名
       */
      private String getSchemaFileName(String template, SchemaVo schema) {
          // 从配置文件读取配置
          String packageName = GenConfig.getPackageName();
          String tablePrefix = GenConfig.getTablePrefix();
          boolean autoRemovePre = GenConfig.getAutoRemovePre();
  
          // 处理类名
          String baseClassName = schema.getTableName();
  
          // 自动去除表前缀
          if (autoRemovePre && StrUtil.isNotBlank(tablePrefix)) {
              String[] prefixes = tablePrefix.split(",");
              for (String prefix : prefixes) {
                  if (baseClassName.startsWith(prefix.trim())) {
                      baseClassName = baseClassName.substring(prefix.trim().length());
                      break;
                  }
              }
          }
  
          String className = toCamelCase(baseClassName, true);   // 首字母大写，如：SysRole
          // 首字母小写，如：sysRole
          String moduleName = getModuleName(packageName);
          String javaPath = "src/main/java/";
          String mybatisPath = "src/main/resources/mapper/";
  
          if (template.contains("domain.java.vm")) {
              return javaPath + packageName.replace(".", "/") + "/domain/" + className + ".java";
          } else if (template.contains("mapper.java.vm")) {
              return javaPath + packageName.replace(".", "/") + "/mapper/" + className + "Mapper.java";
          } else if (template.contains("service.java.vm")) {
              return javaPath + packageName.replace(".", "/") + "/service/" + className + "Service.java";
          } else if (template.contains("serviceImpl.java.vm")) {
              return javaPath + packageName.replace(".", "/") + "/service/impl/" + className + "ServiceImpl.java";
          } else if (template.contains("controller.java.vm")) {
              return javaPath + packageName.replace(".", "/") + "/controller/" + className + "Controller.java";
          } else if (template.contains("vo.java.vm")) {
              return javaPath + packageName.replace(".", "/") + "/domain/vo/" + className + "Vo.java";
          } else if (template.contains("bo.java.vm")) {
              return javaPath + packageName.replace(".", "/") + "/domain/bo/" + className + "Bo.java";
          } else if (template.contains("mapper.xml.vm")) {
              return mybatisPath + moduleName + "/" + className + "Mapper.xml";
          } else if (template.contains("sql.vm")) {
              return javaPath + packageName.replace(".", "/") + "/sql/" + baseClassName + "_menu.sql";
          }
          return template.replace(".vm", "");
      }
  
      /**
       * 获取项目根路径
       */
      private String getProjectRootPath() {
          // 获取当前类的路径，然后向上查找到项目根目录
          String classPath = this.getClass().getProtectionDomain().getCodeSource().getLocation().getPath();
          File currentDir = new File(classPath).getParentFile();
  
          // 向上查找，直到找到包含src目录的项目根目录
          while (currentDir != null && currentDir.exists()) {
              File srcDir = new File(currentDir, "src");
              if (srcDir.exists() && srcDir.isDirectory()) {
                  return currentDir.getAbsolutePath();
              }
              currentDir = currentDir.getParentFile();
          }
  
          // 如果找不到，使用当前工作目录
          return System.getProperty("user.dir");
      }
  
      /**
       * 转换为驼峰命名
       */
      private String toCamelCase(String str, boolean firstUpperCase) {
          if (StrUtil.isBlank(str)) {
              return str;
          }
  
          StringBuilder result = new StringBuilder();
          String[] parts = str.split("_");
          for (int i = 0; i < parts.length; i++) {
              String part = parts[i].toLowerCase();
              if (i == 0 && !firstUpperCase) {
                  result.append(part);
              } else {
                  result.append(part.substring(0, 1).toUpperCase()).append(part.substring(1));
              }
          }
          return result.toString();
      }
  
      /**
       * 获取Java类型
       */
      private String getJavaType(String dbType) {
          if (StrUtil.isBlank(dbType)) {
              return "String";
          }
          String type = dbType.toLowerCase();
          if (StrUtil.equalsAny(type, "int", "tinyint")) {
              return "Integer";
          } else if (StrUtil.equalsAny(type, "bigint")) {
              return "Long";
          } else if (StrUtil.equalsAny(type, "decimal", "numeric", "float", "double")) {
              return "BigDecimal";
          } else if (StrUtil.equalsAny(type, "date")) {
              return "LocalDate";
          } else if (StrUtil.equalsAny(type, "datetime", "timestamp")) {
              return "LocalDateTime";
          } else if (StrUtil.equalsAny(type, "bit", "boolean")) {
              return "Boolean";
          } else {
              return "String";
          }
      }
  
  }
  
  