import * as i2 from '@rxap/open-api';
import { RxapOpenApiError, OpenApiHttpResponseError, OpenApiConfigService, DEFAULT_OPEN_API_REMOTE_METHOD_META_DATA, RXAP_OPEN_API_STRICT_VALIDATOR, DISABLE_SCHEMA_VALIDATION, DISABLE_VALIDATION, SchemaValidationMixin } from '@rxap/open-api';
import { BaseRemoteMethod, RxapRemoteMethod } from '@rxap/remote-method';
import { coerceString } from '@rxap/utilities';
import * as i0 from '@angular/core';
import { isDevMode, Injector, Injectable, Inject, Optional } from '@angular/core';
import * as i1 from '@angular/common/http';
import { HttpErrorResponse, HttpEventType, HttpClient } from '@angular/common/http';
import { __decorate, __metadata } from 'tslib';
import { Mixin } from '@rxap/mixin';
import { BaseHttpRemoteMethod } from '@rxap/remote-method/http';
import { firstValueFrom } from 'rxjs';
import { retry, tap, filter, take, timeout } from 'rxjs/operators';

class RxapOpenApiRemoteMethodError extends RxapOpenApiError {
    constructor(message, code, scope) {
        super(message, code, scope);
        this.addSubPackageName('remote-method');
    }
}

class GetPageAdapterRemoteMethod extends BaseRemoteMethod {
    constructor(remoteMethod, paginator, options) {
        super(null, remoteMethod.metadata);
        this.remoteMethod = remoteMethod;
        this.paginator = paginator;
        this.options = options;
    }
    static BuildFilter(filterEvent) {
        const filter = [];
        if (filterEvent && typeof filterEvent !== 'string') {
            for (const [key, value] of Object.entries(filterEvent)) {
                if (value !== null && value !== undefined && `${value}` !== '') {
                    const valueString = coerceString(value);
                    if (valueString) {
                        filter.push([key, valueString].join('|'));
                    }
                }
            }
        }
        return filter;
    }
    async _call(event) {
        const parameters = {
            pageIndex: event.page?.pageIndex ?? 0,
            pageSize: event.page?.pageSize ?? 10,
            sortBy: event.sort?.active ?? this.options?.sortBy ?? undefined,
            // use the || operator to set the default sort direction if the sort direction is undefined or an empty string
            sortDirection: event.sort?.direction ?? this.options?.sortDirection ?? undefined,
            filter: GetPageAdapterRemoteMethod.BuildFilter(event.filter),
            ...(event.parameters ?? {}),
        };
        const response = await this.remoteMethod.call({ parameters });
        if (event.setTotalLength) {
            event.setTotalLength(response.total);
        }
        if (this.paginator) {
            this.paginator.length = response.total;
        }
        return response.rows;
    }
}
function GetPageAdapterFactory(remoteMethod, paginator) {
    return new GetPageAdapterRemoteMethod(remoteMethod, paginator);
}
function GetPageAdapterFactoryWithOptions(options = {}) {
    return (remoteMethod, paginator) => {
        return new GetPageAdapterRemoteMethod(remoteMethod, paginator, options);
    };
}

function IsOperationFromMetadataInline(metadata) {
    return typeof metadata.operation === 'string';
}
function RxapOpenApiRemoteMethod(operationOrId, serverIndex = 0) {
    return function (target) {
        const id = typeof operationOrId === 'string' ?
            operationOrId :
            (IsOperationFromMetadataInline(operationOrId) ?
                operationOrId.operationId :
                operationOrId.operation.operationId ?? operationOrId.fallbackId);
        if (!id) {
            throw new Error('The operationId for the open api remote method is not defined');
        }
        const metadata = {
            id,
            serverIndex,
        };
        if (typeof operationOrId !== 'string') {
            metadata.operation = operationOrId.operation;
            metadata.serverId = operationOrId.serverId;
        }
        RxapRemoteMethod(metadata)(target);
    };
}
let OpenApiRemoteMethod = class OpenApiRemoteMethod extends BaseHttpRemoteMethod {
    constructor(http, injector, openApiConfigService, metadata = null, strict = null, disableSchemaValidation = null, disableValidation = null) {
        super(http, injector, metadata);
        this.disableSchemaValidation = false;
        this.disableValidation = false;
        this.strict = false;
        this.metadata['operation'] ??= openApiConfigService.getOperation(this.metadata.id);
        if (typeof this.metadata['operation'] === 'string') {
            try {
                this.metadata['operation'] = JSON.parse(this.metadata['operation']);
            }
            catch (e) {
                throw new Error(`could not parse the remote method operation string into an object: ${this.constructor.name}`);
            }
        }
        const operation = this.metadata['operation'];
        this.applyMetadata({
            id: operation.operationId,
            url: () => openApiConfigService.getBaseUrl(this.metadata['serverIndex'], this.metadata['serverId']) +
                operation.path,
            method: operation.method,
            withCredentials: this.metadata.withCredentials ?? true,
            ignoreUndefined: this.metadata['ignoreUndefined'] ?? true,
        });
        this.strict = strict || this.metadata['strict'] || false;
        this.disableSchemaValidation = disableSchemaValidation || this.metadata['disableSchemaValidation'] || false;
        this.disableValidation = disableValidation || this.metadata['disableValidation'] || false;
    }
    get operation() {
        return this.metadata['operation'];
    }
    /**
     * Instead of returning the response body the full response object is returned
     */
    async callWithResponse(args = {}) {
        this.init();
        this.executionsInProgress$.increase();
        const result = await this._callWithResponse(args);
        this.executionsInProgress$.decrease();
        if (result.body) {
            this.executed$.next(result.body);
            this.executed(result.body);
        }
        return result;
    }
    // TODO : update to the new call method concept (the remove of the _call method concept)
    _callWithResponse(args = {}) {
        if (!this.disableValidation) {
            this.validateParameters(this.operation, args.parameters, this.strict);
            this.validateRequestBody(this.operation, args.requestBody, this.strict);
        }
        return firstValueFrom(this.http.request(this.updateRequest(this.buildHttpOptions(this.operation, args.parameters, args.requestBody, this.metadata['ignoreUndefined']))).pipe(retry(this.metadata.retry ?? 0), tap({
            error: (error) => {
                if (error instanceof HttpErrorResponse) {
                    this.interceptors?.forEach(interceptor => interceptor
                        .next({
                        response: error,
                        parameters: args.parameters,
                        requestBody: args.requestBody,
                    }));
                }
            },
        }), filter((event) => event.type === HttpEventType.Response), tap((response) => {
            if (!this.disableValidation) {
                this.validateResponse(this.operation, response, this.strict);
            }
        }), tap((response) => {
            this.interceptors?.forEach(interceptor => interceptor
                .next({
                response,
                parameters: args.parameters,
                requestBody: args.requestBody,
            }));
        }), take(1), timeout(this.timeout)));
    }
    async _call(args = {}) {
        if (!this.disableValidation) {
            this.validateParameters(this.operation, args.parameters, this.strict);
            this.validateRequestBody(this.operation, args.requestBody, this.strict);
        }
        let response;
        try {
            response = await this._callWithResponse(args);
        }
        catch (error) {
            if (error instanceof HttpErrorResponse) {
                throw new OpenApiHttpResponseError(error, this.metadata);
            }
            else {
                throw error;
            }
        }
        if (response.body) {
            return response.body;
        }
        if (isDevMode()) {
            console.warn('The response body is empty!');
        }
        return null;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: OpenApiRemoteMethod, deps: [{ token: HttpClient }, { token: Injector }, { token: OpenApiConfigService }, { token: DEFAULT_OPEN_API_REMOTE_METHOD_META_DATA, optional: true }, { token: RXAP_OPEN_API_STRICT_VALIDATOR, optional: true }, { token: DISABLE_SCHEMA_VALIDATION, optional: true }, { token: DISABLE_VALIDATION, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: OpenApiRemoteMethod }); }
};
OpenApiRemoteMethod = __decorate([
    Mixin(SchemaValidationMixin),
    __metadata("design:paramtypes", [HttpClient,
        Injector,
        OpenApiConfigService, Object, Object, Object, Object])
], OpenApiRemoteMethod);
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: OpenApiRemoteMethod, decorators: [{
            type: Injectable
        }], ctorParameters: () => [{ type: i1.HttpClient, decorators: [{
                    type: Inject,
                    args: [HttpClient]
                }] }, { type: i0.Injector, decorators: [{
                    type: Inject,
                    args: [Injector]
                }] }, { type: i2.OpenApiConfigService, decorators: [{
                    type: Inject,
                    args: [OpenApiConfigService]
                }] }, { type: undefined, decorators: [{
                    type: Optional
                }, {
                    type: Inject,
                    args: [DEFAULT_OPEN_API_REMOTE_METHOD_META_DATA]
                }] }, { type: undefined, decorators: [{
                    type: Optional
                }, {
                    type: Inject,
                    args: [RXAP_OPEN_API_STRICT_VALIDATOR]
                }] }, { type: undefined, decorators: [{
                    type: Optional
                }, {
                    type: Inject,
                    args: [DISABLE_SCHEMA_VALIDATION]
                }] }, { type: undefined, decorators: [{
                    type: Optional
                }, {
                    type: Inject,
                    args: [DISABLE_VALIDATION]
                }] }] });

class OpenApiRemoteMethodLoader {
    constructor(openApiConfig, http, injector) {
        this.openApiConfig = openApiConfig;
        this.http = http;
        this.injector = injector;
    }
    load(definitionId) {
        const operation = this.openApiConfig.getOperation(definitionId);
        if (operation) {
            return new OpenApiRemoteMethod(this.http, this.injector, this.openApiConfig, {
                id: definitionId,
                operation,
            });
        }
        return null;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: OpenApiRemoteMethodLoader, deps: [{ token: OpenApiConfigService }, { token: HttpClient }, { token: i0.Injector }], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: OpenApiRemoteMethodLoader, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: OpenApiRemoteMethodLoader, decorators: [{
            type: Injectable,
            args: [{ providedIn: 'root' }]
        }], ctorParameters: () => [{ type: i2.OpenApiConfigService, decorators: [{
                    type: Inject,
                    args: [OpenApiConfigService]
                }] }, { type: i1.HttpClient, decorators: [{
                    type: Inject,
                    args: [HttpClient]
                }] }, { type: i0.Injector }] });

// region 
// endregion

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

export { GetPageAdapterFactory, GetPageAdapterFactoryWithOptions, GetPageAdapterRemoteMethod, IsOperationFromMetadataInline, OpenApiRemoteMethod, OpenApiRemoteMethodLoader, RxapOpenApiRemoteMethod, RxapOpenApiRemoteMethodError };
//# sourceMappingURL=rxap-open-api-remote-method.mjs.map
