import * as i0 from '@angular/core';
import { Injector, Injectable, Inject, Optional } from '@angular/core';
import * as i1 from '@angular/common/http';
import { HttpClient, HttpRequest, HttpEventType, HttpResponse } from '@angular/common/http';
import * as i1$1 from '@rxap/remote-method';
import { BaseRemoteMethod, RxapRemoteMethodError, REMOTE_METHOD_META_DATA, RemoteMethodLoader } from '@rxap/remote-method';
import { hasIndexSignature } from '@rxap/utilities';
import { retry, tap, filter, map, timeout } from 'rxjs/operators';
import { firstValueFrom } from 'rxjs';

class BaseHttpRemoteMethod extends BaseRemoteMethod {
    constructor(http, injector, metaData = null) {
        super(injector, metaData);
        this.http = http;
        this.timeout = 60 * 1000;
        this.timeout = this.metadata.timeout ?? this.timeout;
        if (http === undefined) {
            throw new RxapRemoteMethodError('HttpClient is undefined. Ensure that the HttpClient is added to the deps property!', '', this.constructor.name);
        }
        if (!(http instanceof HttpClient)) {
            throw new RxapRemoteMethodError('The property http is not an instance of HttpClinent. Check the deps property!', '', this.constructor.name);
        }
    }
    init() {
        super.init();
        this._httpRequest = new HttpRequest(this.metadata.method, this.getRequestUrl(), null, {
            headers: this.metadata.headers,
            reportProgress: this.metadata.reportProgress,
            params: this.metadata.params,
            responseType: this.metadata.responseType || 'json',
            withCredentials: this.metadata.withCredentials,
        });
    }
    updateRequest(parameters) {
        let url = this._httpRequest.url;
        if (parameters && parameters['pathParams']) {
            url = this.buildUrlWithParams(url, parameters.pathParams);
        }
        return this._httpRequest.clone({
            withCredentials: this.metadata.withCredentials,
            ...parameters,
            url,
        });
    }
    buildUrlWithParams(url, pathParams) {
        if (pathParams) {
            if (!hasIndexSignature(pathParams)) {
                throw new RxapRemoteMethodError(`Path params for remote method '${this.id}' has not an index signature`, '', this.constructor.name);
            }
            const matches = url.match(/\{[^}]+\}/g);
            if (matches) {
                for (const match of matches) {
                    const param = match.substr(1, match.length - 2);
                    if (pathParams[param] === undefined) {
                        throw new RxapRemoteMethodError(`Path params for remote method '${this.id}' has not a defined value for '${param}'`, '', this.constructor.name);
                    }
                    url = url.replace(match, encodeURIComponent(pathParams[param]));
                }
            }
        }
        return url;
    }
    getRequestUrl() {
        if (typeof this.metadata.url === 'function') {
            return this.metadata.url();
        }
        return this.metadata.url;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: BaseHttpRemoteMethod, deps: [{ token: HttpClient }, { token: Injector }, { token: REMOTE_METHOD_META_DATA, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: BaseHttpRemoteMethod }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: BaseHttpRemoteMethod, decorators: [{
            type: Injectable
        }], ctorParameters: () => [{ type: i1.HttpClient, decorators: [{
                    type: Inject,
                    args: [HttpClient]
                }] }, { type: i0.Injector, decorators: [{
                    type: Inject,
                    args: [Injector]
                }] }, { type: undefined, decorators: [{
                    type: Optional
                }, {
                    type: Inject,
                    args: [REMOTE_METHOD_META_DATA]
                }] }] });

class HttpRemoteMethod extends BaseHttpRemoteMethod {
    // eslint-disable-next-line @typescript-eslint/no-empty-function
    onSentEvent(event) {
    }
    // eslint-disable-next-line @typescript-eslint/no-empty-function
    onHeaderResponse(event) {
    }
    // eslint-disable-next-line @typescript-eslint/no-empty-function
    onResponse(event) {
    }
    // eslint-disable-next-line @typescript-eslint/no-empty-function
    onProgressEvent(event) {
    }
    // TODO : make abstract to force implementation to handel parameter transformation
    createHttpRequestParameters(parameters) {
        return parameters ?? {};
    }
    transformer(response) {
        return response;
    }
    _call(parameters) {
        return firstValueFrom(this.http.request(this.updateRequest(this.createHttpRequestParameters(parameters)))
            .pipe(retry(this.metadata.retry ?? 0), tap(event => {
            switch (event.type) {
                case HttpEventType.Sent:
                    this.onSentEvent(event);
                    break;
                case HttpEventType.Response:
                    this.onResponse(event);
                    break;
                case HttpEventType.DownloadProgress:
                    this.onProgressEvent(event);
                    break;
                case HttpEventType.UploadProgress:
                    this.onProgressEvent(event);
                    break;
                case HttpEventType.ResponseHeader:
                    this.onHeaderResponse(event);
                    break;
            }
        }), filter((event) => event instanceof HttpResponse), map((event) => event.body), map(body => this.transformer(body)), timeout(this.timeout)));
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: HttpRemoteMethod, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: HttpRemoteMethod }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: HttpRemoteMethod, decorators: [{
            type: Injectable
        }] });

class HttpRemoteMethodLoader {
    // Instead of extanding the RemoteMethodLoader class the RemoteMethodLoader instance
    // will be injected, else there could be multiple instance of RemoteMethodLoader's. Then
    // the RefreshService will not trigger a refresh for HttpRemoteMethod's
    constructor(remoteMethodLoader) {
        this.remoteMethodLoader = remoteMethodLoader;
    }
    request$(remoteMethodIdOrInstanceOrToken, parameters, metadata, injector, notFoundValue, flags) {
        const remoteMethod = this.remoteMethodLoader.load(remoteMethodIdOrInstanceOrToken, metadata, injector, notFoundValue, flags);
        if (!(remoteMethod instanceof HttpRemoteMethod)) {
            throw new RxapRemoteMethodError(`The remote method is not a HttpRemoteMethod`, '', 'HttpRemoteMethodLoader');
        }
        return remoteMethod.call(parameters);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: HttpRemoteMethodLoader, deps: [{ token: RemoteMethodLoader }], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: HttpRemoteMethodLoader, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: HttpRemoteMethodLoader, decorators: [{
            type: Injectable,
            args: [{ providedIn: 'root' }]
        }], ctorParameters: () => [{ type: i1$1.RemoteMethodLoader, decorators: [{
                    type: Inject,
                    args: [RemoteMethodLoader]
                }] }] });

// region 
// endregion

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

export { BaseHttpRemoteMethod, HttpRemoteMethod, HttpRemoteMethodLoader };
//# sourceMappingURL=rxap-remote-method-http.mjs.map
