import { InjectionToken, ɵɵdefineInjectable, ɵɵinject, Injectable, Inject, Optional, NgModule } from '@angular/core';
import { HttpResponse, HttpClientModule, HTTP_INTERCEPTORS, HttpClient } from '@angular/common/http';
import { from, throwError, Subject } from 'rxjs';
import { switchMap, map, catchError, timeout, take } from 'rxjs/operators';
import hash from 'object-hash';
import { SdCacheService } from '@sd-angular/core/cache';
import { __awaiter, __classPrivateFieldGet } from 'tslib';
import { v4 } from 'uuid';

const API_CONFIG = new InjectionToken('api.configuration');
const TOKEN = hash({
    origin: location.origin,
    key: 'ed4a2ffc-af43-41fb-9ac9-970f43d99571'
});

class SdTokenService {
    constructor(configuration, cacheService) {
        this.configuration = configuration;
        this.cacheService = cacheService;
        this.set = (token) => {
            const { set } = this.cacheService.create(TOKEN, {
                type: 'local',
                hours: 240
            });
            set(token);
        };
        this.clear = () => {
            const { remove } = this.cacheService.create(TOKEN, {
                type: 'local',
                hours: 240
            });
            remove();
        };
        this.customHeaders = (args) => {
            var _a, _b;
            return ((_b = (_a = this.configuration) === null || _a === void 0 ? void 0 : _a.customHeaders) === null || _b === void 0 ? void 0 : _b.call(_a, args)) || null;
        };
    }
    get token() {
        const { get } = this.cacheService.create(TOKEN, {
            type: 'local',
            hours: 240
        });
        return get();
    }
}
SdTokenService.ɵprov = ɵɵdefineInjectable({ factory: function SdTokenService_Factory() { return new SdTokenService(ɵɵinject(API_CONFIG, 8), ɵɵinject(SdCacheService)); }, token: SdTokenService, providedIn: "root" });
SdTokenService.decorators = [
    { type: Injectable, args: [{
                providedIn: 'root'
            },] }
];
SdTokenService.ctorParameters = () => [
    { type: undefined, decorators: [{ type: Inject, args: [API_CONFIG,] }, { type: Optional }] },
    { type: SdCacheService }
];

class SdHttpInterceptor {
    constructor(configuration, tokenService) {
        this.configuration = configuration;
        this.tokenService = tokenService;
    }
    intercept(request, next) {
        var _a, _b, _c, _d;
        if (((_a = this.configuration) === null || _a === void 0 ? void 0 : _a.tokenHeader) && this.tokenService.token) {
            request = request.clone({ headers: request.headers.set(this.configuration.tokenHeader, this.tokenService.token) });
        }
        if (!request.url.startsWith('http')) {
            request = request.clone({
                url: (((_b = this.configuration) === null || _b === void 0 ? void 0 : _b.host) || location.host) + request.url
            });
        }
        if (request.body instanceof FormData) {
            request = request.clone({
                headers: request.headers.delete('Content-Type')
            });
        }
        const beforeRemote = (_d = (_c = this.configuration) === null || _c === void 0 ? void 0 : _c.beforeRemote) === null || _d === void 0 ? void 0 : _d.call(_c, request);
        if (beforeRemote instanceof Promise) {
            return from(beforeRemote).pipe(switchMap(() => next.handle(request)), map((event) => {
                var _a, _b;
                if (event instanceof HttpResponse) {
                    (_b = (_a = this.configuration) === null || _a === void 0 ? void 0 : _a.afterRemote) === null || _b === void 0 ? void 0 : _b.call(_a, event);
                }
                return event;
            }), catchError((error) => {
                var _a, _b;
                (_b = (_a = this.configuration) === null || _a === void 0 ? void 0 : _a.afterRemote) === null || _b === void 0 ? void 0 : _b.call(_a, error);
                return throwError(error);
            }));
        }
        return next.handle(request).pipe(map((event) => {
            var _a, _b;
            if (event instanceof HttpResponse) {
                (_b = (_a = this.configuration) === null || _a === void 0 ? void 0 : _a.afterRemote) === null || _b === void 0 ? void 0 : _b.call(_a, event);
            }
            return event;
        }), catchError((error) => {
            var _a, _b;
            (_b = (_a = this.configuration) === null || _a === void 0 ? void 0 : _a.afterRemote) === null || _b === void 0 ? void 0 : _b.call(_a, error);
            return throwError(error);
        }));
    }
}
SdHttpInterceptor.decorators = [
    { type: Injectable }
];
SdHttpInterceptor.ctorParameters = () => [
    { type: undefined, decorators: [{ type: Inject, args: [API_CONFIG,] }, { type: Optional }] },
    { type: SdTokenService }
];

class SdApiModule {
}
SdApiModule.decorators = [
    { type: NgModule, args: [{
                imports: [
                    HttpClientModule,
                ],
                exports: [
                    HttpClientModule
                ],
                providers: [
                    { provide: HTTP_INTERCEPTORS, useClass: SdHttpInterceptor, multi: true }
                ],
            },] }
];

var _timeout, _cacheDuration, _cache, _defineParams;
class SdApiService {
    constructor(httpClient, configuration, cacheService, tokenService) {
        this.httpClient = httpClient;
        this.configuration = configuration;
        this.cacheService = cacheService;
        this.tokenService = tokenService;
        this.uploadId = 'U118fefb1-3085-4641-8cb8-f7fe5c28f509';
        _timeout.set(this, 120000); // 120s
        _cacheDuration.set(this, 2000); // 2s
        _cache.set(this, {});
        this.translate = (value) => {
            var _a;
            return ((_a = this.configuration) === null || _a === void 0 ? void 0 : _a.translate(value)) || value;
        };
        this.post = (url, body, headers, options) => __awaiter(this, void 0, void 0, function* () {
            var _a, _b;
            headers =
                headers ||
                    this.tokenService.customHeaders({
                        url,
                    });
            let hashKey = v4();
            if (!(body instanceof FormData)) {
                hashKey = hash({
                    url,
                    headers,
                    body,
                });
            }
            if (!__classPrivateFieldGet(this, _cache)[hashKey] || Date.addMiliseconds(__classPrivateFieldGet(this, _cache)[hashKey].createdDate, __classPrivateFieldGet(this, _cacheDuration)) < new Date()) {
                __classPrivateFieldGet(this, _cache)[hashKey] = {
                    createdDate: new Date(),
                    subject: new Subject(),
                };
                if ((options === null || options === void 0 ? void 0 : options.responseType) && options.responseType !== 'json') {
                    this.httpClient
                        .post(encodeURI(url), body, {
                        observe: 'body',
                        headers,
                        responseType: options === null || options === void 0 ? void 0 : options.responseType,
                    })
                        .pipe(timeout(__classPrivateFieldGet(this, _timeout)))
                        .subscribe(res => {
                        __classPrivateFieldGet(this, _cache)[hashKey].response = {
                            status: 'success',
                            result: res,
                        };
                        __classPrivateFieldGet(this, _cache)[hashKey].subject.next(res);
                    }, err => {
                        __classPrivateFieldGet(this, _cache)[hashKey].response = {
                            status: 'error',
                            result: err,
                        };
                        __classPrivateFieldGet(this, _cache)[hashKey].subject.error(err);
                    });
                }
                else {
                    this.httpClient
                        .post(encodeURI(url), body, {
                        observe: 'response',
                        headers,
                    })
                        .pipe(timeout(__classPrivateFieldGet(this, _timeout)))
                        .subscribe(res => {
                        if (res.ok) {
                            __classPrivateFieldGet(this, _cache)[hashKey].response = {
                                status: 'success',
                                result: res.body,
                            };
                            __classPrivateFieldGet(this, _cache)[hashKey].subject.next(res.body);
                        }
                        else {
                            __classPrivateFieldGet(this, _cache)[hashKey].response = {
                                status: 'error',
                                result: res.body,
                            };
                            __classPrivateFieldGet(this, _cache)[hashKey].subject.error(res.body);
                        }
                    }, err => {
                        __classPrivateFieldGet(this, _cache)[hashKey].response = {
                            status: 'error',
                            result: err,
                        };
                        __classPrivateFieldGet(this, _cache)[hashKey].subject.error(err);
                    });
                }
            }
            if ((_a = __classPrivateFieldGet(this, _cache)[hashKey].response) === null || _a === void 0 ? void 0 : _a.status) {
                if (((_b = __classPrivateFieldGet(this, _cache)[hashKey].response) === null || _b === void 0 ? void 0 : _b.status) === 'success') {
                    return __classPrivateFieldGet(this, _cache)[hashKey].response.result;
                }
                throw __classPrivateFieldGet(this, _cache)[hashKey].response.result;
            }
            return __classPrivateFieldGet(this, _cache)[hashKey].subject.pipe(take(1)).toPromise();
        });
        this.postCache = (url, body, options) => __awaiter(this, void 0, void 0, function* () {
            const headers = (options === null || options === void 0 ? void 0 : options.headers) ||
                this.tokenService.customHeaders({
                    url,
                });
            const { get, set, has } = this.cacheService.create({
                url,
                headers,
                body,
            }, {
                type: options === null || options === void 0 ? void 0 : options.cacheType,
                hours: options === null || options === void 0 ? void 0 : options.cacheHours,
            });
            if (!has()) {
                const result = yield this.post(url, body, options === null || options === void 0 ? void 0 : options.headers);
                set(result);
                return result;
            }
            return get();
        });
        this.put = (url, body, headers) => __awaiter(this, void 0, void 0, function* () {
            headers =
                headers ||
                    this.tokenService.customHeaders({
                        url,
                    });
            return yield new Promise((resolve, reject) => {
                this.httpClient
                    .put(encodeURI(url), body, {
                    observe: 'response',
                    headers,
                })
                    .pipe(timeout(__classPrivateFieldGet(this, _timeout)))
                    .toPromise()
                    .then(result => {
                    if (result.ok) {
                        resolve(result.body);
                    }
                    else {
                        reject(result.body);
                    }
                })
                    .catch((httpErrorResponse) => {
                    reject(httpErrorResponse);
                });
            });
        });
        _defineParams.set(this, (request) => {
            const rq = [];
            for (const [key, value] of Object.entries(request)) {
                if (value !== null && value !== undefined && value !== '' && (value === null || value === void 0 ? void 0 : value.toString()) !== '') {
                    rq.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);
                }
            }
            return `?${rq === null || rq === void 0 ? void 0 : rq.join('&')}`;
        });
        this.getWithParams = (url, params, options) => __awaiter(this, void 0, void 0, function* () {
            return yield this.get(`${url}${__classPrivateFieldGet(this, _defineParams).call(this, params)}`, options === null || options === void 0 ? void 0 : options.headers, Object.assign(Object.assign({}, options), { encodeURI: false }));
        });
        this.getCacheWithParams = (url, params, headers, options) => __awaiter(this, void 0, void 0, function* () {
            return yield this.getCache(`${url}${__classPrivateFieldGet(this, _defineParams).call(this, params)}`, Object.assign(Object.assign({}, options), { headers, encodeURI: false }));
        });
        this.get = (url, headers, options) => __awaiter(this, void 0, void 0, function* () {
            var _c, _d;
            headers =
                headers ||
                    this.tokenService.customHeaders({
                        url,
                    });
            const encodedUrl = (options === null || options === void 0 ? void 0 : options.encodeURI) === false ? url : encodeURI(url);
            // const hashKey = hash({
            //   encodedUrl,
            //   headers
            // });
            const hashKey = hash({
                encodedUrl,
                headers,
            });
            if (!__classPrivateFieldGet(this, _cache)[hashKey] || Date.addMiliseconds(__classPrivateFieldGet(this, _cache)[hashKey].createdDate, __classPrivateFieldGet(this, _cacheDuration)) < new Date()) {
                __classPrivateFieldGet(this, _cache)[hashKey] = {
                    createdDate: new Date(),
                    subject: new Subject(),
                };
                if ((options === null || options === void 0 ? void 0 : options.responseType) && options.responseType !== 'json') {
                    this.httpClient
                        .get(encodedUrl, { observe: 'body', headers, responseType: options === null || options === void 0 ? void 0 : options.responseType })
                        .pipe(timeout(__classPrivateFieldGet(this, _timeout)))
                        .subscribe(res => {
                        __classPrivateFieldGet(this, _cache)[hashKey].response = {
                            status: 'success',
                            result: res,
                        };
                        __classPrivateFieldGet(this, _cache)[hashKey].subject.next(res);
                    }, err => {
                        __classPrivateFieldGet(this, _cache)[hashKey].response = {
                            status: 'error',
                            result: err,
                        };
                        __classPrivateFieldGet(this, _cache)[hashKey].subject.error(err);
                    });
                }
                else {
                    this.httpClient
                        .get(encodedUrl, { observe: 'response', headers })
                        .pipe(timeout(__classPrivateFieldGet(this, _timeout)))
                        .subscribe(res => {
                        if (res.ok) {
                            __classPrivateFieldGet(this, _cache)[hashKey].response = {
                                status: 'success',
                                result: res.body,
                            };
                            __classPrivateFieldGet(this, _cache)[hashKey].subject.next(res.body);
                        }
                        else {
                            __classPrivateFieldGet(this, _cache)[hashKey].response = {
                                status: 'error',
                                result: res.body,
                            };
                            __classPrivateFieldGet(this, _cache)[hashKey].subject.error(res.body);
                        }
                    }, err => {
                        __classPrivateFieldGet(this, _cache)[hashKey].response = {
                            status: 'error',
                            result: err,
                        };
                        __classPrivateFieldGet(this, _cache)[hashKey].subject.error(err);
                    });
                }
            }
            if ((_c = __classPrivateFieldGet(this, _cache)[hashKey].response) === null || _c === void 0 ? void 0 : _c.status) {
                if (((_d = __classPrivateFieldGet(this, _cache)[hashKey].response) === null || _d === void 0 ? void 0 : _d.status) === 'success') {
                    return __classPrivateFieldGet(this, _cache)[hashKey].response.result;
                }
                throw __classPrivateFieldGet(this, _cache)[hashKey].response.result;
            }
            return __classPrivateFieldGet(this, _cache)[hashKey].subject.pipe(take(1)).toPromise();
        });
        this.getCache = (url, options) => __awaiter(this, void 0, void 0, function* () {
            const headers = (options === null || options === void 0 ? void 0 : options.headers) ||
                this.tokenService.customHeaders({
                    url,
                });
            const encodedUrl = (options === null || options === void 0 ? void 0 : options.encodeURI) === false ? url : encodeURI(url);
            const { get, set, has } = this.cacheService.create({
                encodedUrl,
                headers,
            }, {
                type: options === null || options === void 0 ? void 0 : options.cacheType,
                hours: options === null || options === void 0 ? void 0 : options.cacheHours,
            });
            if (!has() || (options === null || options === void 0 ? void 0 : options.reload)) {
                const result = yield this.get(encodedUrl, options === null || options === void 0 ? void 0 : options.headers, { encodeURI: false });
                set(result);
                return result;
            }
            return get();
        });
        this.delete = (url, headers) => __awaiter(this, void 0, void 0, function* () {
            headers =
                headers ||
                    this.tokenService.customHeaders({
                        url,
                    });
            return yield new Promise((resolve, reject) => {
                this.httpClient
                    .delete(encodeURI(url), { observe: 'response', headers })
                    .pipe(timeout(__classPrivateFieldGet(this, _timeout)))
                    .toPromise()
                    .then(result => {
                    if (result.ok) {
                        resolve(result.body);
                    }
                    else {
                        reject(result.body);
                    }
                })
                    .catch((httpErrorResponse) => {
                    reject(httpErrorResponse);
                });
            });
        });
        this.uploadSingle = (url, option) => {
            return SdUtility.upload(option).then(file => this.upload(url, file));
        };
        this.upload = (url, file) => __awaiter(this, void 0, void 0, function* () {
            const lastDot = file.name.lastIndexOf('.');
            if (lastDot === -1) {
                const message = this.translate(`Invalid file extension`);
                throw new Error(message);
            }
            const formData = new FormData();
            formData.append('file', file, file.name);
            return yield this.post(url, formData);
        });
    }
    get http() {
        return this.httpClient;
    }
}
_timeout = new WeakMap(), _cacheDuration = new WeakMap(), _cache = new WeakMap(), _defineParams = new WeakMap();
SdApiService.ɵprov = ɵɵdefineInjectable({ factory: function SdApiService_Factory() { return new SdApiService(ɵɵinject(HttpClient), ɵɵinject(API_CONFIG, 8), ɵɵinject(SdCacheService), ɵɵinject(SdTokenService)); }, token: SdApiService, providedIn: "root" });
SdApiService.decorators = [
    { type: Injectable, args: [{
                providedIn: 'root',
            },] }
];
SdApiService.ctorParameters = () => [
    { type: HttpClient },
    { type: undefined, decorators: [{ type: Inject, args: [API_CONFIG,] }, { type: Optional }] },
    { type: SdCacheService },
    { type: SdTokenService }
];

class SdHttpService {
    constructor(httpClient, tokenService) {
        this.httpClient = httpClient;
        this.tokenService = tokenService;
        this.get = (url, option) => {
            option = Object.assign(Object.assign({}, option), { headers: option.headers || this.tokenService.customHeaders({
                    url
                }) });
            return this.httpClient.get(url, option);
        };
        this.post = (url, body, option) => {
            option = Object.assign(Object.assign({}, option), { headers: option.headers || this.tokenService.customHeaders({
                    url
                }) });
            return this.httpClient.post(url, body, option);
        };
        this.put = (url, body, option) => {
            option = Object.assign(Object.assign({}, option), { headers: option.headers || this.tokenService.customHeaders({
                    url
                }) });
            return this.httpClient.put(url, body, option);
        };
        this.delete = (url, option) => {
            option = Object.assign(Object.assign({}, option), { headers: option.headers || this.tokenService.customHeaders({
                    url
                }) });
            return this.httpClient.delete(url, option);
        };
        this.request = (method, url, option) => {
            option = Object.assign(Object.assign({}, option), { headers: option.headers || this.tokenService.customHeaders({
                    url
                }) });
            return this.httpClient.request(method, url, option);
        };
    }
}
SdHttpService.ɵprov = ɵɵdefineInjectable({ factory: function SdHttpService_Factory() { return new SdHttpService(ɵɵinject(HttpClient), ɵɵinject(SdTokenService)); }, token: SdHttpService, providedIn: "root" });
SdHttpService.decorators = [
    { type: Injectable, args: [{
                providedIn: 'root'
            },] }
];
SdHttpService.ctorParameters = () => [
    { type: HttpClient },
    { type: SdTokenService }
];

/*
 * Public API Surface of superdev-angular-core
 */

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

export { API_CONFIG, SdApiModule, SdApiService, SdHttpInterceptor, SdHttpService, SdTokenService, TOKEN };
//# sourceMappingURL=sd-angular-core-api.js.map
