// 引入Node.js的path模块，用于处理文件路径相关操作
var path = require('path');
// 原本要引入的roles控制器模块，此处被注释掉了，可能后续会按需启用
// var roles_controller = require("../controllers/roles");

// 再次引入path模块，前面的引入语句重复了，但在Node.js中不会有实质影响，可考虑优化掉重复引入的情况
var path = require("path");

// 创建一个全局对象service_caches，用于缓存服务相关的模块或数据，初始为空对象
global.service_caches = {};

// 创建一个全局变量service_auth_fn，用于存储全局验证函数，初始值为null
global.service_auth_fn = null;

/**
 * Invocation函数用于构造一个回调对象格式，主要用于在调用服务的具体方法时进行权限验证等相关操作。
 * 
 * @param {[type]} serviceName   服务名称，用于标识具体是哪个服务。
 * @param {[type]} actionName    动作名称（方法名），对应服务模块里具体的函数名称。
 * @param {[type]} serviceModule 服务模块，即通过require加载进来的包含具体业务逻辑函数的模块对象。
 * @param {[type]} origFunc      原始方法，也就是服务模块里未经包装的原始业务逻辑函数。
 */
function Invocation(serviceName, actionName, serviceModule, origFunc) {
    // 返回一个新的函数，这个函数会接收一些参数（此处未在形参中体现，在调用时会传入），并返回另一个函数作为真正的回调函数
    return function () {
        var origArguments = arguments;
        return function (req, res, next) {
            // 判断全局验证函数是否存在，如果存在则进行权限验证流程
            if (global.service_auth_fn) {
                global.service_auth_fn(req, res, next, serviceName, actionName, function (pass) {
                    // 如果权限验证通过（pass为true），则执行原始的业务逻辑函数
                    if (pass) {
                        origFunc.apply(serviceModule, origArguments);
                    } else {
                        // 如果权限验证失败，向客户端返回相应的错误信息，状态码为401表示未授权
                        res.sendResult(null, 401, "权限验证失败");
                    }
                });
            } else {
                // 如果全局验证函数不存在，直接返回权限验证失败的错误信息给客户端
                res.sendResult(null, 401, "权限验证失败");
            }
        }
    }
}

// 定义一个函数用于获取服务对象，它是模块对外暴露的接口之一
module.exports.getService = function (serviceName) {
    // 先检查全局缓存中是否已经存在指定名称的服务对象，如果存在则直接返回缓存中的服务对象
    if (global.service_caches[serviceName]) {
        return global.service_caches[serviceName];
    }

    // 构建服务模块的文件路径，通过拼接当前工作目录、"services"文件夹以及服务名称来确定具体路径
    var servicePath = path.join(process.cwd(), "services", serviceName);

    // 通过require加载对应的服务模块，如果模块不存在则返回null并在控制台打印提示信息
    var serviceModule = require(servicePath);
    if (!serviceModule) {
        console.log("模块没有被发现");
        return null;
    }

    // 在全局缓存对象中为当前服务名称创建一个空对象，用于后续存储该服务的具体方法相关的回调对象等信息
    global.service_caches[serviceName] = {};

    // 打印一些提示信息，表明正在拦截指定名称的服务，方便调试和查看流程
    console.log("*****************************************");
    console.log("拦截服务 => %s", serviceName);
    console.log("*****************************************");

    // 遍历服务模块里的所有属性（通常是方法）
    for (actionName in serviceModule) {
        // 检查属性对应的是否是一个函数（即服务模块里有效的业务逻辑函数）
        if (serviceModule && serviceModule[actionName] && typeof (serviceModule[actionName]) == "function") {
            var origFunc = serviceModule[actionName];
            // 使用Invocation函数构造该方法对应的回调对象，并将其存储到全局缓存对象中对应的服务和方法名下
            global.service_caches[serviceName][actionName] = Invocation(serviceName, actionName, serviceModule, origFunc);
            console.log("action => %s", actionName);
        }
    }
    // 打印一些分割线和空行，用于在控制台输出中更清晰地区分不同服务的处理情况，此处注释掉了打印全局缓存对象的语句
    // console.log(global.service_caches);
    console.log("*****************************************\n");
    return global.service_caches[serviceName];
}

// 定义一个函数用于设置全局验证函数，它也是模块对外暴露的接口，供外部传入具体的验证函数
module.exports.setAuthFn = function (authFn) {
    global.service_auth_fn = authFn;
}