"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const needle_1 = require("needle");
const types_1 = require("@deepstream/types");
const utils_1 = require("../../../utils/utils");
class HttpAuthentication extends types_1.DeepstreamPlugin {
    constructor(settings, services, config) {
        super();
        this.settings = settings;
        this.services = services;
        this.description = `http webhook to ${this.settings.endpointUrl}`;
        this.retryAttempts = new Map();
        this.requestId = 0;
        this.validateSettings();
        if (this.settings.promoteToHeader === undefined) {
            this.settings.promoteToHeader = [];
        }
    }
    async isValidUser(connectionData, authData) {
        return new Promise((resolve) => {
            this.validate(this.requestId++, connectionData, authData, resolve);
        });
    }
    validate(id, connectionData, authData, callback) {
        const options = {
            read_timeout: this.settings.requestTimeout,
            open_timeout: this.settings.requestTimeout,
            response_timeout: this.settings.requestTimeout,
            follow_max: 2,
            json: true,
            headers: {}
        };
        if (this.settings.promoteToHeader.length > 0) {
            options.headers = this.settings.promoteToHeader.reduce((result, property) => {
                if (authData[property]) {
                    result[property] = authData[property];
                }
                return result;
            }, {});
        }
        needle_1.post(this.settings.endpointUrl, { connectionData, authData }, options, (error, response) => {
            if (error) {
                this.services.logger.warn(types_1.EVENT.AUTH_ERROR, `http auth error: ${error}`);
                this.retry(id, connectionData, authData, callback);
                return;
            }
            if (!response.statusCode) {
                this.services.logger.warn(types_1.EVENT.AUTH_ERROR, 'http auth server error: missing status code!');
                this.retryAttempts.delete(id);
                callback({ isValid: false });
                return;
            }
            if (response.statusCode >= 500 && response.statusCode < 600) {
                this.services.logger.warn(types_1.EVENT.AUTH_ERROR, `http auth server error: ${JSON.stringify(response.body)}`);
            }
            if (this.settings.retryStatusCodes.includes(response.statusCode)) {
                this.retry(id, connectionData, authData, callback);
                return;
            }
            this.retryAttempts.delete(id);
            if (this.settings.permittedStatusCodes.indexOf(response.statusCode) === -1) {
                if (typeof response.body === 'string' && response.body) {
                    callback({ isValid: false, clientData: { error: response.body } });
                }
                else {
                    callback({ isValid: false, ...response.body });
                }
                return;
            }
            if (response.body && typeof response.body === 'string') {
                callback({ isValid: true, id: response.body });
                return;
            }
            callback({ isValid: true, ...response.body });
        });
    }
    retry(id, connectionData, authData, callback) {
        let retryAttempt = this.retryAttempts.get(id);
        if (!retryAttempt) {
            retryAttempt = {
                connectionData,
                authData,
                callback,
                attempts: 0
            };
            this.retryAttempts.set(id, retryAttempt);
        }
        else {
            retryAttempt.attempts++;
        }
        if (retryAttempt.attempts < this.settings.retryAttempts) {
            setTimeout(() => this.validate(id, connectionData, authData, callback), this.settings.retryInterval);
        }
        else {
            this.retryAttempts.delete(id);
            callback({
                isValid: false,
                clientData: {
                    error: types_1.EVENT.AUTH_RETRY_ATTEMPTS_EXCEEDED
                }
            });
        }
    }
    validateSettings() {
        utils_1.validateMap(this.settings, true, {
            endpointUrl: 'url',
            permittedStatusCodes: 'array',
            requestTimeout: 'number',
            retryStatusCodes: 'array',
            retryAttempts: 'number',
            retryInterval: 'number'
        });
    }
}
exports.HttpAuthentication = HttpAuthentication;
//# sourceMappingURL=http-authentication.js.map