
const glob = require('glob');
const path = require('path');
const fs = require('fs');
const os = require('os');
const { exec } = require('child_process');
const { resolve, basename } = require('path');
const { VIEWHANDLE } = require('../config/defaultConfig.js')

module.exports = {
    generateRandomLetters(length = 3) {
        const letters = 'abcdefghijklmnopqrstuvwxyz';
        let randomLetters = '';

        for (let i = 0; i < length; i++) {
            const randomIndex = Math.floor(Math.random() * letters.length);
            randomLetters += letters[randomIndex];
        }

        return randomLetters;
    },
    async exitsFolder(reaPath) {
        const absPath = path.resolve(__dirname, reaPath);
        try {
            await fs.promises.stat(absPath)
        } catch (e) {
            // 不存在文件夹，直接创建 {recursive: true} 这个配置项是配置自动创建多个文件夹
            await fs.promises.mkdir(absPath, { recursive: true })
        }
    },
    RandomNumBoth(Min, Max) {
        var Range = Max - Min;
        var Rand = Math.random();
        var num = Min + Math.round(Rand * Range); //四舍五入
        return num - 1;
    },
    copyFile(from, to) {
        return new Promise(resolve => {
            const readStream = fs.createReadStream(from)
            const writeStream = fs.createWriteStream(to)
            readStream.pipe(writeStream)
            writeStream.on('finish', () => { resolve() })
            writeStream.on('error', (err) => {
                console.log(err, 'err')
                throw err
            })
        })

    },
    // 递归复制文件与文件夹
    checkDirectory(src, dst, callback = function () { }) {
        fs.access(dst, fs.constants.F_OK, (err) => {
            if (err) {
                fs.mkdirSync(dst, { recursive: true });
                callback(src, dst);
            } else {
                callback(src, dst);
            }
        });

    },
    copyDir(src, dist, blackKeys = [], callback = function () { }) {
        fs.access(dist, function (err) {
            if (err) {
                // 目录不存在时创建目录
                fs.mkdirSync(dist);
            }
            _copy(null, src, dist);
        });

        function _copy(err, src, dist) {
            if (err) {
                callback(err);
            } else {
                fs.readdir(src, function (err, paths) {
                    if (err) {
                        callback(err)
                    } else {
                        paths.forEach(function (path) {
                            var _src = src + '/' + path;
                            var _dist = dist + '/' + path;
                            fs.stat(_src, function (err, stat) {
                                const fileName = basename(_src);

                                if (err) {
                                    callback(err);
                                } else {
                                    // 判断是文件还是目录
                                    if (stat.isFile()) {
                                        const fileName = basename(_src);
                                        if (!blackKeys.includes(fileName)) {
                                            fs.writeFileSync(_dist, fs.readFileSync(_src));
                                        }
                                    } else if (stat.isDirectory()) {
                                        if (!blackKeys.includes(fileName)) {
                                            // 当是目录是，递归复制
                                            module.exports.copyDir(_src, _dist, blackKeys, callback)
                                        }

                                    }
                                }
                            })
                        })
                    }
                })
            }
        }
    },
    /**
     * 下载远程仓库的项目
     * @param {*} path 远程仓库地址
     * @param {*} to 下载的目录
     * @param {*} localFolderName 下载后的仓库别名
     */
    downloadGit(path, to, localFolderName = '', branch = 'master') {
        return new Promise((resolve, reject) => {
            module.exports.mkdirsSync(to)
            console.log(`clone ${path}`)
            exec(`git clone -b ${branch} ${path} ${localFolderName}`, { cwd: `${to}` }, function (error, stdout, stderr) {
                if (error !== null) {
                    console.log('exec error: ' + error);
                    reject();
                } else {
                    console.log(`clone ${path} success！`);
                    resolve();
                }
            })
        })
    },
    /**
     * 递归创建文件夹
     * @param {*} dirname 
     * @returns 
     */
    mkdirsSync(dirname) {
        if (fs.existsSync(dirname)) {
            return true;
        } else {
            if (module.exports.mkdirsSync(path.dirname(dirname))) {
                fs.mkdirSync(dirname);
                return true;
            }
        }
    },
    /**
     * 删除文件夹
     * @param {*} url 
     */
    deleteFolderRecursive(url) {
        let files = [];
        /**
         * 判断给定的路径是否存在
         */
        if (fs.existsSync(url)) {
            /**
             * 返回文件和子目录的数组
             */
            files = fs.readdirSync(url);
            files.forEach(function (file, index) {

                const curPath = path.join(url, file);
                console.log(curPath);
                /**
                 * fs.statSync同步读取文件夹文件，如果是文件夹，在重复触发函数
                 */
                if (fs.statSync(curPath).isDirectory()) { // recurse
                    module.exports.deleteFolderRecursive(curPath);

                } else {
                    fs.unlinkSync(curPath);
                }
            });
            /**
             * 清除文件夹
             */
            fs.rmdirSync(url);

        } else {
            console.log("给定的路径不存在，请给出正确的路径");
        }
    },
    /**
     * 将以逗号分隔的字符串转换为url形式
     * 如 a,b,c 会转换为 a=a&b=b&c=c
     * @param {*} el 
     * @returns 
     */
    strToUrlEncode(el) {
        let newEl = ''
        el.split(',').forEach(item => {
            newEl += `${item}=\$\{${item}\}&`
        })
        return newEl
    },
    /**
   * 将以逗号分隔的字符串转换为body形式
   * 如 a,b,c 会转换为 { a:a,b:b,c:c }
   * @param {*} el 
   * @returns 
   */
    strToBody(el) {


    },
    /**
     * 时间格式化
     * @param {*} date 
     * @param {*} op 
     * @param {*} type 
     * @returns 
     */
    getDate(date, op = '-', type = 'en') {
        let year = (date.getFullYear()).toString()
        let month = (date.getMonth() + 1).toString()
        let day = (date.getDate()).toString()
        let hour = (date.getHours()).toString()
        let min = (date.getMinutes()).toString()
        let sec = (date.getSeconds()).toString()
        if (month.length < 2) {
            month = '0' + month
        }
        if (day.length < 2) {
            day = '0' + day
        }
        if (hour.length < 2) hour = '0' + hour
        if (min.length < 2) min = '0' + min
        if (sec.length < 2) sec = '0' + sec
        // if (type == 'com') {
        //   return `${year}-${month}-${day}`
        // }else {
        //   return `${year}-${month}-${day} ${hour}:${min}:${sec}`
        // }
        if (type == 'en') {
            return `${year}${op}${month}${op}${day}`
        } else {
            return `${year}年${month}月${day}日`
        }

    },
    /**
     * 首字母大写
     * @param {*} str 
     * @returns 
     */
    firstWordToUppercase(str) {
        var reg = /\b(\w)|\s(\w)/g; //  \b判断边界\s判断空格
        return str.replace(reg, function (m) {
            return m.toUpperCase()
        });
    },
    /**
     * 递归创建文件夹并写入文件
     * @param {*} path 
     * @param {*} buffer 
     * @param {*} callback 
     */
    writeFileRecursive(path, buffer, callback) {
        let lastPath = path.substring(0, path.lastIndexOf("/"));
        fs.mkdir(lastPath, { recursive: true }, (err) => {
            if (err) return callback(err);
            fs.writeFile(path, buffer, function (err) {
                if (err) return callback(err);
                return callback(null);
            });
        });
    },
    awaitMe(delay = 500) {
        return new Promise(res => {
            setTimeout(() => {
                res()
            }, delay);
        })
    },
    // 获取模型中需要进行条件筛选的字段
    getModelFilters(model) {
        // Text,select,manyselect,singleDate,date,doubleDate,
        /**
         * filter {
         *  type,
         *  label,
         *  sign 
         * }
         */
        const filters = {}
        const modelFields = model.fields
        for (const key in modelFields) {
            const filed = modelFields[key]
            if (filed.filter) {

                if (typeof filed.filter == 'boolean') {
                    filed.filter = {}
                }

                const filterContent = filed.filter
                filterContent.type || (filterContent.type = filed.meta.formType)
                filterContent.label || (filterContent.label = filed.comment)
                filterContent.meta = filed.meta
                filterContent.hidden = filed.hidden
                filters[key] = filterContent

            }
        }

        return filters
    },
    // 获取代码生成器需要的基本信息
    getGerneratorInitData(projectRoot, arg = {}, model = '') {
        const permissionFolder = arg.language == 'nodejs' ? `${arg.projectName}-server` : `${arg.projectName}-permission`
        const root = `${projectRoot}/`
        const serverRoot = root + permissionFolder

        const viewRoot = `${root}${arg.projectName}-view/`
        const screenRoot = `${root}${arg.projectName}-screen/`
        const screenConfig = `${root}/echarts.json`
        const modelConfigRoot = `${projectRoot}/modelConf`;
        const modelFiles = model == '' ? '*_model.js' : `${model}_model.js`

        const nodejsModelRoot = `${serverRoot}/business`;
        const nodejsControllerRoot = `${serverRoot}/controllers`;

        const javaRoot = `${projectRoot}/${arg.projectName}-server/src/main/java/com/work/project`
        const javaResource = `${projectRoot}/${arg.projectName}-server/src/main/resources`
        const javaBeanRoot = `${javaRoot}/bean`
        const javaDtoRoot = `${javaRoot}/dto`
        const javaMapperRoot = `${javaRoot}/mapper`
        const javaServiceRoot = `${javaRoot}/service`
        const javaServiceImplRoot = `${javaRoot}/service/impl`
        const javaControllerRoot = `${javaRoot}/controller`




        const ssmRoot = `${projectRoot}/${arg.projectName}-server/src/main/java/com/cyy/maven/core`
        const ssmResource = `${projectRoot}/${arg.projectName}-server/src/main/resources`
        const ssmEntityRoot = `${ssmRoot}/entity`
        const ssmDtoRoot = `${ssmRoot}/dto`
        const ssmDaoRoot = `${ssmRoot}/dao`
        const ssmControllerRoot = `${javaRoot}/controller`
        const ssmServiceRoot = `${ssmRoot}/service`
        const ssmServiceImplRoot = `${ssmRoot}/service/impl`
        const ssmMapperRoot = `${ssmResource}/mappers`

        const phpMainRoot = `${projectRoot}/${arg.projectName}-server`;
        const phpModelRoot = `${projectRoot}/${arg.projectName}-server/app`;
        const phpControllerRoot = `${projectRoot}/${arg.projectName}-server/app/Http/Controllers`;
        const phpMigrationRoot = `${projectRoot}/${arg.projectName}-server/database/migrations`;
        const phpRouterRoot = `${projectRoot}/${arg.projectName}-server/routes`;

        const pythonBeanRoot = `${projectRoot}/${arg.projectName}-server/work/bean`;
        const pythonControllerRoot = `${projectRoot}/${arg.projectName}-server/work/controller`;
        const pythonMainRoot = `${projectRoot}/${arg.projectName}-server/djangoProject`

        const appRoot = `${arg.projectName}-app`
        const appApiRoot = `${arg.projectName}-app/api`
        const appMixinRoot = `${arg.projectName}-app/mixins`
        let models = glob.sync(`${modelConfigRoot}/**/${modelFiles}`); // 模型配置文件
        const absoluteRoot = os.platform() === 'win32' ? modelConfigRoot.replace(/\\/ig, '/') : modelConfigRoot;

        // 去除系统模型配置文件
        // models = models.filter(item => {
        //     if (!item.includes('uc')) return item
        // })
        return {
            projectRoot,
            serverRoot,
            viewRoot,
            screenRoot,
            screenConfig,
            nodejsModelRoot,
            nodejsControllerRoot,
            modelConfigRoot,
            modelFiles,
            models,
            arg,
            absoluteRoot,
            javaRoot,
            javaResource,
            javaBeanRoot,
            javaDtoRoot,
            javaMapperRoot,
            javaServiceRoot,
            javaServiceImplRoot,
            javaControllerRoot,
            phpMainRoot,
            phpModelRoot,
            phpControllerRoot,
            phpMigrationRoot,
            phpRouterRoot,
            pythonBeanRoot,
            pythonControllerRoot,
            pythonMainRoot,
            appRoot,
            appApiRoot,
            appMixinRoot,

            ssmRoot,
            ssmResource,
            ssmEntityRoot,
            ssmDtoRoot,
            ssmDaoRoot,
            ssmControllerRoot,
            ssmServiceRoot,
            ssmServiceImplRoot,
            ssmMapperRoot,
        }
    },
    arrToQuery(model, whereArr, type = 'body', appendStr = '') {
        let whereStr = `{`
        whereArr.forEach(item => {
            if (!model.fields[item]) {
                console.log(`字段${item}不在模型${model.modelCn}上`)
                return;
            }
            const fieldDefaultValue = model.fields[item].defaultValue
            const fileItem = fieldDefaultValue ? `ctx.request.${type}.${item} ?? ${fieldDefaultValue}` : `ctx.request.${type}.${item}`
            whereStr += `
            ${item}: ${fileItem},`
        })
        whereStr += `${appendStr}
        }`
        return whereStr
    },
    arrToExpressQuery(model, whereArr, type = 'body', appendStr = '') {
        let whereStr = `{`
        whereArr.forEach(item => {
            if (!model.fields[item]) {
                console.log(`字段${item}不在模型${model.modelCn}上`)
                return;
            }
            const fieldDefaultValue = model.fields[item].defaultValue
            const fileItem = fieldDefaultValue ? `req.${type}.${item} ?? ${fieldDefaultValue}` : `req.${type}.${item}`
            whereStr += `
            ${item}: ${fileItem},`
        })
        whereStr += `${appendStr}
        }`
        return whereStr
    },
    toHump(name) {
        return name.toLocaleLowerCase().replace(/\_(\w)/g, function (all, letter) {
            return letter.toUpperCase();
        });
    },
    /**
    *深度合并多个对象的方法
    */
    deepAssign() {
        function isPlainObject(obj) {
            return typeof obj === 'object' && Object.prototype.toString.call(obj) === '[object Object]'
        }
        let len = arguments.length, target = arguments[0]
        if (!isPlainObject(target)) {
            target = {}
        }
        for (let i = 1; i < len; i++) {
            let source = arguments[i]
            if (isPlainObject(source)) {
                for (let s in source) {
                    if (s === '__proto__' || target === source[s]) {
                        continue
                    }
                    if (isPlainObject(source[s])) {
                        target[s] = module.exports.deepAssign(target[s], source[s])
                    } else {
                        target[s] = source[s]
                    }
                }
            }
        }
        return target
    },
    ObjectToQuery(obj) {
        // 首先判断obj是否为真，为真则进行处理，不然直接return
        if (obj) {
            // 定义变量接收query字符串
            let query = ""
            // 循环遍历对象
            for (let i in obj) {
                // 定义变量接收对象的value值
                let value = obj[i]
                // 若对象的value值为数组，则进行join打断
                if (Array.isArray(value)) {
                    value = value.join(",")
                }
                // 进行字符串拼接
                query += `&${i}=${value}`
            }
            // replace返回一个新的字符串，要用query重新接受一下，并把第一个&替换为?
            query = query.replace('&', '?')
            // 返回生成的query字符串
            return query
        }
        return ""
    },
    // 写入文件 如果文件夹不存在则创建文件夹
    fwriteFileByUser(filePath, data) {
        if (fs.existsSync(filePath)) {
        } else {
            module.exports.mkdir(filePath);
        }
        fs.writeFile(filePath, data, (err) => {
            if (err) {
                console.log(err);
            } else {
                console.log('成功写入文件：' + filePath)
            }
        })

    }
    , mkdir(filePath) {
        const dirCache = {};
        const arr = filePath.split('/');
        let dir = arr[0];
        for (let i = 1; i < arr.length; i++) {
            if (!dirCache[dir] && !fs.existsSync(dir)) {
                dirCache[dir] = true;
                fs.mkdirSync(dir);
            }
            dir = dir + '/' + arr[i];
        }
        fs.writeFileSync(filePath, '')
    },
    deleteLastField(myString,op=',') {

        // 找到最后一个逗号的索引
        let lastCommaIndex = myString.lastIndexOf(op);

        // 如果找到了逗号，就删除它及其之后的内容
        if (lastCommaIndex !== -1) {
            myString = myString.slice(0, lastCommaIndex);
        }
        return myString


    }
}