// 引入Node.js的mysql模块，用于与MySQL数据库进行交互（虽然此处只是引入，后续具体使用情况暂未明确体现）
require('mysql');
// 引入Node.js的文件系统模块fs，用于对文件进行读写等操作
var fs = require("fs");
// 引入orm模块，可能用于对象关系映射（Object Relational Mapping）相关操作，方便在Node.js中操作数据库
var orm = require("orm");
// 引入bluebird模块，用于提供更强大的Promise功能，便于处理异步操作
var Promise = require("bluebird");
// 引入path模块，用于处理文件路径相关的操作
var path = require("path");

/*
 * initialize函数用于初始化数据库相关的配置以及加载ORM（对象关系映射）模型，
 * 它接收应用程序环境对象、回调函数作为参数，通过一系列操作完成数据库连接和模型加载，
 * 并在操作完成后通过回调函数返回相应结果。
 * 
 * @param {Object} app - 应用程序环境对象，通常包含了应用的一些全局配置和上下文信息，可用于挂载数据库实例、模型等相关对象。
 * @param {Function} callback - 回调函数，在数据库初始化及模型加载完成（成功或失败）后被调用，用于传递操作结果等信息。
 */
function initialize(app, callback) {
    // 加载配置文件，通过config模块（这里应该是自定义的配置管理模块）获取名为"db_config"的配置信息
    var config = require('config').get("db_config");

    // 从配置信息中提取数据库相关的配置参数，构建一个包含协议、主机、数据库名称、端口、用户名、密码以及查询相关配置（启用连接池、开启调试模式）的对象opts
    var opts = {
        protocol: config.get("protocol"),
        host: config.get("host"),
        database: config.get("database"),
        port: config.get("port"),
        user: config.get("user"),
        password: config.get("password"),
        query: { pool: true, debug: true }
    };

    // 在控制台打印数据库连接参数，将opts对象转换为JSON字符串格式输出，方便查看配置情况
    console.log("数据库连接参数 %s", JSON.stringify(opts));

    // 使用orm模块的express方法初始化ORM模型，将数据库配置参数opts以及一个包含define函数的对象作为参数传入
    app.use(orm.express(opts, {
        define: function (db, models, next) {
            // 将数据库实例db挂载到应用程序环境对象app上，方便在其他地方访问数据库实例
            app.db = db;
            // 同时也将数据库实例挂载到全局对象global上，命名为database，不过使用全局变量需要谨慎，避免命名冲突等问题
            global.database = db;

            // 获取映射文件的路径，通过拼接当前工作目录和"/models"来确定模型文件所在的文件夹路径
            var modelsPath = path.join(process.cwd(), "/models");

            // 使用文件系统模块的readdir方法读取指定路径下的所有文件（即模型文件），读取完成后会调用回调函数处理结果
            fs.readdir(modelsPath, function (err, files) {
                // 创建一个数组，用于存放所有加载模型的异步函数，每个元素对应一个模型文件的加载操作
                var loadModelAsynFns = new Array();
                // 以下循环遍历读取到的所有文件，准备加载每个模型文件对应的模型定义（通过db.loadAsync方法异步加载）
                // console.log("开始加载 ORM 模型层文件 ");
                for (var i = 0; i < files.length; i++) {
                    var modelPath = modelsPath + "/" + files[i];
                    // console.log("加载模型 %s", modelPath);
                    // 将每个模型文件的异步加载函数存入数组中，后续会统一处理这些异步加载操作
                    loadModelAsynFns[i] = db.loadAsync(modelPath);
                }

                // 使用Promise.all方法来并行处理所有模型文件的加载操作，当所有加载操作都成功完成后，执行then回调函数
                Promise.all(loadModelAsynFns)
                   .then(function () {
                        // console.log("ORM 模型加载完成");
                        // 遍历数据库实例中已加载的所有模型，将每个模型挂载到models对象上，方便统一管理和访问
                        for (var modelName in db.models) {
                            models[modelName] = db.models[modelName];
                        }
                        // 将包含所有模型的models对象挂载到应用程序环境对象app上，方便在应用中使用模型进行数据库操作
                        app.models = models;
                        // 调用传入的回调函数，传递null表示操作成功完成，无错误信息
                        callback(null);
                        // 执行next函数，用于告知orm模块相关操作已完成，可继续后续流程（具体取决于orm模块的设计和使用方式）
                        next();
                    })
                   .catch(function (error) {
                        // 如果在加载模型过程中出现错误，在控制台打印错误信息，同时调用回调函数并传递错误对象，告知调用者操作失败
                        console.error('加载模块出错 error: ' + err);
                        callback(error);
                        // 同样执行next函数，告知orm模块相关流程结束（即便出现错误）
                        next();
                    });
            });
        }
    }));
}

// 将initialize函数作为模块的一个属性暴露出去，方便其他模块引入并调用该函数进行数据库初始化操作
module.exports.initialize = initialize;

// 定义一个函数用于获取全局的数据库实例对象，通过返回global对象上挂载的database属性（在initialize函数中进行挂载的）来实现
module.exports.getDatabase = function () {
    return global.database;
}