package com.ruoyi.generator.utils;

import org.apache.commons.lang3.StringUtils;
import org.apache.velocity.VelocityContext;
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.internal.DefaultShellCallback;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 * @author Cesar
 * @date 2017/1/10
 * @desc 代码生成类
 */
public class MybatisGeneratorUtil {

    /**
     * generatorConfig模板路径
     */
    private static String generatorConfig_vm = "/template/generatorConfig.vm";
    /**
     * Service模板路径
     */
    private static String service_vm = "/template/Service.vm";
    /**
     * ServiceImpl模板路径
     */
    private static String serviceImpl_vm = "/template/ServiceImpl.vm";

    private static String WIN = "win";

    /**
     * 根据模板生成generatorConfig.xml文件
     *
     * @param jdbcDriver   驱动路径
     * @param jdbcUrl      链接
     * @param jdbcUsername 帐号
     * @param jdbcPassword 密码
     * @param module       项目模块
     * @param database     数据库
     * @param tablePrefix  表前缀
     * @param packageName  包名
     */
    public static void generator(
            String jdbcDriver,
            String jdbcUrl,
            String jdbcUsername,
            String jdbcPassword,
            String module,
            String database,
            String tablePrefix,
            String packageName,
            String tableName,
            Map<String, String> lastInsertIdTables) throws Exception {

        String os = System.getProperty("os.name");
        if (os.toLowerCase().startsWith(WIN)) {
            generatorConfig_vm = MybatisGeneratorUtil.class.getResource(generatorConfig_vm).getPath().replaceFirst("/", "");
            service_vm = MybatisGeneratorUtil.class.getResource(service_vm).getPath().replaceFirst("/", "");
            serviceImpl_vm = MybatisGeneratorUtil.class.getResource(serviceImpl_vm).getPath().replaceFirst("/", "");
        } else {
            generatorConfig_vm = MybatisGeneratorUtil.class.getResource(generatorConfig_vm).getPath();
            service_vm = MybatisGeneratorUtil.class.getResource(service_vm).getPath();
            serviceImpl_vm = MybatisGeneratorUtil.class.getResource(serviceImpl_vm).getPath();
        }

        String targetProject = module;
        String basePath = MybatisGeneratorUtil.class.getResource("/").getPath().replace("/target/classes/", "").replace(targetProject, "").replaceFirst("/", "");
        basePath = "/" + basePath;//mac电脑加/
        String generatorConfigXml = MybatisGeneratorUtil.class.getResource("/").getPath().replace("/target/classes/", "") + "/src/main/resources/generatorConfig.xml";
        targetProject = basePath + targetProject;
        String sql = "SELECT table_name FROM INFORMATION_SCHEMA.TABLES WHERE table_schema = '" + database + "' AND table_name LIKE '" + tablePrefix + "_%';";

        System.out.println("========== 开始生成generatorConfig.xml文件 ==========");
        List<Map<String, Object>> tables = new ArrayList<>();
        try {
            VelocityContext context = new VelocityContext();
            Map<String, Object> table;

            // 查询定制前缀项目的所有表
            JdbcUtil jdbcUtil = new JdbcUtil(jdbcDriver, jdbcUrl, jdbcUsername, jdbcPassword);
            List<Map> result = jdbcUtil.selectByParams(sql, null);
            for (Map map : result) {
                table = new HashMap<>(2);
                table.put("table_name", map.get("TABLE_NAME"));
                table.put("model_name", lineToHump(Objects.toString(map.get("TABLE_NAME"))));
                if (map.get("TABLE_NAME").toString().equals(tableName)) {
                    tables.add(table);
                    System.out.println(map.get("TABLE_NAME"));
                }
            }
            jdbcUtil.release();

            context.put("tables", tables);
            context.put("generator_javaModelGenerator_targetPackage", packageName + ".model");
            context.put("generator_sqlMapGenerator_targetPackage", packageName + ".mapper");
            context.put("generator_javaClientGenerator_targetPackage", packageName + ".mapper");
            context.put("targetProject", targetProject);
            context.put("targetProject_sqlMap", targetProject);
            context.put("generator_jdbc_password", jdbcPassword);
            context.put("last_insert_id_tables", lastInsertIdTables);
            VelocityUtil.generate(generatorConfig_vm, generatorConfigXml, context);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("========== 结束生成generatorConfig.xml文件 ==========");

        System.out.println("========== 开始运行MybatisGenerator ==========");
        List<String> warnings = new ArrayList<>();
        File configFile = new File(generatorConfigXml);
        ConfigurationParser cp = new ConfigurationParser(warnings);
        Configuration config = cp.parseConfiguration(configFile);
        DefaultShellCallback callback = new DefaultShellCallback(true);
        MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
        myBatisGenerator.generate(null);
        for (String warning : warnings) {
            System.out.println(warning);
        }
        System.out.println("========== 结束运行MybatisGenerator ==========");

//        System.out.println("========== 开始生成Service ==========");
//        String ctime = new SimpleDateFormat("yyyy/M/d").format(new Date());
//        String servicePath = basePath + module + "/src/main/java/" + packageName.replaceAll("\\.", "/") + "/service/api";
//        String serviceImplPath = basePath + module + "/src/main/java/" + packageName.replaceAll("\\.", "/") + "/service/impl";
//        for (int i = 0; i < tables.size(); i++) {
//            String model = lineToHump(Objects.toString(tables.get(i).get("table_name")));
//            String service = servicePath + "/" + model + "Service.java";
//            String serviceImpl = serviceImplPath + "/" + model + "ServiceImpl.java";
//            // 生成service
//            File serviceFile = new File(service);
//            if (!serviceFile.exists()) {
//                VelocityContext context = new VelocityContext();
//                context.put("package_name", packageName);
//                context.put("model", model);
//                context.put("ctime", ctime);
//                VelocityUtil.generate(service_vm, service, context);
//                System.out.println(service);
//            }
//            // 生成serviceImpl
//            File serviceImplFile = new File(serviceImpl);
//            if (!serviceImplFile.exists()) {
//                VelocityContext context = new VelocityContext();
//                context.put("package_name", packageName);
//                context.put("model", model);
//                context.put("mapper", toLowerCaseFirstOne(model));
//                context.put("ctime", ctime);
//                VelocityUtil.generate(serviceImpl_vm, serviceImpl, context);
//                System.out.println(serviceImpl);
//            }
//        }
//        System.out.println("========== 结束生成Service ==========");
    }

    private static Pattern linePattern = Pattern.compile("_(\\w)");

    /**
     * 下划线转驼峰
     *
     * @param str
     * @return
     */
    private static String lineToHump(String str) {
        if (null == str || "".equals(str)) {
            return str;
        }
        str = str.toLowerCase();
        Matcher matcher = linePattern.matcher(str);
        StringBuffer sb = new StringBuffer();
        while (matcher.find()) {
            matcher.appendReplacement(sb, matcher.group(1).toUpperCase());
        }
        matcher.appendTail(sb);

        str = sb.toString();
        str = str.substring(0, 1).toUpperCase() + str.substring(1);

        return str;
    }

    /**
     * 首字母转小写
     *
     * @param s
     * @return
     */
    public static String toLowerCaseFirstOne(String s) {
        if (StringUtils.isBlank(s)) {
            return s;
        }
        if (Character.isLowerCase(s.charAt(0))) {
            return s;
        } else {
            return (new StringBuilder()).append(Character.toLowerCase(s.charAt(0))).append(s.substring(1)).toString();
        }
    }


}
