import * as i0 from '@angular/core';
import { Injectable, NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import * as i1 from '@angular/common/http';
import { HttpHeaders, HttpParams, HttpRequest, HttpResponse, HttpClientModule } from '@angular/common/http';
import { AbstractHttpService } from '@wm/core';
import { Subject } from 'rxjs';
import { getErrMessage } from '@wavemaker/variables';
import { isNumber, isBoolean, includes, isFunction } from 'lodash-es';

var HTTP_EVENT_TYPE;
(function (HTTP_EVENT_TYPE) {
    HTTP_EVENT_TYPE[HTTP_EVENT_TYPE["Sent"] = 0] = "Sent";
    HTTP_EVENT_TYPE[HTTP_EVENT_TYPE["UploadProgress"] = 1] = "UploadProgress";
    HTTP_EVENT_TYPE[HTTP_EVENT_TYPE["ResponseHeader"] = 2] = "ResponseHeader";
    HTTP_EVENT_TYPE[HTTP_EVENT_TYPE["DownloadProgress"] = 3] = "DownloadProgress";
    HTTP_EVENT_TYPE[HTTP_EVENT_TYPE["Response"] = 4] = "Response";
    HTTP_EVENT_TYPE[HTTP_EVENT_TYPE["User"] = 5] = "User";
})(HTTP_EVENT_TYPE || (HTTP_EVENT_TYPE = {}));
class HttpServiceImpl extends AbstractHttpService {
    constructor(httpClient) {
        super();
        this.httpClient = httpClient;
        this.nonBodyTypeMethods = ['GET', 'DELETE', 'HEAD', 'OPTIONS', 'JSONP'];
        this.sessionTimeoutObservable = new Subject();
        this.sessionTimeoutQueue = [];
    }
    /**
     * This method handles session timeout.
     * @param options
     * @param resolve
     * @param reject
     */
    handleSessionTimeout(options, subscriber401) {
        this.sessionTimeoutQueue.push({
            requestInfo: options,
            sub401: subscriber401
        });
        this.on401();
    }
    /**
     * Generates a request with provided options
     * @param options, request params/options
     */
    generateRequest(options) {
        let reqHeaders = new HttpHeaders(), reqParams = new HttpParams();
        const headers = options.headers;
        const params = options.params;
        const responseType = options.responseType;
        const withCredentials = options.withCredentials;
        // this header is not to be sent with non-proxy calls from service variable
        if (!options.isDirectCall) {
            reqHeaders = reqHeaders.append('X-Requested-With', 'XMLHttpRequest');
        }
        // headers
        if (headers) {
            Object.entries(headers).forEach(([k, v]) => {
                if (isNumber(v) || isBoolean(v)) {
                    v = v.toString();
                }
                reqHeaders = reqHeaders.append(k, v);
            });
        }
        // params
        if (params) {
            Object.entries(params).forEach(([k, v]) => reqParams = reqParams.append(k, v));
        }
        let third, fourth;
        const reqOptions = {
            headers: reqHeaders,
            params: reqParams,
            responseType: responseType,
            withCredentials: withCredentials
        };
        // Even if method is not expecting request body, if body is passed in request, pass it on.
        if (includes(this.nonBodyTypeMethods, options.method && options.method.toUpperCase()) && options.data === undefined) {
            third = reqOptions;
            fourth = null;
        }
        else {
            third = options.data;
            fourth = reqOptions;
        }
        return new HttpRequest(options.method, options.url, third, fourth);
    }
    /**
     * Make a http call and returns an observable that can be cancelled
     * @param options, options using which the call needs to be made
     */
    sendCallAsObservable(options, params) {
        const req = this.generateRequest(options);
        return this.httpClient.request(req);
    }
    sendCall(requestParams, variable, params) {
        return new Promise((resolve, reject) => {
            variable._observable = this.sendCallAsObservable(requestParams, params).subscribe((response) => {
                if (response && response.type) {
                    resolve(response);
                }
            }, (err) => {
                reject(err);
            });
        });
    }
    /**
     * Makes a http call and return a promise
     * @param options, options using which the call needs to be made
     */
    send(options) {
        const req = this.generateRequest(options);
        return new Promise((resolve, reject) => {
            this.httpClient.request(req).toPromise().then((response) => {
                resolve(response);
            }, (err) => {
                if (this.isPlatformSessionTimeout(err)) {
                    err._401Subscriber.asObservable().subscribe((response) => {
                        resolve(response);
                    }, (e) => {
                        reject(e);
                    });
                }
                else {
                    const errMsg = getErrMessage(err, this.getLocale());
                    reject({
                        error: errMsg,
                        details: err
                    });
                }
            });
        });
    }
    cancel(variable, $file) {
        if (variable._observable) {
            variable._observable.unsubscribe();
        }
        if ($file && $file._uploadProgress) {
            $file._uploadProgress.unsubscribe();
        }
    }
    setLocale(locale) {
        this.localeObject = locale;
    }
    getLocale() {
        return this.localeObject;
    }
    getHeader(error, headerKey) {
        return error.headers.get(headerKey);
    }
    isPlatformSessionTimeout(error) {
        const MSG_SESSION_NOT_FOUND = 'Session Not Found';
        return error.status === 401 && this.getHeader(error, 'x-wm-login-errormessage') === MSG_SESSION_NOT_FOUND;
    }
    get(url, options) {
        options = options || {};
        options.url = url;
        options.method = 'get';
        return this.send(options).then((response) => response.body);
    }
    post(url, data, options) {
        options = options || {};
        options.url = url;
        options.method = 'post';
        options.data = data;
        return this.send(options);
    }
    put(url, data, options) {
        options = options || {};
        options.url = url;
        options.method = 'put';
        options.data = data;
        return this.send(options);
    }
    patch(url, data, options) {
        options = options || {};
        options.url = url;
        options.method = 'patch';
        options.data = data;
        return this.send(options);
    }
    delete(url, options) {
        options = options || {};
        options.url = url;
        options.method = 'delete';
        return this.send(options);
    }
    head(url, options) {
        options = options || {};
        options.url = url;
        options.method = 'head';
        return this.send(options);
    }
    jsonp(url, options) {
        options = options || {};
        options.url = url;
        options.method = 'jsonp';
        return this.send(options);
    }
    upload(url, data, options) {
        const req = new HttpRequest('POST', url, data, {
            reportProgress: true // for progress data
        });
        return this.httpClient.request(req);
        // return this.httpClient.post(url, data, {
        //     reportProgress: true
        // });
    }
    uploadFile(url, data, variable, options) {
        return new Promise((resolve, reject) => {
            variable.request = this.upload(url, data, options).subscribe((event) => {
                if (event.type === HTTP_EVENT_TYPE.UploadProgress) {
                    const uploadProgress = Math.round(100 * event.loaded / event.total);
                    options.notify(uploadProgress);
                }
                if (event.type === HTTP_EVENT_TYPE.Response) {
                    resolve(event.body);
                }
            }, error => {
                reject(error);
            });
        });
    }
    /**
     * registers a callback to be trigerred on session timeout
     * @param callback
     */
    registerOnSessionTimeout(callback) {
        this.sessionTimeoutObservable.asObservable().subscribe(callback);
    }
    /**
     * trigger the registered methods on session timeout
     */
    on401() {
        this.sessionTimeoutObservable.next(undefined);
    }
    pushToSessionFailureQueue(callback) {
        this.sessionTimeoutQueue.push({
            callback: callback
        });
    }
    /**
     * Execute queued requests, failed due to session timeout
     */
    executeSessionFailureRequests() {
        const queue = this.sessionTimeoutQueue;
        const that = this;
        that.sessionTimeoutQueue = [];
        queue.forEach(data => {
            if (isFunction(data.callback)) {
                data.callback();
            }
            else {
                data.requestInfo.headers.headers.delete('x-wm-xsrf-token');
                that.httpClient.request(data.requestInfo)
                    .subscribe(response => {
                    if (response && response.type && data.sub401) {
                        data.sub401.next(response);
                    }
                }, (reason) => {
                    data.sub401.error(reason);
                });
            }
        });
    }
    static { this.ɵfac = function HttpServiceImpl_Factory(t) { return new (t || HttpServiceImpl)(i0.ɵɵinject(i1.HttpClient)); }; }
    static { this.ɵprov = /*@__PURE__*/ i0.ɵɵdefineInjectable({ token: HttpServiceImpl, factory: HttpServiceImpl.ɵfac }); }
}
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(HttpServiceImpl, [{
        type: Injectable
    }], () => [{ type: i1.HttpClient }], null); })();

/**
 * This class creates a custom WmHttpRequest.
 */
class WmHttpRequest {
    constructor() {
        this.headers = [];
    }
    /**
     * This method converts the given wm HttpRequest to angular HttpRequest
     * @param reqObj, the wm HttpRequest
     */
    wmToAngularRequest(reqObj) {
        let angReq;
        angReq = new HttpRequest(reqObj.method, reqObj.url);
        angReq = angReq.clone();
        angReq.body = reqObj.body;
        angReq.method = reqObj.method;
        angReq.responseType = reqObj.responseType;
        angReq.reportProgress = reqObj.reportProgress;
        angReq.urlWithParams = reqObj.url;
        angReq.withCredentials = reqObj.withCredentials;
        reqObj.headers.forEach((value, header) => {
            angReq.headers = angReq.headers.append(header, value);
        });
        return angReq;
    }
    /**
     * This method converts the given angular HttpRequest to wm HttpRequest
     * @param req, the angular HttpRequest
     */
    angularToWmRequest(req) {
        let wmReq = new WmHttpRequest();
        let headerMap = new Map();
        wmReq.body = req.body;
        wmReq.method = req.method;
        wmReq.responseType = req.responseType;
        wmReq.reportProgress = req.reportProgress;
        wmReq.url = req.urlWithParams;
        wmReq.withCredentials = req.withCredentials;
        req.headers.keys().forEach((header) => {
            headerMap.set(header, req.headers.headers.get(header.toLowerCase())[0]);
        });
        wmReq.headers = headerMap;
        return wmReq;
    }
}

/**
 * This class creates a custom WmHttpRequest.
 */
class WmHttpResponse extends WmHttpRequest {
    constructor() {
        super();
    }
    /**
     * This method converts the given wm HttpResponse to angular HttpResponse
     * @param respObj, the wm HttpResponse
     */
    wmToAngularResponse(respObj) {
        let angResp;
        angResp = new HttpResponse();
        angResp = angResp.clone();
        angResp.body = respObj.body;
        angResp.error = respObj.error;
        angResp.message = respObj.message;
        angResp.url = respObj.url;
        angResp.ok = respObj.ok;
        angResp.status = respObj.status;
        angResp.statusText = respObj.statusText;
        respObj.headers.forEach((value, header) => {
            angResp.headers = angResp.headers.append(header, value);
        });
        return angResp;
    }
    /**
     * This method converts the given wm HttpResponse to angular HttpResponse
     * @param respObj, the angular HttpResponse
     */
    angularToWmResponse(respObj) {
        let wmResp;
        let headerMap = new Map();
        wmResp = new WmHttpResponse();
        wmResp.body = respObj.body;
        wmResp.error = respObj.error;
        wmResp.message = respObj.message;
        wmResp.url = respObj.url;
        wmResp.ok = respObj.ok;
        wmResp.status = respObj.status;
        wmResp.statusText = respObj.statusText;
        respObj.headers.keys().forEach((header) => {
            headerMap.set(header, respObj.headers.headers.get(header.toLowerCase())[0]);
        });
        wmResp.headers = headerMap;
        return wmResp;
    }
}

class HttpServiceModule {
    static forRoot() {
        return {
            ngModule: CommonModule,
            providers: [
                { provide: AbstractHttpService, useClass: HttpServiceImpl }
            ]
        };
    }
    static { this.ɵfac = function HttpServiceModule_Factory(t) { return new (t || HttpServiceModule)(); }; }
    static { this.ɵmod = /*@__PURE__*/ i0.ɵɵdefineNgModule({ type: HttpServiceModule }); }
    static { this.ɵinj = /*@__PURE__*/ i0.ɵɵdefineInjector({ imports: [CommonModule,
            HttpClientModule] }); }
}
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(HttpServiceModule, [{
        type: NgModule,
        args: [{
                imports: [
                    CommonModule,
                    HttpClientModule
                ],
                declarations: []
            }]
    }], null, null); })();
(function () { (typeof ngJitMode === "undefined" || ngJitMode) && i0.ɵɵsetNgModuleScope(HttpServiceModule, { imports: [CommonModule,
        HttpClientModule] }); })();

/**
 * Generated bundle index. Do not edit.
 */

export { HttpServiceImpl, HttpServiceModule, WmHttpRequest, WmHttpResponse };
//# sourceMappingURL=index.mjs.map
