"use strict";
/**
 * -------------------------------------------------------------------------------------------
 * Copyright (c) Microsoft Corporation.  All Rights Reserved.  Licensed under the MIT License.
 * See License in the project root for license information.
 * -------------------------------------------------------------------------------------------
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.ChaosHandler = void 0;
var tslib_1 = require("tslib");
var MiddlewareControl_1 = require("./MiddlewareControl");
var MiddlewareUtil_1 = require("./MiddlewareUtil");
var ChaosHandlerData_1 = require("./options/ChaosHandlerData");
var ChaosHandlerOptions_1 = require("./options/ChaosHandlerOptions");
var ChaosStrategy_1 = require("./options/ChaosStrategy");
/**
 * Class representing ChaosHandler
 * @class
 * Class
 * @implements Middleware
 */
var ChaosHandler = /** @class */ (function () {
    /**
     * @public
     * @constructor
     * To create an instance of Testing Handler
     * @param {ChaosHandlerOptions} [options = new ChaosHandlerOptions()] - The testing handler options instance
     * @param manualMap - The Map passed by user containing url-statusCode info
     * @returns An instance of Testing Handler
     */
    function ChaosHandler(options, manualMap) {
        if (options === void 0) { options = new ChaosHandlerOptions_1.ChaosHandlerOptions(); }
        this.options = options;
        this.manualMap = manualMap;
    }
    /**
     * Generates responseHeader
     * @private
     * @param {ChaosHandlerOptions} chaosHandlerOptions - The ChaosHandlerOptions object
     * @param {string} requestID - request id
     * @param {string} requestDate - date of the request
     * @returns response Header
     */
    ChaosHandler.prototype.createResponseHeaders = function (chaosHandlerOptions, requestID, requestDate) {
        var responseHeader = chaosHandlerOptions.headers ? new Headers(chaosHandlerOptions.headers) : new Headers();
        responseHeader.append("Cache-Control", "no-store");
        responseHeader.append("request-id", requestID);
        responseHeader.append("client-request-id", requestID);
        responseHeader.append("x-ms-ags-diagnostic", "");
        responseHeader.append("Date", requestDate);
        responseHeader.append("Strict-Transport-Security", "");
        if (chaosHandlerOptions.statusCode === 429) {
            // throttling case has to have a timeout scenario
            responseHeader.append("retry-after", "3");
        }
        return responseHeader;
    };
    /**
     * Generates responseBody
     * @private
     * @param {ChaosHandlerOptions} chaosHandlerOptions - The ChaosHandlerOptions object
     * @param {string} requestID - request id
     * @param {string} requestDate - date of the request
     *  * @returns response body
     */
    ChaosHandler.prototype.createResponseBody = function (chaosHandlerOptions, requestID, requestDate) {
        if (chaosHandlerOptions.responseBody) {
            return chaosHandlerOptions.responseBody;
        }
        var body;
        if (chaosHandlerOptions.statusCode >= 400) {
            var codeMessage = ChaosHandlerData_1.httpStatusCode[chaosHandlerOptions.statusCode];
            var errMessage = chaosHandlerOptions.statusMessage;
            body = {
                error: {
                    code: codeMessage,
                    message: errMessage,
                    innerError: {
                        "request-id": requestID,
                        date: requestDate,
                    },
                },
            };
        }
        else {
            body = {};
        }
        return body;
    };
    /**
     * creates a response
     * @private
     * @param {ChaosHandlerOptions} chaosHandlerOptions - The ChaosHandlerOptions object
     * @param {Context} context - Contains the context of the request
     */
    ChaosHandler.prototype.createResponse = function (chaosHandlerOptions, context) {
        var requestURL = context.request;
        var requestID = (0, MiddlewareUtil_1.generateUUID)();
        var requestDate = new Date();
        var responseHeader = this.createResponseHeaders(chaosHandlerOptions, requestID, requestDate.toString());
        var responseBody = this.createResponseBody(chaosHandlerOptions, requestID, requestDate.toString());
        var init = { url: requestURL, status: chaosHandlerOptions.statusCode, statusText: chaosHandlerOptions.statusMessage, headers: responseHeader };
        context.response = new Response(typeof responseBody === "string" ? responseBody : JSON.stringify(responseBody), init);
    };
    /**
     * Decides whether to send the request to the graph or not
     * @private
     * @param {ChaosHandlerOptions} chaosHandlerOptions - A ChaosHandlerOptions object
     * @param {Context} context - Contains the context of the request
     * @returns nothing
     */
    ChaosHandler.prototype.sendRequest = function (chaosHandlerOptions, context) {
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            return tslib_1.__generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        this.setStatusCode(chaosHandlerOptions, context.request, context.options.method);
                        if (!((chaosHandlerOptions.chaosStrategy === ChaosStrategy_1.ChaosStrategy.MANUAL && !this.nextMiddleware) || Math.floor(Math.random() * 100) < chaosHandlerOptions.chaosPercentage)) return [3 /*break*/, 1];
                        this.createResponse(chaosHandlerOptions, context);
                        return [3 /*break*/, 3];
                    case 1:
                        if (!this.nextMiddleware) return [3 /*break*/, 3];
                        return [4 /*yield*/, this.nextMiddleware.execute(context)];
                    case 2:
                        _a.sent();
                        _a.label = 3;
                    case 3: return [2 /*return*/];
                }
            });
        });
    };
    /**
     * Fetches a random status code for the RANDOM mode from the predefined array
     * @private
     * @param {string} requestMethod - the API method for the request
     * @returns a random status code from a given set of status codes
     */
    ChaosHandler.prototype.getRandomStatusCode = function (requestMethod) {
        var statusCodeArray = ChaosHandlerData_1.methodStatusCode[requestMethod];
        return statusCodeArray[Math.floor(Math.random() * statusCodeArray.length)];
    };
    /**
     * To fetch the relative URL out of the complete URL using a predefined regex pattern
     * @private
     * @param {string} urlMethod - the complete URL
     * @returns the string as relative URL
     */
    ChaosHandler.prototype.getRelativeURL = function (urlMethod) {
        var pattern = /https?:\/\/graph\.microsoft\.com\/[^/]+(.+?)(\?|$)/;
        var relativeURL;
        if (pattern.exec(urlMethod) !== null) {
            relativeURL = pattern.exec(urlMethod)[1];
        }
        return relativeURL;
    };
    /**
     * To fetch the status code from the map(if needed), then returns response by calling createResponse
     * @private
     * @param {ChaosHandlerOptions} chaosHandlerOptions - The ChaosHandlerOptions object
     * @param {string} requestURL - the URL for the request
     * @param {string} requestMethod - the API method for the request
     */
    ChaosHandler.prototype.setStatusCode = function (chaosHandlerOptions, requestURL, requestMethod) {
        var _this = this;
        if (chaosHandlerOptions.chaosStrategy === ChaosStrategy_1.ChaosStrategy.MANUAL) {
            if (chaosHandlerOptions.statusCode === undefined) {
                // manual mode with no status code, can be a global level or request level without statusCode
                var relativeURL_1 = this.getRelativeURL(requestURL);
                if (this.manualMap.get(relativeURL_1) !== undefined) {
                    // checking Manual Map for exact match
                    if (this.manualMap.get(relativeURL_1).get(requestMethod) !== undefined) {
                        chaosHandlerOptions.statusCode = this.manualMap.get(relativeURL_1).get(requestMethod);
                    }
                    // else statusCode would be undefined
                }
                else {
                    // checking for regex match if exact match doesn't work
                    this.manualMap.forEach(function (value, key) {
                        var regexURL = new RegExp(key + "$");
                        if (regexURL.test(relativeURL_1)) {
                            if (_this.manualMap.get(key).get(requestMethod) !== undefined) {
                                chaosHandlerOptions.statusCode = _this.manualMap.get(key).get(requestMethod);
                            }
                            // else statusCode would be undefined
                        }
                    });
                }
                // Case of redirection or request url not in map ---> statusCode would be undefined
            }
        }
        else {
            // Handling the case of Random here
            chaosHandlerOptions.statusCode = this.getRandomStatusCode(requestMethod);
            // else statusCode would be undefined
        }
    };
    /**
     * To get the options for execution of the middleware
     * @private
     * @param {Context} context - The context object
     * @returns options for middleware execution
     */
    ChaosHandler.prototype.getOptions = function (context) {
        var options;
        if (context.middlewareControl instanceof MiddlewareControl_1.MiddlewareControl) {
            options = context.middlewareControl.getMiddlewareOptions(ChaosHandlerOptions_1.ChaosHandlerOptions);
        }
        if (typeof options === "undefined") {
            options = Object.assign(new ChaosHandlerOptions_1.ChaosHandlerOptions(), this.options);
        }
        return options;
    };
    /**
     * To execute the current middleware
     * @public
     * @async
     * @param {Context} context - The context object of the request
     * @returns A Promise that resolves to nothing
     */
    ChaosHandler.prototype.execute = function (context) {
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            var chaosHandlerOptions;
            return tslib_1.__generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        chaosHandlerOptions = this.getOptions(context);
                        return [4 /*yield*/, this.sendRequest(chaosHandlerOptions, context)];
                    case 1: return [2 /*return*/, _a.sent()];
                }
            });
        });
    };
    /**
     * @public
     * To set the next middleware in the chain
     * @param {Middleware} next - The middleware instance
     * @returns Nothing
     */
    ChaosHandler.prototype.setNext = function (next) {
        this.nextMiddleware = next;
    };
    return ChaosHandler;
}());
exports.ChaosHandler = ChaosHandler;
//# sourceMappingURL=ChaosHandler.js.map