package cn.datax.tool.codegen.utils;

import cn.datax.tool.codegen.engine.VelocityTemplateEngine;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;

import java.io.File;
import java.util.*;

public class Generate {

    public static void main(String[] args) {
        // 代码生成器
        AutoGenerator mpg = new AutoGenerator();
        // 全局配置
        GlobalConfig gc = new GlobalConfig();
        String projectPath = "F://code";
        gc.setOutputDir(projectPath + "/src/main/java");
        gc.setAuthor("yuwei");
        //  是否打开输出目录
        gc.setOpen(true);
        //  是否覆盖已有文件
        gc.setFileOverride(true);
        //  开启 ActiveRecord 模式
        gc.setActiveRecord(false);
        //  开启 BaseResultMap
        gc.setBaseResultMap(true);
        //  开启 baseColumnList
        gc.setBaseColumnList(true);
        gc.setEntityName("%sEntity");
        gc.setMapperName("%sDao");
        gc.setXmlName("%sMapper");
        gc.setServiceName("%sService");
        gc.setServiceImplName("%sServiceImpl");
        gc.setControllerName("%sController");
        //  实体属性 Swagger2 注解
        gc.setSwagger2(false);
        //  指定生成的主键的ID类型
        gc.setIdType(IdType.ID_WORKER_STR);
        mpg.setGlobalConfig(gc);

        // 数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://localhost:3306/data_cloud?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8");
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("1234@abcd");
        mpg.setDataSource(dsc);

        // 包配置
        PackageConfig pc = new PackageConfig();
        pc.setParent("cn.datax.service");
        //  父包模块名
        pc.setModuleName("system");
        pc.setMapper("dao");
        mpg.setPackageInfo(pc);

        // 自定义配置
        InjectionConfig cfg = new InjectionConfig() {
            @Override
            public void initMap() {
                Map<String, Object> map = new HashMap<String, Object>();
                map.put("PackageParent", "cn.datax.service");
                this.setMap(map);
            }
        };

        // 自定义输出配置
        List<FileOutConfig> focList = new ArrayList<>();
        // 自定义配置会被优先输出
        focList.add(new FileOutConfig("/templates/mapper.xml.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义输出文件名 ， 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化！！
                return projectPath + "/src/main/resources/mapper/" + pc.getModuleName()
                        + "/" + tableInfo.getEntityName().replace("Entity", "Mapper") + StringPool.DOT_XML;
            }
        });
        focList.add(new FileOutConfig("/templates/entity.java.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return projectPath + "/src/main/java/"+ "cn.datax.service".replace(".", File.separator) + File.separator + pc.getModuleName() + "/api/entity/" + tableInfo.getEntityName() + StringPool.DOT_JAVA;
            }
        });
        focList.add(new FileOutConfig("/templates/mapstruct.java.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return projectPath + "/src/main/java/"+ "cn.datax.service".replace(".", File.separator) + File.separator + pc.getModuleName() + "/mapstruct/" + tableInfo.getEntityName().replace("Entity", "Mapper") + StringPool.DOT_JAVA;
            }
        });
        focList.add(new FileOutConfig("/templates/dto.java.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return projectPath + "/src/main/java/"+ "cn.datax.service".replace(".", File.separator) + File.separator + pc.getModuleName() + "/api/dto/" + tableInfo.getEntityName().replace("Entity", "Dto") + StringPool.DOT_JAVA;
            }
        });
        focList.add(new FileOutConfig("/templates/vo.java.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return projectPath + "/src/main/java/"+ "cn.datax.service".replace(".", File.separator) + File.separator + pc.getModuleName() + "/api/vo/" + tableInfo.getEntityName().replace("Entity", "Vo") + StringPool.DOT_JAVA;
            }
        });
        focList.add(new FileOutConfig("/templates/query.java.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return projectPath + "/src/main/java/"+ "cn.datax.service".replace(".", File.separator) + File.separator + pc.getModuleName() + "/api/query/" + tableInfo.getEntityName().replace("Entity", "Query") + StringPool.DOT_JAVA;
            }
        });
        /*
        cfg.setFileCreate(new IFileCreate() {
            @Override
            public boolean isCreate(ConfigBuilder configBuilder, FileType fileType, String filePath) {
                // 判断自定义文件夹是否需要创建
                checkDir("调用默认方法创建的目录");
                return false;
            }
        });
        */
        cfg.setFileOutConfigList(focList);
        mpg.setCfg(cfg);

        // 配置模板
        TemplateConfig templateConfig = new TemplateConfig();

        // 配置自定义输出模板
        //指定自定义模板路径，注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别
        templateConfig.setEntity(null);
        templateConfig.setController("templates/controller.java");
        templateConfig.setService("templates/service.java");
        templateConfig.setServiceImpl("templates/serviceImpl.java");
        templateConfig.setMapper("templates/mapper.java");
        templateConfig.setXml(null);
        mpg.setTemplate(templateConfig);

        // 策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        strategy.setSuperEntityClass("cn.datax.common.base.BaseEntity");
        // 写于父类中的公共字段
        strategy.setSuperEntityColumns(new String[]{"id", "create_time", "create_by", "update_time", "update_by", "status"});
        strategy.setEntityLombokModel(true);
        strategy.setRestControllerStyle(true);
        // 公共父类
        strategy.setSuperControllerClass("cn.datax.common.base.BaseController");
        strategy.setSuperServiceClass("cn.datax.common.base.BaseService");
        strategy.setSuperServiceImplClass("cn.datax.common.base.BaseServiceImpl");
        strategy.setSuperMapperClass("cn.datax.common.base.BaseDao");
        strategy.setControllerMappingHyphenStyle(true);
        strategy.setTablePrefix("sys_");
//        strategy.setInclude(new String[]{"sys_user", "sys_role", "sys_dept", "sys_menu", "sys_post", "sys_user_role", "sys_user_dept", "sys_user_post", "sys_role_menu"});
        strategy.setInclude(new String[]{"sys_user"});
        mpg.setStrategy(strategy);
        mpg.setTemplateEngine(new VelocityTemplateEngine());

        mpg.execute();
    }

    /**
     * 根据表自动生成
     *
     * @param moduleName            模块名
     * @param parentName            包名
     * @param tableNames            表名
     */
    private void generateByTables(String moduleName, String parentName, List<String> tableNames) {
        //配置数据源
        DataSourceConfig dataSourceConfig = getDataSourceConfig();
        //全局变量配置
        GlobalConfig globalConfig = getGlobalConfig();
        //包名配置
        PackageConfig packageConfig = getPackageConfig(moduleName, parentName);
        // 策略配置
        StrategyConfig strategyConfig = getStrategyConfig(tableNames);
        //自定义配置
        InjectionConfig injectionConfig = getInjectionConfig(moduleName, parentName);
        //配置模板
        TemplateConfig templateConfig = getTemplateConfig();
        //自动生成
        atuoGenerator(dataSourceConfig, strategyConfig, globalConfig, packageConfig, injectionConfig, templateConfig);
    }

    /**
     * 集成
     *
     * @param dataSourceConfig 数据源配置
     * @param strategyConfig   策略配置
     * @param globalConfig     全局变量配置
     * @param packageConfig    包名配置
     * @param injectionConfig  自定义配置
     * @param templateConfig   模板配置
     */
    private void atuoGenerator(DataSourceConfig dataSourceConfig, StrategyConfig strategyConfig, GlobalConfig globalConfig, PackageConfig packageConfig,
                               InjectionConfig injectionConfig, TemplateConfig templateConfig) {
        new AutoGenerator()
                .setGlobalConfig(globalConfig)
                .setDataSource(dataSourceConfig)
                .setStrategy(strategyConfig)
                .setPackageInfo(packageConfig)
                .setCfg(injectionConfig)
                .setTemplate(templateConfig)
                .setTemplateEngine(new VelocityTemplateEngine())
                .execute();
    }

    /**
     * 自定义配置 可以在 VM 中使用 cfg.abc
     *
     * @return templateConfig
     */
    private InjectionConfig getInjectionConfig(String moduleName, String parentName) {
        InjectionConfig cfg = new InjectionConfig() {
            @Override
            public void initMap() {
                Map<String, Object> map = new HashMap<>();
                map.put("PackageParent", parentName);
                this.setMap(map);
            }
        };
        List<FileOutConfig> focList = new ArrayList<>();
        focList.add(new FileOutConfig("/templates/mapper.xml.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return System.getProperty("user.dir") + "/src/main/resources/mapper/" + tableInfo.getEntityName().replace("Entity", "Mapper") + StringPool.DOT_XML;
            }
        });
        focList.add(new FileOutConfig("/templates/entity.java.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return System.getProperty("user.dir") + "/src/main/java/"+ parentName.replace(".", File.separator) + File.separator + moduleName + "/api/entity/" + tableInfo.getEntityName() + StringPool.DOT_JAVA;
            }
        });
        focList.add(new FileOutConfig("/templates/mapstruct.java.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return System.getProperty("user.dir") + "/src/main/java/"+ parentName.replace(".", File.separator) + File.separator + moduleName + "/mapstruct/" + tableInfo.getEntityName().replace("Entity", "Mapper") + StringPool.DOT_JAVA;
            }
        });
        focList.add(new FileOutConfig("/templates/dto.java.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return System.getProperty("user.dir") + "/src/main/java/"+ parentName.replace(".", File.separator) + File.separator + moduleName + "/api/dto/" + tableInfo.getEntityName().replace("Entity", "Dto") + StringPool.DOT_JAVA;
            }
        });
        focList.add(new FileOutConfig("/templates/vo.java.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return System.getProperty("user.dir") + "/src/main/java/"+ parentName.replace(".", File.separator) + File.separator + moduleName + "/api/vo/" + tableInfo.getEntityName().replace("Entity", "Vo") + StringPool.DOT_JAVA;
            }
        });
        focList.add(new FileOutConfig("/templates/query.java.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return System.getProperty("user.dir") + "/src/main/java/"+ parentName.replace(".", File.separator) + File.separator + moduleName + "/api/query/" + tableInfo.getEntityName().replace("Entity", "Query") + StringPool.DOT_JAVA;
            }
        });
        cfg.setFileOutConfigList(focList);
        return cfg;
    }

    /**
     * 模板配置
     *
     * @return templateConfig
     */
    private TemplateConfig getTemplateConfig() {
        return new TemplateConfig()
                .setEntity(null)
                .setController("templates/controller.java")
                .setService("templates/service.java")
                .setServiceImpl("templates/serviceImpl.java")
                .setMapper("templates/mapper.java")
                .setXml(null);
    }

    /**
     * 设置包名
     *
     * @param moduleName 模块名 如：system
     * @param parentName 父路径包名 如：cn.datax.service
     * @return PackageConfig 包名配置
     */
    private PackageConfig getPackageConfig(String moduleName, String parentName) {
        return new PackageConfig()
                .setModuleName(moduleName)
                .setParent(parentName)
                .setXml("mapper")
                .setMapper("dao")
                .setController("controller")
                .setService("service")
                .setServiceImpl("service.impl")
                .setEntity("entity");
    }

    /**
     * 全局配置
     *
     * @return GlobalConfig
     */
    private GlobalConfig getGlobalConfig() {
        return new GlobalConfig()
                //是否打开输出目录
                .setOpen(false)
                //开启 baseColumnList
                .setBaseColumnList(true)
                //开启 BaseResultMap
                .setBaseResultMap(true)
                //开启 ActiveRecord 模式
                .setActiveRecord(false)
                //是否覆盖已有文件
                .setFileOverride(true)
                //实体属性 Swagger2 注解
                .setSwagger2(false)
                .setAuthor("yuwei")
                //指定生成的主键的ID类型
                .setIdType(IdType.ID_WORKER_STR)
                //设置输出路径
                .setOutputDir(System.getProperty("user.dir") + "/src/main/java/")
                .setEntityName("%sEntity")
                .setMapperName("%sDao")
                .setXmlName("%sMapper")
                .setServiceName("%sService")
                .setServiceImplName("%sServiceImpl")
                .setControllerName("%sController");
    }

    /**
     * 策略配置
     *
     * @param tableNames 表名
     * @return StrategyConfig
     */
    private StrategyConfig getStrategyConfig(List<String> tableNames) {
        return new StrategyConfig()
                //从数据库表到文件的命名策略
                .setNaming(NamingStrategy.underline_to_camel)
                .setColumnNaming(NamingStrategy.underline_to_camel)
                .setSuperEntityClass("cn.datax.common.base.BaseEntity")
                //写于父类中的公共字段
                .setSuperEntityColumns(new String[]{"id", "create_time", "create_by", "update_time", "update_by", "status"})
                .setEntityLombokModel(true)
                .setRestControllerStyle(true)
                //公共父类
                .setSuperControllerClass("cn.datax.common.base.BaseController")
                .setSuperServiceClass("cn.datax.common.base.BaseService")
                .setSuperServiceImplClass("cn.datax.common.base.BaseServiceImpl")
                .setSuperMapperClass("cn.datax.common.base.BaseDao")
                .setControllerMappingHyphenStyle(true)
                .setTablePrefix("sys_")
                .setInclude(tableNames.toArray(new String[tableNames.size()]));
    }

    /**
     * 配置数据源
     *
     * @return 数据源配置 DataSourceConfig
     */
    private DataSourceConfig getDataSourceConfig() {
        return new DataSourceConfig()
                .setUrl("jdbc:mysql://localhost:3306/data_cloud?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8")
                .setDriverName("com.mysql.cj.jdbc.Driver")
                .setUsername("root")
                .setPassword("1234@abcd");
    }
}
