"use strict";
var __assign = (this && this.__assign) || function () {
    __assign = Object.assign || function(t) {
        for (var s, i = 1, n = arguments.length; i < n; i++) {
            s = arguments[i];
            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
                t[p] = s[p];
        }
        return t;
    };
    return __assign.apply(this, arguments);
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __generator = (this && this.__generator) || function (thisArg, body) {
    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
    return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
    function verb(n) { return function (v) { return step([n, v]); }; }
    function step(op) {
        if (f) throw new TypeError("Generator is already executing.");
        while (_) try {
            if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
            if (y = 0, t) op = [op[0] & 2, t.value];
            switch (op[0]) {
                case 0: case 1: t = op; break;
                case 4: _.label++; return { value: op[1], done: false };
                case 5: _.label++; y = op[1]; op = [0]; continue;
                case 7: op = _.ops.pop(); _.trys.pop(); continue;
                default:
                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
                    if (t[2]) _.ops.pop();
                    _.trys.pop(); continue;
            }
            op = body.call(thisArg, _);
        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
    }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.PreReCalFeeDecorator = void 0;
var mslib_1 = require("mslib");
var Config_1 = require("./Config");
var ApiResponse_1 = require("./ApiResponse");
var Security_1 = require("./Security"); // 需包含DES解密方法
var memberapi_config = Config_1.IocConfigProvider.getMemberConfig();
/**
 * 3DS Token校验装饰器（DES解密+时效性+参数一致性校验）
 *
 * 从请求参数中提取token，解密后验证：
 * 1. token是否在有效期内（基于加密时的timestamp和expiresIn）
 * 2. 请求参数中的关键字段与加密时的原始数据是否一致
 *
 * @param description 服务描述（日志用）
 * @param config 配置选项
 * @param config.isLog 是否记录日志，默认true
 * @param config.isVerify 是否启用校验，默认true
 */
function PreReCalFeeDecorator(description, config) {
    // 默认配置（关键字段需根据业务场景调整）
    var defaultConfig = __assign({ isLog: true, isVerify: true, isEncrypt: true, expiresIn: 300 }, config);
    return function (target, propertyKey, descriptor) {
        var _a;
        // 装饰器初始化日志
        var tapdId = ((_a = Config_1.IocConfigProvider.getBasicConfig()) === null || _a === void 0 ? void 0 : _a.tapdId) || '';
        mslib_1.logger.info(tapdId + "." + target.constructor.name + "/1.0", "Token\u6821\u9A8C\u88C5\u9970\u5668 - " + (description || '未提供描述'));
        // 保存原始方法
        var originalMethod = descriptor.value;
        // 重写方法（核心校验逻辑）
        descriptor.value = function () {
            var _a;
            var args = [];
            for (var _i = 0; _i < arguments.length; _i++) {
                args[_i] = arguments[_i];
            }
            return __awaiter(this, void 0, void 0, function () {
                var tapdId, serviceName, errorMsg, errorMsg, requestParams, token, serviceInfo, errorMsg, decryptedStr, errorMsg, decryptedData, errorMsg, currentTimestamp, expireTimestamp, errorMsg, validationResult, errorMsg, result, methodError_1, errorMsg, errorMsg, errorMsg, timestamp, dataToEncrypt, encryptToken;
                return __generator(this, function (_b) {
                    switch (_b.label) {
                        case 0:
                            tapdId = ((_a = Config_1.IocConfigProvider.getBasicConfig()) === null || _a === void 0 ? void 0 : _a.tapdId) || '';
                            serviceName = description || target.constructor.name + "." + propertyKey;
                            // 1. 基础配置校验
                            if (defaultConfig.isVerify) {
                                if (!memberapi_config.key) {
                                    errorMsg = 'Token校验失败：未配置DES密钥（key）';
                                    mslib_1.logger.error("tapd:" + tapdId + " " + serviceName, errorMsg);
                                    return [2 /*return*/, ApiResponse_1.ApiResponse.successResult(1, errorMsg, {})];
                                }
                                if (!memberapi_config.iv) {
                                    errorMsg = 'Token校验失败：未配置DES向量（iv）';
                                    mslib_1.logger.error("tapd:" + tapdId + " " + serviceName, errorMsg);
                                    return [2 /*return*/, ApiResponse_1.ApiResponse.successResult(1, errorMsg, {})];
                                }
                            }
                            requestParams = args[0] || {};
                            token = requestParams === null || requestParams === void 0 ? void 0 : requestParams.jwtToken;
                            serviceInfo = "tapd:" + tapdId + " Token\u6821\u9A8C\u670D\u52A1 " + serviceName;
                            // 3. 记录请求日志
                            if (defaultConfig.isLog) {
                                mslib_1.logger.info(serviceInfo + " \u8BF7\u6C42\u53C2\u6570:" + JSON.stringify(requestParams) + "\uFF0C\u5F85\u6821\u9A8Ctoken:" + (token ? '存在' : '不存在'));
                            }
                            // 4. 校验开关：若不启用校验，直接执行原始方法
                            if (!defaultConfig.isVerify) {
                                return [2 /*return*/, originalMethod.apply(this, args)];
                            }
                            // 5. 校验token是否存在
                            if (!token) {
                                errorMsg = '请求中未包含token，请检查jwtToken字段';
                                mslib_1.logger.error(serviceInfo + " \u6821\u9A8C\u5F02\u5E38", errorMsg);
                                return [2 /*return*/, ApiResponse_1.ApiResponse.successResult(1, "Token\u6821\u9A8C\u5931\u8D25\uFF1A" + errorMsg, {})];
                            }
                            decryptedStr = Security_1.CryptoUtils.desDecrypt(token, memberapi_config.key, memberapi_config.iv);
                            if (!decryptedStr) {
                                errorMsg = 'token解密失败，可能是无效token或密钥不匹配';
                                mslib_1.logger.error(serviceInfo + " \u6821\u9A8C\u5F02\u5E38", errorMsg);
                                return [2 /*return*/, ApiResponse_1.ApiResponse.successResult(1, "Token\u6821\u9A8C\u5931\u8D25\uFF1A" + errorMsg, {})];
                            }
                            try {
                                decryptedData = JSON.parse(decryptedStr);
                            }
                            catch (parseError) {
                                errorMsg = 'token解析失败，格式不正确';
                                mslib_1.logger.error(serviceInfo + " \u6821\u9A8C\u5F02\u5E38", errorMsg, parseError);
                                return [2 /*return*/, ApiResponse_1.ApiResponse.successResult(1, "Token\u6821\u9A8C\u5931\u8D25\uFF1A" + errorMsg, {})];
                            }
                            currentTimestamp = Math.floor(Date.now() / 1000);
                            expireTimestamp = decryptedData.timestamp + decryptedData.expiresIn;
                            if (currentTimestamp > expireTimestamp) {
                                errorMsg = "token\u5DF2\u8FC7\u671F\uFF08\u6709\u6548\u671F" + decryptedData.expiresIn + "\u79D2\uFF09\uFF0C\u8BF7\u91CD\u65B0\u83B7\u53D6";
                                mslib_1.logger.error(serviceInfo + " \u6821\u9A8C\u5F02\u5E38", errorMsg);
                                return [2 /*return*/, ApiResponse_1.ApiResponse.successResult(1, "Token\u6821\u9A8C\u5931\u8D25\uFF1A" + errorMsg, {})];
                            }
                            validationResult = validateParams(requestParams, decryptedData.payload.data);
                            if (!validationResult.isValid) {
                                errorMsg = "\u53C2\u6570\u4E0D\u4E00\u81F4\uFF1A" + validationResult.errors.join('; ');
                                mslib_1.logger.error(serviceInfo + " \u6821\u9A8C\u5F02\u5E38", errorMsg);
                                return [2 /*return*/, ApiResponse_1.ApiResponse.successResult(1, "Token\u6821\u9A8C\u5931\u8D25\uFF1A" + errorMsg, {})];
                            }
                            // 10. 校验通过，执行原始方法
                            if (defaultConfig.isLog) {
                                mslib_1.logger.info(serviceInfo + " token\u6821\u9A8C\u901A\u8FC7\uFF0C\u5F00\u59CB\u6267\u884C\u539F\u59CB\u65B9\u6CD5");
                            }
                            _b.label = 1;
                        case 1:
                            _b.trys.push([1, 3, , 4]);
                            return [4 /*yield*/, originalMethod.apply(this, args)];
                        case 2:
                            // 调用原始方法获取结果
                            result = _b.sent();
                            return [3 /*break*/, 4];
                        case 3:
                            methodError_1 = _b.sent();
                            errorMsg = methodError_1 instanceof Error ? methodError_1.message : "\u539F\u59CB\u65B9\u6CD5\u6267\u884C\u5931\u8D25\uFF1A" + String(methodError_1);
                            mslib_1.logger.error(serviceInfo + " \u539F\u59CB\u65B9\u6CD5\u6267\u884C\u5F02\u5E38", errorMsg);
                            return [2 /*return*/, ApiResponse_1.ApiResponse.successResult(1, errorMsg, {})];
                        case 4:
                            // 如果需要加密且结果有效，则进行DES加密处理
                            if (result && typeof result === 'object') {
                                //非正常可抵扣数据不赋值prePayId
                                if (result.resCode != 0) {
                                    return [2 /*return*/, result];
                                }
                                // 确保有DES密钥
                                if (!memberapi_config.key) {
                                    errorMsg = 'DES加密失败：未配置key';
                                    mslib_1.logger.error(serviceInfo + " \u52A0\u5BC6\u5F02\u5E38", errorMsg);
                                    return [2 /*return*/, ApiResponse_1.ApiResponse.successResult(1, errorMsg, {})];
                                }
                                // 确保有DES向量
                                if (!memberapi_config.iv) {
                                    errorMsg = 'DES加密失败：未配置iv';
                                    mslib_1.logger.error(serviceInfo + " \u52A0\u5BC6\u5F02\u5E38", errorMsg);
                                    return [2 /*return*/, ApiResponse_1.ApiResponse.successResult(1, errorMsg, {})];
                                }
                                timestamp = Math.floor(Date.now() / 1000);
                                dataToEncrypt = {
                                    payload: result,
                                    timestamp: timestamp,
                                    expiresIn: defaultConfig.expiresIn
                                };
                                encryptToken = Security_1.CryptoUtils.desEncrypt(JSON.stringify(dataToEncrypt), memberapi_config.key, memberapi_config.iv);
                                // 将加密结果存入prePayId字段
                                result.data.prePayId = encryptToken;
                                return [2 /*return*/, result];
                            }
                            return [2 /*return*/, result];
                    }
                });
            });
        };
        return descriptor;
    };
}
exports.PreReCalFeeDecorator = PreReCalFeeDecorator;
/**
 * 校验前端参数与原始参数的一致性
 * 按照提供的validateParams方法逻辑实现
 * @param frontData 前端参数对象
 * @param rawData 原始参数中的data对象
 * @returns 校验结果：{isValid: 布尔值, errors: 错误信息数组}
 */
function validateParams(frontData, rawData) {
    var _a, _b, _c, _d, _e, _f;
    var errors = [];
    var front = frontData || {}; // 前端参数
    var raw = rawData || {}; // 原始数据中的data部分
    // 1. 校验车牌号（PlateNo）
    var frontPlateNo = front.PlateNo;
    var rawPlateNo = (_a = raw.CarplateData) === null || _a === void 0 ? void 0 : _a.PlateNo;
    if (frontPlateNo !== rawPlateNo) {
        errors.push("\u8F66\u724C\u53F7\u4E0D\u4E00\u81F4\uFF1A\u524D\u7AEF=\"" + frontPlateNo + "\"\uFF0C\u539F\u59CB=\"" + rawPlateNo + "\"");
    }
    // 2. 校验VIP等级（VIPLevel）
    var frontVIPLevel = front.VIPLevel;
    var rawVIPLevel = (_b = raw.VIPData) === null || _b === void 0 ? void 0 : _b.VIPLevel;
    if (frontVIPLevel !== rawVIPLevel) {
        errors.push("VIP\u7B49\u7EA7\u4E0D\u4E00\u81F4\uFF1A\u524D\u7AEF=\"" + frontVIPLevel + "\"\uFF0C\u539F\u59CB=\"" + rawVIPLevel + "\"");
    }
    // 2.1 等级抵扣限制和额度校验
    var frontBenefitsData = (front === null || front === void 0 ? void 0 : front.BenefitsData) || {};
    var rawBenefitsData = (raw === null || raw === void 0 ? void 0 : raw.BenefitsData) || {};
    if (rawBenefitsData === null || rawBenefitsData === void 0 ? void 0 : rawBenefitsData.VIPBenefit) {
        if (!frontBenefitsData) {
            errors.push("\u7B49\u7EA7\u62B5\u6263\u524D\u7AEF\u53C2\u6570\u7F3A\u5931");
        }
        if ((frontBenefitsData === null || frontBenefitsData === void 0 ? void 0 : frontBenefitsData.VIPBenefits) != (rawBenefitsData === null || rawBenefitsData === void 0 ? void 0 : rawBenefitsData.VIPBenefits)) {
            errors.push("\u7B49\u7EA7\u62B5\u6263\u989D\u5EA6\u4E0D\u4E00\u81F4\uFF1A\u524D\u7AEF=" + (frontBenefitsData === null || frontBenefitsData === void 0 ? void 0 : frontBenefitsData.VIPBenefits) + "\uFF0C\u539F\u59CB=" + (rawBenefitsData === null || rawBenefitsData === void 0 ? void 0 : rawBenefitsData.VIPBenefits));
        }
        if ((frontBenefitsData === null || frontBenefitsData === void 0 ? void 0 : frontBenefitsData.BenefitsType) != (rawBenefitsData === null || rawBenefitsData === void 0 ? void 0 : rawBenefitsData.BenefitsType)) {
            errors.push("\u7B49\u7EA7\u62B5\u6263\u4F7F\u7528\u989D\u5EA6\u4E0D\u4E00\u81F4\uFF1A\u524D\u7AEF=" + (frontBenefitsData === null || frontBenefitsData === void 0 ? void 0 : frontBenefitsData.BenefitsType) + "\uFF0C\u539F\u59CB=" + (rawBenefitsData === null || rawBenefitsData === void 0 ? void 0 : rawBenefitsData.BenefitsType));
        }
    }
    // 3. 校验优惠券数组（CouponData）
    var frontCoupons = front.CouponData || [];
    var rawCoupons = raw.CouponData || [];
    // 3.1 数组长度一致性
    if (frontCoupons.length > rawCoupons.length) {
        errors.push("\u4F18\u60E0\u5238\u6570\u91CF\u4E0D\u4E00\u81F4\uFF1A\u524D\u7AEF=" + frontCoupons.length + "\u6761\uFF0C\u539F\u59CB=" + rawCoupons.length + "\u6761");
    }
    else {
        // 3.2 逐条校验优惠券字段
        frontCoupons.forEach(function (frontCoupon, index) {
            var rawCoupon = rawCoupons[index];
            if (!rawCoupon) {
                errors.push("\u4F18\u60E0\u5238[" + index + "]\uFF1A\u539F\u59CB\u53C2\u6570\u7F3A\u5931");
                return;
            }
            // // 规则ID
            // if (frontCoupon.RuleId !== rawCoupon.RuleId) {
            //     errors.push(`优惠券[${index}]规则ID不一致：前端=${frontCoupon.RuleId}，原始=${rawCoupon.RuleId}`);
            // }
            // // 规则名称
            // if (frontCoupon.RuleName !== rawCoupon.RuleName) {
            //     errors.push(`优惠券[${index}]名称不一致：前端="${frontCoupon.RuleName}"，原始="${rawCoupon.RuleName}"`);
            // }
            // 优惠券编号
            if (frontCoupon.TicketNo !== rawCoupon.TicketNo) {
                errors.push("\u4F18\u60E0\u5238[" + index + "]\u7F16\u53F7\u4E0D\u4E00\u81F4\uFF1A\u524D\u7AEF=\"" + frontCoupon.TicketNo + "\"\uFF0C\u539F\u59CB=\"" + rawCoupon.TicketNo + "\"");
            }
            // 面额（前端TicketValue对应原始DisAmout）
            if (frontCoupon.DisAmout !== rawCoupon.TicketValue) {
                errors.push("\u4F18\u60E0\u5238[" + index + "]\u9762\u989D\u4E0D\u4E00\u81F4\uFF1A\u524D\u7AEF=" + frontCoupon.DisAmout + "\uFF0C\u539F\u59CB=" + rawCoupon.TicketValue);
            }
            // 抵扣类型（前端DisType对应原始TicketType）
            if (frontCoupon.DisType !== rawCoupon.TicketType) {
                errors.push("\u4F18\u60E0\u5238[" + index + "]\u62B5\u6263\u7C7B\u578B\u4E0D\u4E00\u81F4\uFF1A\u524D\u7AEF=" + frontCoupon.DisType + "\uFF0C\u539F\u59CB=" + rawCoupon.TicketType);
            }
        });
    }
    // 3.2 校验前端的卷是有无重复卷
    if (!checkUnique(frontCoupons, 'TicketNo')) {
        errors.push("\u4F18\u60E0\u5238\u5B58\u5728\u91CD\u590DTicketNo");
    }
    // 4.1 消费抵扣限制和额度校验
    var frontConsumeData = front.ConsumeData || {};
    var rawConsumeData = raw.ConsumeData || {};
    // 消费抵扣规则存在
    if (rawConsumeData === null || rawConsumeData === void 0 ? void 0 : rawConsumeData.DiscountRule) {
        if (!frontConsumeData) {
            errors.push("\u6D88\u8D39\u62B5\u6263\u524D\u7AEF\u53C2\u6570\u7F3A\u5931");
        }
        if ((frontConsumeData === null || frontConsumeData === void 0 ? void 0 : frontConsumeData.DisAmout) != ((_c = rawConsumeData === null || rawConsumeData === void 0 ? void 0 : rawConsumeData.DiscountRule[0]) === null || _c === void 0 ? void 0 : _c.DiscountLimit)) {
            errors.push("\u6D88\u8D39\u62B5\u6263\u989D\u5EA6\u4E0D\u4E00\u81F4\uFF1A\u524D\u7AEF=" + (frontConsumeData === null || frontConsumeData === void 0 ? void 0 : frontConsumeData.DisAmout) + "\uFF0C\u539F\u59CB=" + ((_d = rawConsumeData === null || rawConsumeData === void 0 ? void 0 : rawConsumeData.DiscountRule[0]) === null || _d === void 0 ? void 0 : _d.DiscountLimit));
        }
        if ((frontConsumeData === null || frontConsumeData === void 0 ? void 0 : frontConsumeData.Consume) != ((_e = rawConsumeData === null || rawConsumeData === void 0 ? void 0 : rawConsumeData.DiscountRule[0]) === null || _e === void 0 ? void 0 : _e.ConsumeLimit)) {
            errors.push("\u6D88\u8D39\u62B5\u6263\u4F7F\u7528\u989D\u5EA6\u4E0D\u4E00\u81F4\uFF1A\u524D\u7AEF=" + (frontConsumeData === null || frontConsumeData === void 0 ? void 0 : frontConsumeData.Consume) + "\uFF0C\u539F\u59CB=" + ((_f = rawConsumeData === null || rawConsumeData === void 0 ? void 0 : rawConsumeData.DiscountRule[0]) === null || _f === void 0 ? void 0 : _f.ConsumeLimit));
        }
    }
    return {
        isValid: errors.length === 0,
        errors: errors
    };
}
/**
 * 检查对象数组中指定字段是否存在重复值
 * @param {Array} arr 要检查的对象数组
 * @param {string} key 要检查的字段名（如 'id'、'name'）
 * @returns {boolean} 存在重复值返回 false，无重复返回 true
 */
function checkUnique(arr, key) {
    // 边界处理：非数组或空数组直接返回 true（无重复）
    if (!Array.isArray(arr) || arr.length === 0)
        return true;
    var valueSet = new Set(); // 利用 Set 存储已出现的值，自动去重
    for (var _i = 0, arr_1 = arr; _i < arr_1.length; _i++) {
        var item = arr_1[_i];
        // 跳过非对象元素（避免报错）
        if (typeof item !== 'object' || item === null)
            continue;
        var value = item[key];
        // 若当前值已在 Set 中存在，说明重复，返回 false
        if (valueSet.has(value)) {
            return false;
        }
        // 否则将值存入 Set
        valueSet.add(value);
    }
    // 遍历完所有元素无重复，返回 true
    return true;
}
//# sourceMappingURL=PreReCalFee.js.map