package com.storlead.sales.util;

import com.baomidou.mybatisplus.annotation.DbType;
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.querys.MySqlQuery;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * mybatis plus  自动代码生成
 * 自动基于指定表生成 model mapper controller service
 *
 * @author YPZ
 * @since 2024/4/3 下午3:43
 */
public class MybatisPlusGenerator {


    /**
     * 是否生成代码到项目位置
     * 如要生成到D盘这里改成 false 即可
     */
    private static final boolean WRITE_FILE_TO_PROJECT = false;

    //文件生成目录
    final static String projectPath = System.getProperty("user.dir");

    //默认输出路径
    final static String defaultOutputDir = "D:\\java";
    //项目输出路径
    final static String outputDirPrefix = filePathJoin(projectPath , "java" ,"sp-sales-platform", "src" , "main");
    //自定义xml输出位置
//    final static String customMapperPath = "\\java\\sp-sales-service\\src\\main\\resources\\mapper\\console";
    final static String customMapperPath =filePathJoinWithSeparator(File.separator,File.separator,"java","sp-sales-platform","src","main","resources","mapper","console");

    //实体的公共父类
    final static  String superEntityClass = "com.storlead.frame.mybatis.entity.SysBaseField";
    //数据库连接字符串
    final static String jdbcUrl ="jdbc:mysql://192.168.1.69:3306/sp_sales_dev?characterEncoding=utf8&useSSL=false";
    //数据库驱动
    final static String driverName = "com.mysql.jdbc.Driver";
    //数据库用户名
    final static String username = "storlead";
    //数据库密码
    final static String password =  "DW8YRN*5!6u&Agt7N";

    //创建人
    final static String author =  "YPZ";

    final static  String entitySuffix="Entity";

    public static void main(String[] args) {

        String[] generateTables = {
                "customer_search"
                //待运行生成的数据库表
        };
        //代码生成器
        AutoGenerator mpg = new AutoGenerator();
        //1.加载全局配置
        mpg.setGlobalConfig( getGlobalConfig());
        //2.加载数据源配置
        mpg.setDataSource(getDataSourceConfig());
        //3.加载包配置
        mpg.setPackageInfo(getPackageConfig());
        //4.加载模板配置
        mpg.setTemplate(getTemplateConfig());
        //5.加载策略配置
        mpg.setStrategy(getStrategyConfig(generateTables));
        //6.自定义配置
        mpg.setCfg(getInjectionConfig());
        //7.设置模板引擎//支持 Velocity(默认)/Freemarker/Beetl
        mpg.setTemplateEngine(new FreemarkerTemplateEngine());
        //生成器执行，生成代码
        mpg.execute();
    }


    /**
     * @Param:
     * @return: @return {@link GlobalConfig }
     * @Author: YPZ
     * @Date: 2024-04-02
     */
    public static GlobalConfig getGlobalConfig() {
        GlobalConfig gc = new GlobalConfig();
        if (WRITE_FILE_TO_PROJECT) {
            // 设置代码直接生成在项目中 警告 会覆盖旧有代码!
            gc.setOutputDir(filePathJoin(outputDirPrefix,"java") );
        } else {
            // 设置代码生成在 D盘
            gc.setOutputDir(defaultOutputDir);
        }
        //生成完成后是否打开目录
        gc.setOpen(false);
        //启用swagger2注解
        gc.setSwagger2(true);
        gc.setFileOverride(true);
        // 不需要ActiveRecord特性的请改为false
        gc.setActiveRecord(false);
        // XML 二级缓存
        gc.setEnableCache(false);
        // XML ResultMap
        gc.setBaseResultMap(true);
        // XML columList
        gc.setBaseColumnList(true);
        // .setKotlin(true) 是否生成 kotlin 代码
        gc.setAuthor(author);
        gc.setServiceName("%sService");
        gc.setServiceImplName("%sServiceImpl");
        gc.setEntityName("%s"+entitySuffix);
        return gc;
    }


    /**
     * 数据源配置
     * @return: @return {@link DataSourceConfig }
     * @author: YPZ
     * @date: 2024-04-02
     */
    public static DataSourceConfig getDataSourceConfig() {
        // 数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setDbType(DbType.MYSQL);
        dsc.setDriverName(driverName);
        dsc.setUsername(username);
        dsc.setPassword(password);
        dsc.setUrl(jdbcUrl);
        dsc.setDbQuery(new MySqlQuery() {
            /**
             * 重写父类预留查询自定义字段
             * 这里查询的 SQL 对应父类 tableFieldsSql 的查询字段，默认不能满足你的需求请重写它
             * 模板中调用：  table.fields 获取所有字段信息，
             * 然后循环字段获取 field.customMap 从 MAP 中获取注入字段如下  NULL 或者 PRIVILEGES
             */
            @Override
            public String[] fieldCustom() {
                return new String[]{"DEFAULT"};
            }
        });
        return dsc;
    }

    /**
     * 包配置，用于指定生成的controller/service(impl)/entity/mapper/xml等输出的包位置
     * @return: @return {@link PackageConfig }
     * @author: YPZ
     * @date: 2024-04-02
     */
    public static PackageConfig getPackageConfig() {
        // 包配置
        PackageConfig pc = new PackageConfig();

        pc.setParent("");
        //可自定义修改包名
        pc.setController("com.storlead.sales.customer");
        pc.setService("com.storlead.sales.service.customer");
        pc.setServiceImpl("com.storlead.sales.service.impl.customer");
        pc.setMapper("com.storlead.sales.mapper.customer");
        pc.setXml("com.storlead.sales.mapper.customer.xml");
        pc.setEntity("com.storlead.sales.pojo.entity.customer");
        return pc;
    }

    /**
     * 模板配置，用于指定生成各类文件的模板，一般均采用默认模板，如果不需要自动生成哪一类文件，则向setter传null即可。
     * @return: @return {@link TemplateConfig }
     * @author: YPZ
     * @date: 2024-04-02
     */
    public static TemplateConfig getTemplateConfig() {
        // 配置模板
        TemplateConfig templateConfig = new TemplateConfig();
        // 关闭默认 xml 生成，调整生成 至 自定义目录
        templateConfig.setXml(null);
        return templateConfig ;
    }

    /**
     * 策略配置，用于设置各种生成策略和一些数据表策略
     * @return: @return {@link StrategyConfig }
     * @author: YPZ
     * @date: 2024-04-02
     */
    public static StrategyConfig getStrategyConfig(String[] tableNames) {
        // 策略配置
        StrategyConfig strategy = new StrategyConfig();
        //生成 lombok Model
        strategy.setEntityLombokModel(true);
        strategy.setControllerMappingHyphenStyle(true);

        //生成 restController
        strategy.setRestControllerStyle(true);
        // 表名生成策略
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);

        // 公共父类
        strategy.setSuperEntityClass(superEntityClass);
        // 写于父类中的公共字段
        strategy.setSuperEntityColumns("create_by","update_by","create_time","update_time","is_delete","enabled","owner_by","sort");
        strategy.setControllerMappingHyphenStyle(true);
        strategy.setEntityTableFieldAnnotationEnable(true);
        /**
         *  需要生成的表
         *
         */
        strategy.setInclude(tableNames);

        //修改继承类
        strategy.setSuperMapperClass("com.storlead.frame.mybatis.mapper.MyBaseMapper");
        strategy.setSuperServiceClass("com.storlead.frame.mybatis.service.MyBaseService");
        strategy.setSuperServiceImplClass("com.storlead.frame.mybatis.service.impl.MyBaseServiceImpl");

        return strategy;
    }

    /**
     * 自定义配置
     * @return: @return {@link InjectionConfig }
     * @author: YPZ
     * @date: 2024-04-02
     */
    public static InjectionConfig getInjectionConfig() {
        InjectionConfig cfg = new InjectionConfig() {
            @Override
            public void initMap() {
                Map<String, Object> map = new HashMap<String, Object>();

                //自定义配置，在模版中cfg.superColums 获取
                // TODO 这里解决子类会生成父类属性的问题，在模版里会用到该配置
                map.put("superColums", this.getConfig().getStrategyConfig().getSuperEntityColumns());

                this.setMap(map);
            }
        };
        // 如果模板引擎是 freemarker
        String templatePath = "/templates/mapper.xml.ftl";
        // 自定义输出配置
        List<FileOutConfig> focList = new ArrayList<>();
        // 自定义配置会被优先输出
        focList.add(new FileOutConfig(templatePath) {
            @Override
            public String outputFile(TableInfo tableInfo) {
                int len = tableInfo.getEntityName().length();
                String entityName = tableInfo.getEntityName().substring(0,len-entitySuffix.length());
                if (WRITE_FILE_TO_PROJECT) {
                    // 自定义输出文件名 ， 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化！！
//                    return outputDirPrefix+"com.storlead.tems.modules.console.mapper.xml";
                    return projectPath + customMapperPath +  entityName+ "Mapper" + StringPool.DOT_XML;
                } else {
                    //生成到D盘\java 目录
                    return "D:\\java\\resources\\mapper\\customer\\"+ entityName + "Mapper" + StringPool.DOT_XML;
                }
            }
        });
        //mapper.xml输出路径
        cfg.setFileOutConfigList(focList);
        return cfg;
    }


    /**
     * 文件路径拼接
     * @param paths 路径
     * @return: @return {@link String }
     * @author: YPZ
     * @date: 2024-04-02
     */
    public static String filePathJoin(String... paths) {
        StringBuffer sb = new StringBuffer();
        int i = 0;
        if (paths.length == 0) {
            return "";
        }
        for (i = 0; i < paths.length - 1; i++) {
            sb.append(paths[i] + File.separator);
        }
        sb.append(paths[i]);
        return sb.toString();
    }

    /**
     * @param startSeparator 开始分隔符
     * @param endSeparator   结束分隔符
     * @param paths          路径
     * @return: @return {@link String }
     * @author: YPZ
     * @date: 2024-04-02
     */
    public static String filePathJoinWithSeparator(String startSeparator,String endSeparator,String... paths){
        return startSeparator+filePathJoin(paths)+endSeparator;
    }
}
