package com.th.demo.service.impl.develop;

import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.th.demo.mapping.develop.DevBussinessTableMapper;
import com.th.demo.mapping.develop.DevTablePropertyMapper;
import com.th.demo.mapping.system.SysMenuMapper;
import com.th.demo.model.develop.DevBussinessTable;
import com.th.demo.model.develop.DevCodeMechine;
import com.th.demo.model.develop.DevTableProperty;
import com.th.demo.model.system.Type;
import com.th.demo.service.develop.CodeMachineService;
import com.th.demo.tools.CodeMachineTools;
import com.th.demo.tools.JSONTools;
import com.th.demo.tools.Tools;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.*;
import org.mybatis.generator.exception.InvalidConfigurationException;
import org.mybatis.generator.internal.DefaultShellCallback;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.*;
import java.sql.SQLException;
import java.util.*;

@Service("CodeMachineService")
public class CodeMachineServiceImpl implements CodeMachineService {
    @Autowired
    SysMenuMapper sysMenuMapper;
    @Autowired
    DevBussinessTableMapper devBussinessTableMapper;
    @Autowired
    DevTablePropertyMapper devTablePropertyMapper;



    int num;
    String result;


    @Override
    public String query(int page, int rows, String queryTableName) {
        PageHelper.startPage(page, rows);
        List<DevBussinessTable> list = devBussinessTableMapper.select(queryTableName);
        PageInfo<DevBussinessTable> pageInfo = new PageInfo<DevBussinessTable>(list);
        result = JSON.toJSONString(pageInfo);
        return result;
    }

    @Override
    public String remove(String id, String userId) {
        DevBussinessTable devBussinessTable = devBussinessTableMapper.selectByPrimaryKey(id);
        String tableName = devBussinessTable.getDbTableName();
        num += devTablePropertyMapper.deleteByTableName(tableName);
        num += devBussinessTableMapper.deleteByPrimaryKey(id);
        return JSON.toJSONString(Tools.moreThanZero(num));
    }

    @Override
    public String queryTableProperty(String bussinessName) {
        List<DevTableProperty> list = devTablePropertyMapper.selectByBussinessName(bussinessName);
        return JSON.toJSONString(list);
    }

    @Override
    public String queryBussiness(String processDefinitionId) {
        DevBussinessTable devBussinessTable = devBussinessTableMapper.selectByProcessDefinitionId(processDefinitionId);
        return JSONTools.toString(devBussinessTable);
    }


    @Override
    public String queryTableName() {
        List<String> list = sysMenuMapper.selectTableName();

        List<Map<String, Object>> listmap = new ArrayList<Map<String, Object>>();
        Map<String, Object> map;
        for (String name : list) {
            map = new HashMap<String, Object>();
            map.put("label", name);
            map.put("value", name);
            listmap.add(map);
        }
        return JSON.toJSONString(listmap);
    }

    @Override
    public String queryProcessName() {
//        List<Model> list = repositoryService.createModelQuery().orderByCreateTime().desc().list();
//
//        List<Map<String, Object>> listmap = new ArrayList<Map<String, Object>>();
//        Map<String, Object> map;
//        for (Model m : list) {
//            ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionKey(m.getKey()).latestVersion().singleResult();
//
//            map = new HashMap<String, Object>();
//            map.put("label", processDefinition.getName());
//            //map.put("value", processDefinition.getId());
//            map.put("value", processDefinition.getKey());
//            listmap.add(map);
//        }
//        return JSON.toJSONString(listmap);
        return null;
    }

    @Override
    public String generate(String id, String bussinessName, String dbTableName, String processName, String packageName, String moduleName, String userId) {
        //String packageName = "com.th.demo";
        // String fileName = "src/main/test/";
        //  String moduleName = "test";


        try {
//            ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionKey(processName).latestVersion().singleResult();
//            String defId = processDefinition.getId();
            List<DevBussinessTable> checkList = devBussinessTableMapper.selectByTableName(dbTableName);
            List<DevCodeMechine> dcmList = CodeMachineTools.feild2Property(devBussinessTableMapper.selectFeildByTableName(dbTableName));


            if (checkList != null && checkList.size() > 0) {
                DevBussinessTable devBussinessTable;
                devBussinessTable = devBussinessTableMapper.selectByPrimaryKey(id);
                devBussinessTable.setBussinessName(bussinessName);
                devBussinessTable.setDbTableName(dbTableName);
                devBussinessTable.setProcessName(processName);
                devBussinessTable.setPackageName(packageName);
                devBussinessTable.setModuleName(moduleName);
                devBussinessTable.setModifyId(userId);
                devBussinessTable.setModifyTime(new Date());
                num = devBussinessTableMapper.updateByPrimaryKey(devBussinessTable);
                result = "该表已经生成table列数据和form数据，仅生成文件！";
            } else {
                num = 0;
                result = "";
                DevBussinessTable devBussinessTable;

                if (id.equals("") || id == null) {
                    devBussinessTable = new DevBussinessTable();
                    devBussinessTable.setBussinessName(bussinessName);
                    devBussinessTable.setDbTableName(dbTableName);
                    devBussinessTable.setProcessName(processName);
                    devBussinessTable.setPackageName(packageName);
                    devBussinessTable.setModuleName(moduleName);
                    devBussinessTable.setAttr1("0");
                    devBussinessTable.setCancelFlag("0");

                    devBussinessTable.setAddId(userId);
                    devBussinessTable.setAddTime(new Date());
                    num = devBussinessTableMapper.insert(devBussinessTable);
                    if (num > 0) {
                        generateTableProperty(dbTableName, dcmList);
                    }
                } else {
                    devBussinessTable = devBussinessTableMapper.selectByPrimaryKey(id);
                    devBussinessTable.setBussinessName(bussinessName);
                    devBussinessTable.setDbTableName(dbTableName);
                    devBussinessTable.setProcessName(processName);
                    devBussinessTable.setPackageName(packageName);
                    devBussinessTable.setModuleName(moduleName);

                    devBussinessTable.setModifyId(userId);
                    devBussinessTable.setModifyTime(new Date());
                    num = devBussinessTableMapper.updateByPrimaryKey(devBussinessTable);
                    List<DevTableProperty> list = devTablePropertyMapper.selectByBussinessName(dbTableName);
                    if (list == null || list.size() == 0) {
                        generateTableProperty(dbTableName, dcmList);
                    }
                }
            }

            String modelName = CodeMachineTools.tableName2ModelName(dbTableName);
            String fileName = this.getClass().getClassLoader().getResource("").getPath();

            generateControllerService(packageName, fileName, moduleName, modelName, dcmList);
            generateModelMapper(packageName, fileName, dbTableName, moduleName, modelName);
            generateVue(dbTableName, fileName, moduleName, modelName);

            System.out.println("代码生成成功,路径:" + fileName + "generate/" + packageName.replace(".", "/"));

        } catch (Exception ex) {
            ex.printStackTrace();
            result = Type.FAIL + ex.getMessage();
        } finally {
            return result;
        }


    }


    private void generateTableProperty(String dbTableName, List<DevCodeMechine> dcmList) {
        for (int i = 0; i < dcmList.size(); i++) {
            DevCodeMechine dcm = dcmList.get(i);
            DevTableProperty devTableProperty = new DevTableProperty();
            devTableProperty.setTableName(dbTableName);
            devTableProperty.setTableField(dcm.getColumnName());
            devTableProperty.setTableProp(dcm.getPropertyName());
            devTableProperty.setTableLabel(dcm.getComments() == null ? dcm.getColumnName() : dcm.getComments());
            devTableProperty.setTableWidth("120");
            devTableProperty.setAttr1("0");
            devTableProperty.setSort(i);
            devTableProperty.setIsForm("0");
            devTableProperty.setFormSort(i + "");
            devTableProperty.setFormType("String");
            devTableProperty.setIsQuery("0");
            devTableProperty.setQuerySort(i + "");
            devTableProperty.setQueryType("String");
            devTablePropertyMapper.insert(devTableProperty);
        }

    }


    private void generateControllerService(String packageName,
                                           String fileName,
                                           String moduleName,
                                           String modelName,
                                           List<DevCodeMechine> list) throws IOException {
        Writer writerController = null;
        Writer writerService = null;
        Writer writerServiceImpl = null;
        try {
            String modelNameFirstLower = modelName.substring(0, 1).toLowerCase() + modelName.substring(1, modelName.length());
            String packagePath = packageName.replace(".", "/");

            String realPath = fileName + "generate/" + packagePath;
            String[] paths = {realPath + "/controller/" + moduleName, realPath + "/service/" + moduleName, realPath + "/service/impl/" + moduleName};
            for (int i = 0; i < paths.length; i++) {
                File dir = new File(paths[i]);
                if (!dir.exists()) {
                    dir.mkdirs();
                }
            }
            Configuration configuration = new Configuration(Configuration.VERSION_2_3_28);
            configuration.setDirectoryForTemplateLoading(new File(fileName + "template"));
            configuration.setDefaultEncoding("UTF-8");


            Template templateController = configuration.getTemplate("controller.ftl");
            Map<String, Object> paramMapController = new HashMap<String, Object>();
            paramMapController.put("packageName", packageName);
            paramMapController.put("moduleName", moduleName);
            paramMapController.put("modelName", modelName);
            paramMapController.put("modelNameFirstLower", modelNameFirstLower);
            paramMapController.put("list", list);
            //System.out.println("生成controller路径="+realPath + "/controller/" + moduleName + "/" + modelName + "Controller.java");
            writerController = new OutputStreamWriter(new FileOutputStream(realPath + "/controller/" + moduleName + "/" + modelName + "Controller.java"), "UTF-8");
            templateController.process(paramMapController, writerController);


            Template templateService = configuration.getTemplate("service.ftl");
            Map<String, Object> paramMapService = new HashMap<String, Object>();
            paramMapService.put("packageName", packageName);
            paramMapService.put("moduleName", moduleName);
            paramMapService.put("modelName", modelName);
            paramMapService.put("modelNameFirstLower", modelNameFirstLower);
            paramMapService.put("list", list);
            // System.out.println("生成service路径="+realPath + "/service/" + moduleName + "/" + modelName + "Service.java");
            writerService = new OutputStreamWriter(new FileOutputStream(realPath + "/service/" + moduleName + "/" + modelName + "Service.java"), "UTF-8");
            templateService.process(paramMapService, writerService);


            Template templateServiceImpl = configuration.getTemplate("serviceimpl.ftl");
            Map<String, Object> paramMapServiceImpl = new HashMap<String, Object>();
            paramMapServiceImpl.put("packageName", packageName);
            paramMapServiceImpl.put("moduleName", moduleName);
            paramMapServiceImpl.put("modelName", modelName);
            paramMapServiceImpl.put("modelNameFirstLower", modelNameFirstLower);
            paramMapServiceImpl.put("list", list);
            // System.out.println("生成serviceimpl路径="+realPath + "/service/impl/" + moduleName + "/" + modelName + "ServiceImpl.java");
            writerServiceImpl = new OutputStreamWriter(new FileOutputStream(realPath + "/service/impl/" + moduleName + "/" + modelName + "ServiceImpl.java"), "UTF-8");
            templateServiceImpl.process(paramMapServiceImpl, writerServiceImpl);
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            if (writerController != null) {
                writerController.close();
            }
            if (writerService != null) {
                writerService.close();
            }
            if (writerServiceImpl != null) {
                writerServiceImpl.close();
            }

        }

    }

    public String generateModelMapper(String packageName, String fileName, String tableName, String moduleName, String modelName) {
        String result = Type.FAIL;
        fileName = fileName.substring(1, fileName.length()) + "generate/";
        try {
            result = Type.FAIL;
            List<String> warnings = new ArrayList<String>();
            boolean overwrite = true;

            org.mybatis.generator.config.Configuration config = new org.mybatis.generator.config.Configuration();
            Context context = new Context(ModelType.CONDITIONAL);
            context.setId("defaultContext");
            context.setTargetRuntime("MyBatis3");
            //设置是否生成注释
            CommentGeneratorConfiguration commentGeneratorConfiguration = new CommentGeneratorConfiguration();
            commentGeneratorConfiguration.addProperty("suppressAllComments", "true");
            commentGeneratorConfiguration.addProperty("suppressDate", "true");
            context.setCommentGeneratorConfiguration(commentGeneratorConfiguration);

            //设置连接数据库
//                JDBCConnectionConfiguration jdbcConnectionConfiguration = new JDBCConnectionConfiguration();
//                jdbcConnectionConfiguration.setDriverClass("com.mysql.jdbc.Driver");
//                jdbcConnectionConfiguration.setConnectionURL("jdbc:mysql://localhost:3306/sb_01");
//                jdbcConnectionConfiguration.setPassword("root");
//                jdbcConnectionConfiguration.setUserId("root");
//                context.setJdbcConnectionConfiguration(jdbcConnectionConfiguration);

            JDBCConnectionConfiguration jdbcConnectionConfiguration = new JDBCConnectionConfiguration();
            jdbcConnectionConfiguration.setDriverClass("oracle.jdbc.driver.OracleDriver");
            jdbcConnectionConfiguration.setConnectionURL("jdbc:oracle:thin:@172.16.7.190:1521:devdb");
            jdbcConnectionConfiguration.setUserId("syb01");
            jdbcConnectionConfiguration.setPassword("xxhsyb");
            context.setJdbcConnectionConfiguration(jdbcConnectionConfiguration);

            JavaTypeResolverConfiguration javaTypeResolverConfiguration = new JavaTypeResolverConfiguration();
            //是否使用bigDecimal， false可自动转化以下类型（Long, Integer, Short, etc.）
            javaTypeResolverConfiguration.addProperty("forceBigDecimals", "false");
            context.setJavaTypeResolverConfiguration(javaTypeResolverConfiguration);

            //生成实体类的地址
            JavaModelGeneratorConfiguration javaModelGeneratorConfiguration = new JavaModelGeneratorConfiguration();
            javaModelGeneratorConfiguration.setTargetPackage(packageName + ".model." + moduleName);
            javaModelGeneratorConfiguration.setTargetProject(fileName);
            javaModelGeneratorConfiguration.addProperty("enableSubPackages", "false");
            javaModelGeneratorConfiguration.addProperty("trimStrings", "true");
            context.setJavaModelGeneratorConfiguration(javaModelGeneratorConfiguration);
            // System.out.println("生成model路径="+packageName + ".model."+moduleName);
            //生成的xml的地址
            SqlMapGeneratorConfiguration sqlMapGeneratorConfiguration = new SqlMapGeneratorConfiguration();
//            sqlMapGeneratorConfiguration.setTargetPackage("/");
//            sqlMapGeneratorConfiguration.setTargetProject("src/main/resource/mapper");
            sqlMapGeneratorConfiguration.setTargetPackage(packageName + ".mapper." + moduleName);
            sqlMapGeneratorConfiguration.setTargetProject(fileName);
            sqlMapGeneratorConfiguration.addProperty("enableSubPackages", "true");
            context.setSqlMapGeneratorConfiguration(sqlMapGeneratorConfiguration);
            // System.out.println("生成model路径="+packageName + ".mapper."+moduleName);
            //生成mapxml对应client，也就是接口dao
            JavaClientGeneratorConfiguration javaClientGeneratorConfiguration = new JavaClientGeneratorConfiguration();
            javaClientGeneratorConfiguration.setTargetPackage(packageName + ".mapping." + moduleName);
            javaClientGeneratorConfiguration.setTargetProject(fileName);
            javaClientGeneratorConfiguration.setConfigurationType("XMLMAPPER");
            javaClientGeneratorConfiguration.addProperty("enableSubPackages", "true");
            context.setJavaClientGeneratorConfiguration(javaClientGeneratorConfiguration);
            //  System.out.println("生成model路径="+packageName + ".mapping."+moduleName);

            TableConfiguration tableConfiguration = new TableConfiguration(context);
            tableConfiguration.setTableName(tableName);
            tableConfiguration.setDomainObjectName(modelName);
            //tableConfiguration.setSchema("SYB01");
            tableConfiguration.setCountByExampleStatementEnabled(false);
            tableConfiguration.setUpdateByExampleStatementEnabled(false);
            tableConfiguration.setDeleteByExampleStatementEnabled(false);
            tableConfiguration.setSelectByExampleStatementEnabled(false);

            context.addTableConfiguration(tableConfiguration);

            config.addContext(context);


            DefaultShellCallback callback = new DefaultShellCallback(overwrite);
            MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
            myBatisGenerator.generate(null);
            result = Type.SUCCESS;
            System.out.println("代码生成完毕>>>>>>>>>>>>model mapper");
        } catch (InvalidConfigurationException e) {
            result = Type.FAIL + e.getMessage();
            e.printStackTrace();
        } catch (InterruptedException e) {
            result = Type.FAIL + e.getMessage();
            e.printStackTrace();
        } catch (IOException e) {
            result = Type.FAIL + e.getMessage();
            e.printStackTrace();
        } catch (SQLException e) {
            result = Type.FAIL + e.getMessage();
            e.printStackTrace();
        } finally {
            return result;
        }


    }


    private void generateVue(String dbTableName, String fileName,
                             String moduleName,
                             String modelName) throws IOException {
        Writer writerVue = null;

        try {
            String modelNameFirstLower = modelName.substring(0, 1).toLowerCase() + modelName.substring(1, modelName.length());
            List<DevTableProperty> listForm = devTablePropertyMapper.selectForGenerateVueForm(dbTableName);
            String realPath = fileName + "generate/";
            String[] paths = {realPath + "/vue/"};
            for (int i = 0; i < paths.length; i++) {
                File dir = new File(paths[i]);
                if (!dir.exists()) {
                    dir.mkdirs();
                }
            }
            Configuration configuration = new Configuration(Configuration.VERSION_2_3_28);
            configuration.setDirectoryForTemplateLoading(new File(fileName + "template"));
            configuration.setDefaultEncoding("UTF-8");
            Template templateVue = configuration.getTemplate("vue.ftl");
            Map<String, Object> paramMapController = new HashMap<String, Object>();
            paramMapController.put("moduleName", moduleName);
            paramMapController.put("modelName", modelName);
            paramMapController.put("dbTableName", dbTableName);
            paramMapController.put("modelNameFirstLower", modelNameFirstLower);
            paramMapController.put("list", listForm);
            //System.out.println("生成controller路径="+realPath + "/controller/" + moduleName + "/" + modelName + "Controller.java");
            writerVue = new OutputStreamWriter(new FileOutputStream(realPath + "/vue/" +modelNameFirstLower + ".vue"), "UTF-8");
            templateVue.process(paramMapController, writerVue);


        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            if (writerVue != null) {
                writerVue.close();
            }

        }
    }
}
