package xyz.wbsite.dbtool.javafx.manger;

import org.springframework.boot.system.ApplicationHome;
import xyz.wbsite.dbtool.javafx.enums.DataBase;
import xyz.wbsite.dbtool.javafx.enums.FieldType;
import xyz.wbsite.dbtool.javafx.manger.callable.*;
import xyz.wbsite.dbtool.javafx.po.*;
import xyz.wbsite.dbtool.javafx.tool.Dialog;

import java.io.File;
import java.io.FilenameFilter;
import java.sql.*;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;

public class ProjectManager {

    public static boolean isUpdate = false;
    private XmlManager xmlService;
    public static AbstractDBmapper dBmapper;
    public static File path;
    private Project project = new Project();

    public ProjectManager() {
        xmlService = ManagerFactory.getXmlManager();
        try {
            ApplicationHome home = new ApplicationHome(getClass());
            File jarFile = home.getSource();
            this.path = new File(jarFile.getParent(), "project");
        } catch (Exception e) {
            e.printStackTrace();
            this.path = new File(System.getProperty("user.home"), "project");
        }
        invalidate();
    }

    public static File getPath() {
        return path;
    }

    public static void setPath(File path) {
        ProjectManager.path = path;
    }

    public void modelCreate() {
        project = new Project();
    }

    public Module findDBByDBName(String name) {
        for (Module md : project.getModules()) {
            if (md.getModuleName().equals(name)) {
                return md;
            }
        }
        return null;
    }

    public boolean removeDBByDBName(String name) {
        for (Module md : project.getModules()) {
            if (md.getModuleName().equals(name)) {
                project.getModules().remove(md);
                return true;
            }
        }
        return false;
    }

    public Table findTableByTableName(Module md, String name) {
        for (Table t : md.getTables()) {
            if (t.getTableName().equals(name)) {
                return t;
            }
        }
        return null;
    }

    public Table getNewTableName(Module md) {
        String base = "NEW_TABLE";
        String name = base;
        int k = 0;
        do {
            int i;
            for (i = 0; i < md.getTables().size(); i++) {
                if (name.equals(md.getTables().get(i).getTableName())) {
                    break;
                }
            }
            if (i < md.getTables().size()) {
                k++;
                name = base + "_" + k;
            } else {
                Table table = new Table(name);
                table.setTableComment("注释");
                table.setCreate(true);
                table.setDelete(true);
                table.setUpdate(true);
                table.setFind(true);
                table.setGet(true);
                table.setSearch(false);
                table.setGetAll(false);

                md.putTable(table);
                return table;
            }
        } while (true);
    }

    public String getNewModuleName() {
        String base = "example";
        String name = base;
        int k = 0;
        do {
            int i;
            for (i = 0; i < project.getModules().size(); i++) {
                if (name.equals(project.getModules().get(i).getModuleName())) {
                    break;
                }
            }
            if (i < project.getModules().size()) {
                k++;
                name = base + k;
            } else {
                Module md = new Module(name);
                md.setModuleName(name);
                md.setModuleComment("注释");
                project.putModule(md);
                return name;
            }
        } while (true);
    }

    public String getNewFieldName(List<Field> fields) {
        String base = "NEW_FIELD";
        String name = base;
        int k = 0;
        do {
            int i;
            for (i = 0; i < fields.size(); i++) {
                if (name.equals(fields.get(i).getFieldName())) {
                    break;
                }
            }
            if (i < fields.size()) {
                k++;
                name = base + "_" + k;
            } else {
                Field field = new Field(name);
                field.setDefaultValue("NULL");
                field.setIsQuery(false);
                field.setIsMust(false);
                field.setIsPrimaryKey(false);
                field.setFieldType(FieldType.String_var50);
                field.setFieldLength(FieldType.String_var50.getDefaultLength());
                int j = 0;
                for (; j < fields.size(); j++) {
                    if (fields.get(j).getFieldName().equals("ROW_VERSION")) {
                        break;
                    }
                }
                fields.add(j, field);
                return name;
            }
        } while (true);
    }

    public List<Module> getMds() {
        return project.getModules();
    }

    public Project getProject() {
        return project;
    }

    public boolean doCheck() {
        if (project.getProjectName() == null || "".equals(project.getProjectName())) {
            Dialog.showConfirmDialog("没有填写项目名!");
            return false;
        } else if (project.getProjectBasePackage() == null || "".equals(project.getProjectBasePackage())) {
            Dialog.showConfirmDialog("没有填写基本域名!");
            return false;
        } else if (project.getProjectAuthor() == null || "".equals(project.getProjectAuthor())) {
            Dialog.showConfirmDialog("没有填写作者!");
            return false;
        }
        for (Module md : project.getModules()) {
            if (md.getModuleName() == null || "".equals(md.getModuleName())) {
                Dialog.showConfirmDialog("项目" + project.getProjectName() + "没有填写模块名!");
                return false;
            } else if (md.getModuleComment() == null || "".equals(md.getModuleComment())) {
                Dialog.showConfirmDialog("项目" + project.getProjectName() + "没有模块注释!");
                return false;
            }
        }
        return true;
    }

    /**
     * 保存配置文件
     */
    public void save(File file) {
        xmlService.saveAs(file, project);
    }

    public void save() {
        xmlService.saveAs(path, project);
    }

    public void delete() {
        File file = new File(path, project.getProjectName() + ".xml");
        if (file.exists()) {
            file.delete();
        }
    }

    private static ExecutorService service = Executors.newFixedThreadPool(1);

    public void tryGetDBmapper(DataBase dataBase) {
        if (dataBase.name().equals(DataBase.MYSQL.name())) {
            dBmapper = new MySqlDBmapper(dataBase);
        } else if (dataBase.name().equals(DataBase.ORACLE.name())) {
            dBmapper = new OracleDBmapper(dataBase);
        }
    }

    /**
     * 生成模板 入口
     *
     * @param path
     */
    public void generate(final String path, final String option, final DataBase dataBase) {
        tryGetDBmapper(dataBase);

        File root = new File(path);
        if (!root.exists()) {
            Dialog.showTimedDialog(1000, "目录不存在!");
        }
        Dialog.showProgress("生成中...");
        new Thread() {
            @Override
            public void run() {
                Callable callback = null;
                switch (option) {
                    case "SpringBoot":
                        callback = new SpringBootCallable(path, dataBase, project, option, false);
                        break;
                    case "SpringBoot+Cloud":
                        callback = new SpringBootCallable(path, dataBase, project, "SpringBoot", true);
                        break;
                    case "SpringMVC_Mybatis":
                        callback = new SpringMVCMybatisCallable(path, dataBase, project, option);
                        break;
                    default:

                }

                Future submit = service.submit(callback);
                try {
                    submit.get();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (ExecutionException e) {
                    e.printStackTrace();
                }
                Dialog.stopPopup();
                Dialog.showSuccess("生成完成.");
            }
        }.start();
    }

    public void generateApi(File module, File sdk, List<Api> apis) {
        if (module.exists()) {
            Dialog.showProgress("生成中...");
            new Thread() {
                @Override
                public void run() {
                    boolean mkdirs = sdk.mkdirs();
                    File reqList = new File(module,"req");
                    File rspList = new File(module,"rsp");
                    File entList = new File(module, "ent");
                    File enumsList = new File(module, "enums");
                    SDKCallable sdkCallable = new SDKCallable(sdk, reqList, rspList, entList, enumsList, apis);
                    Future submit = service.submit(sdkCallable);
                    try {
                        Boolean b = (Boolean) submit.get();
                        if (!b) {
                            Dialog.showError("请确认目录结构是否存在或正确!");
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (ExecutionException e) {
                        e.printStackTrace();
                    }

                    Dialog.stopPopup();
                    Dialog.showSuccess("Api生成完成.");
                }
            }.start();
        }
    }

    public void generate(final String path, AndroidOption option) {
        Dialog.showProgress("生成中...");
        new Thread() {
            @Override
            public void run() {
                AndroidCallable androidCallable = new AndroidCallable(path, option);
                Future submit = service.submit(androidCallable);
                try {
                    Boolean b = (Boolean) submit.get();
                    if (!b) {
                        Dialog.showError("请确认目录结构是否存在或正确!");
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (ExecutionException e) {
                    e.printStackTrace();
                }

                Dialog.stopPopup();
                Dialog.showSuccess("Android生成完成.");
            }
        }.start();
    }

    public void generate(final String path, VueOption option) {
        Dialog.showProgress("生成中...");
        new Thread() {
            @Override
            public void run() {
                VueCallable vueCallable = new VueCallable(path, option);
                Future submit = service.submit(vueCallable);
                try {
                    Boolean b = (Boolean) submit.get();
                    if (!b) {
                        Dialog.showError("请确认目录结构是否存在或正确!");
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (ExecutionException e) {
                    e.printStackTrace();
                }

                Dialog.stopPopup();
                Dialog.showSuccess("Vue生成完成.");
            }
        }.start();
    }

    /**
     * 初始化模型树,当存在多个时,默认第一个
     */
    public void invalidate() {
        File[] files = path.listFiles(new FilenameFilter() {
            public boolean accept(File dir, String name) {
                return name.endsWith(".xml") || name.endsWith(".XML");
            }
        });

        if (files.length == 0) {
            project = xmlService.inflate(null);
        } else {
            project = xmlService.inflate(files[0]);
        }
    }

    /**
     * 初始化模型树,当存在多个时,默认第一个
     */
    public void invalidate(File xmlFile) {
        project = xmlService.inflate(xmlFile);
    }

    public static boolean testConnect(Map<String, String> properties) {

        String url = properties.get("url");
        String username = properties.get("username");
        String password = properties.get("password");
        String driverClassName = properties.get("driverClassName");

        try {
            //加载MySql的驱动类
            Class.forName(driverClassName);

            Connection cn = DriverManager.getConnection(url, username, password);
            cn.close();
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    public static boolean loadMD(Map<String, String> properties) {

        String type = properties.get("type");
        String url = properties.get("url");
        String username = properties.get("username");
        String password = properties.get("password");
        String driverClassName = properties.get("driverClassName");
        Connection cn = null;

        if ("Orcale".equals(type)) {
            try {
                dBmapper = new OracleDBmapper(DataBase.ORACLE);

                //加载驱动类
                Class.forName(driverClassName);
                cn = DriverManager.getConnection(url, username, password);

                Module md = new Module(username);
                //查询所有表
                Statement statement = cn.createStatement();
                ResultSet rs = statement.executeQuery("select t.table_name,c.comments from user_tables t LEFT JOIN user_tab_comments c ON t.table_name = c.table_name ORDER BY T .table_name");

                while (rs.next()) {
                    Table table = new Table(rs.getString("table_name"), rs.getString("comments"));
                    md.putTable(table);
                }

                for (Table table : md.getTables()) {
                    String sql = "SELECT T.*,CASE WHEN C.POSITION='1' THEN '1' ELSE '0' END PrimaryKey FROM(select A.COLUMN_ID,A.COLUMN_NAME,A.DATA_TYPE,A.DATA_LENGTH,A .DATA_PRECISION,A .DATA_SCALE,A.NULLABLE,A.DATA_DEFAULT,B.comments from user_tab_columns A ,user_col_comments B where A.Table_Name='" + table.getTableName() + "' AND B.Table_Name='" + table.getTableName() + "' AND A.COLUMN_NAME=B.COLUMN_NAME) T LEFT JOIN user_cons_columns C ON T.COLUMN_NAME = C.COLUMN_NAME AND POSITION = '1' AND C.Table_Name='" + table.getTableName() + "' ORDER BY T .COLUMN_ID";
                    ResultSet set = statement.executeQuery(sql);

                    while (set.next()) {
                        Field field = new Field();

                        field.setFieldName(set.getString("COLUMN_NAME"));

                        String data_type = set.getString("DATA_TYPE");
                        int data_length = set.getInt("DATA_LENGTH");
                        int data_precision = set.getInt("DATA_PRECISION");
                        int data_scale = set.getInt("DATA_SCALE");
                        field.setFieldType(dBmapper.getType(data_type, data_length, data_precision, data_scale));
                        field.setFieldLength(set.getInt("DATA_LENGTH"));
                        String nullable = set.getString("NULLABLE");
                        field.setDefaultValue(set.getString("DATA_DEFAULT"));
                        field.setFieldComment(set.getString("COMMENTS"));
                        if ("N".equals(nullable)) {
                            field.setIsMust(true);
                        } else {
                            field.setIsMust(false);
                        }
                        String primarykey = set.getString("PRIMARYKEY");
                        if ("1".equals(primarykey)) {
                            field.setIsPrimaryKey(true);
                        } else {
                            field.setIsPrimaryKey(false);
                        }
                        field.setIsQuery(false);

                        table.putField(field);
                    }
                }

                ManagerFactory.getdBManager().project.putModule(md);
                isUpdate = true;
                return true;
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    cn.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        } else if ("Mysql".equals(type)) {
            try {
                dBmapper = new MySqlDBmapper(DataBase.MYSQL);

                //加载驱动类
                Class.forName(driverClassName);
                cn = DriverManager.getConnection(url, username, password);

                String[] split = url.split("/");
                String dbName = split[split.length - 1];

                Module md = new Module(dbName);
                //查询所有表
                Statement statement = cn.createStatement();
                ResultSet rs = statement.executeQuery("SELECT TABLE_NAME,TABLE_COMMENT FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '" + dbName + "'");

                while (rs.next()) {
                    Table table = new Table(rs.getString("TABLE_NAME"), rs.getString("TABLE_COMMENT"));
                    md.putTable(table);
                }

                for (Table table : md.getTables()) {
                    String sql = "select COLUMN_NAME,COLUMN_COMMENT,COLUMN_KEY,COLUMN_DEFAULT,IS_NULLABLE,DATA_TYPE, COLUMN_TYPE,CHARACTER_MAXIMUM_LENGTH from information_schema.COLUMNS where table_name = '" + table.getTableName() + "' and table_schema = '" + dbName + "' ORDER BY ORDINAL_POSITION ASC";
                    ResultSet set = statement.executeQuery(sql);

                    while (set.next()) {
                        Field field = new Field();

                        field.setFieldName(set.getString("COLUMN_NAME"));

                        if ("NO".equals(set.getString("IS_NULLABLE"))) {
                            field.setIsMust(true);
                        } else {
                            field.setIsMust(false);
                        }

                        if ("PRI".equals(set.getString("COLUMN_KEY"))) {
                            field.setIsPrimaryKey(true);
                        } else {
                            field.setIsPrimaryKey(false);
                        }

                        String data_type = set.getString("DATA_TYPE");
                        int data_length = set.getInt("CHARACTER_MAXIMUM_LENGTH");
                        field.setFieldType(dBmapper.getType(data_type, data_length, 0, 0));
                        field.setFieldLength(0);
                        if ("varchar".equals(data_type) || "char".equals(data_type)) {
                            int length = Integer.parseInt(set.getString("CHARACTER_MAXIMUM_LENGTH"));
                            field.setFieldLength(length);
                        }

                        field.setDefaultValue(set.getString("COLUMN_DEFAULT"));
                        field.setFieldComment(set.getString("COLUMN_COMMENT"));

                        field.setIsQuery(false);

                        table.putField(field);
                    }
                }

                ManagerFactory.getdBManager().project.putModule(md);
                isUpdate = true;
                return true;
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (SQLException e) {
                e.printStackTrace();
            }

            return false;
        }
        return false;
    }
}