/**
 * This file was automatically generated by openapi-codegeneration.
 * DO NOT MODIFY IT BY HAND. Instead, modify the source OpenAPI file,
 * and run openapi-codegeneration to regenerate this file.
 */
/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable @typescript-eslint/ban-ts-comment */
import fetch from 'node-fetch';
import * as RequestValidation from './requestValidation.js';
import * as Types from './types.js';
/**
 * This error class should be used if an error occurs during validation of a request/response.
 * @category Errors
 */
export class ValidationError extends Error {
    errors;
    constructor(message, errors) {
        super(message);
        this.name = 'ValidationError';
        this.errors = errors;
    }
}
/**
 * This error class should be used if an error occurs while fetching a request.
 * @category Errors
 */
export class FetchError extends Error {
    constructor(message) {
        super(message);
        this.name = 'FetchError';
    }
}
/**
 * This error class should be used if the response of the server has a status
 * greater than or equal to 400. This error should contain the validated response.
 * @category Errors
 */
export class UnsuccessfulRequestError extends Error {
    response;
    constructor(message, response) {
        super(message);
        this.response = response;
        this.name = 'UnsuccessfulRequestError';
    }
}
/**
 * This error class should be used if the validation of an url fails.
 * @category Errors
 */
export class InvalidUrlError extends Error {
    constructor(message) {
        super(message);
        this.name = 'InvalidUrlError';
    }
}
/**
 * This function attempts to parse a Response as ResponseData.
 */
async function parseResponse(response) {
    let text = null;
    try {
        text = await response.text();
        const json = JSON.parse(text);
        return { status: response.status, body: json };
    }
    catch {
        return { status: response.status, body: text };
    }
}
/**
 * This function checks if a string is a valid http url.
 * @param string The string to be checked.
 * @returns True if the string is a valid http url.
 */
function isValidHttpUrl(string) {
    let url;
    try {
        url = new URL(string);
    }
    catch (_) {
        return false;
    }
    return url.protocol === 'http:' || url.protocol === 'https:';
}
/**
 * This function takes an url and a pattern for the requested endpoint and parses the contained path parameters.
 * @param url The url to be parsed.
 * @param endpoint Pattern of the requested endpoint.
 * @throws {InvalidUrlError} Thrown if the provided url does not end with the provided endpoint.
 * @returns An array containing all parsed path parameters in order of appearance.
 * @example
 * // returns ["username", "role_name"]
 * parsePathParameters("https://api.example.com/users/username/roles/role_name", "/users/{}/roles/{}")
 */
function parsePathParameters(url, endpoint) {
    const parameterRegex = '([^\/]+)';
    const regex = new RegExp(endpoint.replaceAll('{}', parameterRegex) + '(?:.(?!\\\\))?$');
    const matches = url.match(regex);
    if (!matches)
        throw new InvalidUrlError('Url does not end with the provided endpoint');
    return matches.slice(1);
}
/**
 * This function validates a given http url and parses its path parameters.
 * @param url The url to be validated.
 * @param endpoint Pattern of the requested endpoint.
 * @throws {InvalidUrlError} Thrown if the validation of the provided url fails.
 * @returns An array containing all parsed path parameters in order of appearance (see {@link parsePathParameters}).
 * @example
 * // returns ["username", "role_name"]
 * validateUrl("https://api.example.com/users/username/roles/role_name", "/users/{}/roles/{}")
 */
function validateUrl(url, endpoint) {
    if (!isValidHttpUrl(url))
        throw new InvalidUrlError('Provided url is not a valid http url');
    return parsePathParameters(url, endpoint);
}
/**
 * This function appends a given endpoint to an url.
 * @param url The url to append the endpoint to.
 * @param endpoint The endpoint to be appended.
 * @example
 * // returns "https://api.example.com/devices/device_id/token"
 * appendToUrl("https://api.example.com/devices/device_id", "/token")
 * @example
 * // returns "https://api.example.com/devices/device_id/token"
 * appendToUrl("https://api.example.com/devices/device_id/", "/token")
 * @returns The url with the appended endpoint.
 */
function appendToUrl(url, endpoint) {
    return url.endsWith('/') ? `${url.slice(0, -1)}${endpoint}` : `${url}${endpoint}`;
}
/**
 * Client for the use of the Crosslab API
 * @category Client
 */
export class Client {
    baseUrl;
    serviceUrl;
    accessToken;
    fixedHeaders;
    fetch = async (url, init) => {
        let raw_response;
        const parsedUrl = new URL(url.toString());
        try {
            if (parsedUrl.toString().startsWith(this.baseUrl) ||
                parsedUrl.toString().startsWith(this.serviceUrl)) {
                raw_response = await fetch(url, init);
            }
            else {
                raw_response = await fetch(appendToUrl(this.baseUrl, '/proxy?' + new URLSearchParams([['URL', url.toString()]]).toString()), init);
            }
        }
        catch (error) {
            if (error instanceof Error) {
                throw new FetchError(error.message);
            }
            else if (typeof error === 'string') {
                throw new FetchError(error);
            }
            else {
                throw new FetchError('Something went wrong while trying to fetch the request');
            }
        }
        return await parseResponse(raw_response);
    };
    /**
     * @category Constructors
     */
    constructor(baseUrl, options) {
        this.baseUrl = new URL(baseUrl).toString().slice(0, -1);
        this.serviceUrl = new URL(options.serviceUrl ?? this.baseUrl).toString().slice(0, -1);
        this.accessToken = options.accessToken ?? '';
        this.fixedHeaders = options.fixedHeaders ?? [];
    }
    /**
     * Login user
     *
     * @param username
     * Username of the user.
     * @param password
     * Password of the user.
     * @param options.method
     * Authentication method.
     *
     * @throws {@link FetchError | FetchError }
     * Thrown if fetch fails.
     * @throws {@link ValidationError | ValidationError }
     * Thrown if the request/response validation fails.
     * @throws {@link InvalidUrlError | InvalidUrlError }
     * Thrown if the provided url is not valid for this request.
     * @throws {@link UnsuccessfulRequestError | UnsuccessfulRequestError }
     * Thrown if response is validated but has status greater than or equal to 400.
     *
     * @returns
     * Return the access token.
     */
    async login(username, password, options) {
        const url = appendToUrl(this.baseUrl, '/login');
        const body = {
            username: username,
            password: password,
            method: options?.method,
        };
        if (!RequestValidation.validateLoginInput(body))
            throw new ValidationError('Request validation failed!', RequestValidation.validateLoginInput.errors);
        const response = await this.fetch(new URL(url).toString().replace(this.baseUrl, this.serviceUrl), {
            method: 'POST',
            headers: [
                ['Content-Type', 'application/json'],
                ...this.fixedHeaders,
                ...(options?.headers ?? []),
            ],
            body: JSON.stringify(body),
        });
        if (!RequestValidation.validateLoginOutput(response))
            throw new ValidationError('Response validation failed!', RequestValidation.validateLoginOutput.errors);
        if (Types.isErrorResponse(response))
            throw new UnsuccessfulRequestError(`Server returned response with status ${response.status}`, response);
        this.accessToken = response.body;
    }
    /**
     * Logout user
     *
     * @throws {@link FetchError | FetchError }
     * Thrown if fetch fails.
     * @throws {@link ValidationError | ValidationError }
     * Thrown if the request/response validation fails.
     * @throws {@link InvalidUrlError | InvalidUrlError }
     * Thrown if the provided url is not valid for this request.
     * @throws {@link UnsuccessfulRequestError | UnsuccessfulRequestError }
     * Thrown if response is validated but has status greater than or equal to 400.
     *
     * @returns
     * Successfully logged out the user.
     */
    async logout(options) {
        const url = appendToUrl(this.baseUrl, '/logout');
        const body = { token: this.accessToken };
        if (!RequestValidation.validateLogoutInput(body))
            throw new ValidationError('Request validation failed!', RequestValidation.validateLogoutInput.errors);
        const authorization = `Bearer ${this.accessToken}`;
        const response = await this.fetch(new URL(url).toString().replace(this.baseUrl, this.serviceUrl), {
            method: 'POST',
            headers: [
                ['Content-Type', 'application/json'],
                ['Authorization', authorization],
                ...this.fixedHeaders,
                ...(options?.headers ?? []),
            ],
            body: JSON.stringify(body),
        });
        if (!RequestValidation.validateLogoutOutput(response))
            throw new ValidationError('Response validation failed!', RequestValidation.validateLogoutOutput.errors);
        if (Types.isErrorResponse(response))
            throw new UnsuccessfulRequestError(`Server returned response with status ${response.status}`, response);
        this.accessToken = '';
    }
    /**
     * Get all users
     *
     * @param options.username
     * filter for users with a specific username
     * @param options.url
     * Url of the  to be used.
     *
     * @throws {@link FetchError | FetchError }
     * Thrown if fetch fails.
     * @throws {@link ValidationError | ValidationError }
     * Thrown if the request/response validation fails.
     * @throws {@link InvalidUrlError | InvalidUrlError }
     * Thrown if the provided url is not valid for this request.
     * @throws {@link UnsuccessfulRequestError | UnsuccessfulRequestError }
     * Thrown if response is validated but has status greater than or equal to 400.
     *
     * @returns
     * The JSON representation of the users.
     */
    async listUsers(options) {
        const url = appendToUrl(options?.url ?? this.baseUrl, '/users');
        const parameters = {
            username: options?.username,
        };
        const query = [];
        if (parameters['username'])
            query.push(['username', parameters['username'].toString()]);
        if (!RequestValidation.validateListUsersInput(parameters))
            throw new ValidationError('Request validation failed!', RequestValidation.validateListUsersInput.errors);
        const authorization = `Bearer ${this.accessToken}`;
        const response = await this.fetch(new URL(url).toString().replace(this.baseUrl, this.serviceUrl) +
            '?' +
            new URLSearchParams(query), {
            method: 'GET',
            headers: [
                ['Content-Type', 'application/json'],
                ['Authorization', authorization],
                ...this.fixedHeaders,
                ...(options?.headers ?? []),
            ],
        });
        if (!RequestValidation.validateListUsersOutput(response))
            throw new ValidationError('Response validation failed!', RequestValidation.validateListUsersOutput.errors);
        if (Types.isErrorResponse(response))
            throw new UnsuccessfulRequestError(`Server returned response with status ${response.status}`, response);
        return response.body;
    }
    /**
     * Create a user
     *
     * @param user
     * User to be created.
     * @param options.url
     * Url of the  to be used.
     *
     * @throws {@link FetchError | FetchError }
     * Thrown if fetch fails.
     * @throws {@link ValidationError | ValidationError }
     * Thrown if the request/response validation fails.
     * @throws {@link InvalidUrlError | InvalidUrlError }
     * Thrown if the provided url is not valid for this request.
     * @throws {@link UnsuccessfulRequestError | UnsuccessfulRequestError }
     * Thrown if response is validated but has status greater than or equal to 400.
     *
     * @returns
     * The JSON representation of the created user.
     */
    async createUser(user, options) {
        const url = appendToUrl(options?.url ?? this.baseUrl, '/users');
        const body = user;
        if (!RequestValidation.validateCreateUserInput(body))
            throw new ValidationError('Request validation failed!', RequestValidation.validateCreateUserInput.errors);
        const authorization = `Bearer ${this.accessToken}`;
        const response = await this.fetch(new URL(url).toString().replace(this.baseUrl, this.serviceUrl), {
            method: 'POST',
            headers: [
                ['Content-Type', 'application/json'],
                ['Authorization', authorization],
                ...this.fixedHeaders,
                ...(options?.headers ?? []),
            ],
            body: JSON.stringify(body),
        });
        if (!RequestValidation.validateCreateUserOutput(response))
            throw new ValidationError('Response validation failed!', RequestValidation.validateCreateUserOutput.errors);
        if (Types.isErrorResponse(response))
            throw new UnsuccessfulRequestError(`Server returned response with status ${response.status}`, response);
        return response.body;
    }
    /**
     * Get a user
     *
     * @param url
     * Url of the resource to be accessed.
     *
     * @throws {@link FetchError | FetchError }
     * Thrown if fetch fails.
     * @throws {@link ValidationError | ValidationError }
     * Thrown if the request/response validation fails.
     * @throws {@link InvalidUrlError | InvalidUrlError }
     * Thrown if the provided url is not valid for this request.
     * @throws {@link UnsuccessfulRequestError | UnsuccessfulRequestError }
     * Thrown if response is validated but has status greater than or equal to 400.
     *
     * @returns
     * The JSON respresentation of the user.
     */
    async getUser(url, options) {
        const urlSuffix = '/users/{}'.split('{}').at(-1) ?? '';
        if (urlSuffix && !url.endsWith(urlSuffix))
            url = appendToUrl(url, urlSuffix);
        const [user_id] = validateUrl(new URL(url).toString(), '/users/{}');
        const parameters = {
            user_id: user_id,
        };
        if (!RequestValidation.validateGetUserInput(parameters))
            throw new ValidationError('Request validation failed!', RequestValidation.validateGetUserInput.errors);
        const authorization = `Bearer ${this.accessToken}`;
        const response = await this.fetch(new URL(url).toString().replace(this.baseUrl, this.serviceUrl), {
            method: 'GET',
            headers: [
                ['Content-Type', 'application/json'],
                ['Authorization', authorization],
                ...this.fixedHeaders,
                ...(options?.headers ?? []),
            ],
        });
        if (!RequestValidation.validateGetUserOutput(response))
            throw new ValidationError('Response validation failed!', RequestValidation.validateGetUserOutput.errors);
        if (Types.isErrorResponse(response))
            throw new UnsuccessfulRequestError(`Server returned response with status ${response.status}`, response);
        return response.body;
    }
    /**
     * Update a user
     *
     * @param url
     * Url of the resource to be accessed.
     * @param user
     * Updated user
     *
     * @throws {@link FetchError | FetchError }
     * Thrown if fetch fails.
     * @throws {@link ValidationError | ValidationError }
     * Thrown if the request/response validation fails.
     * @throws {@link InvalidUrlError | InvalidUrlError }
     * Thrown if the provided url is not valid for this request.
     * @throws {@link UnsuccessfulRequestError | UnsuccessfulRequestError }
     * Thrown if response is validated but has status greater than or equal to 400.
     *
     * @returns
     * The JSON representation of the updated user.
     */
    async updateUser(url, user, options) {
        const urlSuffix = '/users/{}'.split('{}').at(-1) ?? '';
        if (urlSuffix && !url.endsWith(urlSuffix))
            url = appendToUrl(url, urlSuffix);
        const [user_id] = validateUrl(new URL(url).toString(), '/users/{}');
        const body = user;
        const parameters = {
            user_id: user_id,
        };
        if (!RequestValidation.validateUpdateUserInput(parameters, body))
            throw new ValidationError('Request validation failed!', RequestValidation.validateUpdateUserInput.errors);
        const authorization = `Bearer ${this.accessToken}`;
        const response = await this.fetch(new URL(url).toString().replace(this.baseUrl, this.serviceUrl), {
            method: 'PATCH',
            headers: [
                ['Content-Type', 'application/json'],
                ['Authorization', authorization],
                ...this.fixedHeaders,
                ...(options?.headers ?? []),
            ],
            body: JSON.stringify(body),
        });
        if (!RequestValidation.validateUpdateUserOutput(response))
            throw new ValidationError('Response validation failed!', RequestValidation.validateUpdateUserOutput.errors);
        if (Types.isErrorResponse(response))
            throw new UnsuccessfulRequestError(`Server returned response with status ${response.status}`, response);
        return response.body;
    }
    /**
     * Delete a user
     *
     * @param url
     * Url of the resource to be accessed.
     *
     * @throws {@link FetchError | FetchError }
     * Thrown if fetch fails.
     * @throws {@link ValidationError | ValidationError }
     * Thrown if the request/response validation fails.
     * @throws {@link InvalidUrlError | InvalidUrlError }
     * Thrown if the provided url is not valid for this request.
     * @throws {@link UnsuccessfulRequestError | UnsuccessfulRequestError }
     * Thrown if response is validated but has status greater than or equal to 400.
     *
     * @returns
     * User deleted successfully
     */
    async deleteUser(url, options) {
        const urlSuffix = '/users/{}'.split('{}').at(-1) ?? '';
        if (urlSuffix && !url.endsWith(urlSuffix))
            url = appendToUrl(url, urlSuffix);
        const [user_id] = validateUrl(new URL(url).toString(), '/users/{}');
        const parameters = {
            user_id: user_id,
        };
        if (!RequestValidation.validateDeleteUserInput(parameters))
            throw new ValidationError('Request validation failed!', RequestValidation.validateDeleteUserInput.errors);
        const authorization = `Bearer ${this.accessToken}`;
        const response = await this.fetch(new URL(url).toString().replace(this.baseUrl, this.serviceUrl), {
            method: 'DELETE',
            headers: [
                ['Content-Type', 'application/json'],
                ['Authorization', authorization],
                ...this.fixedHeaders,
                ...(options?.headers ?? []),
            ],
        });
        if (!RequestValidation.validateDeleteUserOutput(response))
            throw new ValidationError('Response validation failed!', RequestValidation.validateDeleteUserOutput.errors);
        if (Types.isErrorResponse(response))
            throw new UnsuccessfulRequestError(`Server returned response with status ${response.status}`, response);
    }
    /**
     * Get identity
     *
     * @throws {@link FetchError | FetchError }
     * Thrown if fetch fails.
     * @throws {@link ValidationError | ValidationError }
     * Thrown if the request/response validation fails.
     * @throws {@link InvalidUrlError | InvalidUrlError }
     * Thrown if the provided url is not valid for this request.
     * @throws {@link UnsuccessfulRequestError | UnsuccessfulRequestError }
     * Thrown if response is validated but has status greater than or equal to 400.
     *
     * @returns
     * The JSON representation of the corresponding user.
     */
    async getIdentity(options) {
        const url = appendToUrl(this.baseUrl, '/identity');
        if (!RequestValidation.validateGetIdentityInput())
            throw new ValidationError('Request validation failed!', RequestValidation.validateGetIdentityInput.errors);
        const authorization = `Bearer ${this.accessToken}`;
        const response = await this.fetch(new URL(url).toString().replace(this.baseUrl, this.serviceUrl), {
            method: 'GET',
            headers: [
                ['Content-Type', 'application/json'],
                ['Authorization', authorization],
                ...this.fixedHeaders,
                ...(options?.headers ?? []),
            ],
        });
        if (!RequestValidation.validateGetIdentityOutput(response))
            throw new ValidationError('Response validation failed!', RequestValidation.validateGetIdentityOutput.errors);
        if (Types.isErrorResponse(response))
            throw new UnsuccessfulRequestError(`Server returned response with status ${response.status}`, response);
        return response.body;
    }
    /**
     * Update identity
     *
     * @param user
     * Updated identity.
     *
     * @throws {@link FetchError | FetchError }
     * Thrown if fetch fails.
     * @throws {@link ValidationError | ValidationError }
     * Thrown if the request/response validation fails.
     * @throws {@link InvalidUrlError | InvalidUrlError }
     * Thrown if the provided url is not valid for this request.
     * @throws {@link UnsuccessfulRequestError | UnsuccessfulRequestError }
     * Thrown if response is validated but has status greater than or equal to 400.
     *
     * @returns
     * The JSON representation of the updated user.
     */
    async updateIdentity(user, options) {
        const url = appendToUrl(this.baseUrl, '/identity');
        const body = user;
        if (!RequestValidation.validateUpdateIdentityInput(body))
            throw new ValidationError('Request validation failed!', RequestValidation.validateUpdateIdentityInput.errors);
        const authorization = `Bearer ${this.accessToken}`;
        const response = await this.fetch(new URL(url).toString().replace(this.baseUrl, this.serviceUrl), {
            method: 'PATCH',
            headers: [
                ['Content-Type', 'application/json'],
                ['Authorization', authorization],
                ...this.fixedHeaders,
                ...(options?.headers ?? []),
            ],
            body: JSON.stringify(body),
        });
        if (!RequestValidation.validateUpdateIdentityOutput(response))
            throw new ValidationError('Response validation failed!', RequestValidation.validateUpdateIdentityOutput.errors);
        if (Types.isErrorResponse(response))
            throw new UnsuccessfulRequestError(`Server returned response with status ${response.status}`, response);
        return response.body;
    }
    /**
     * Create a new token
     *
     * @param body
     *
     * @throws {@link FetchError | FetchError }
     * Thrown if fetch fails.
     * @throws {@link ValidationError | ValidationError }
     * Thrown if the request/response validation fails.
     * @throws {@link InvalidUrlError | InvalidUrlError }
     * Thrown if the provided url is not valid for this request.
     * @throws {@link UnsuccessfulRequestError | UnsuccessfulRequestError }
     * Thrown if response is validated but has status greater than or equal to 400.
     *
     * @returns
     * The token was created successfully.
     */
    async createToken(body, options) {
        const url = appendToUrl(this.baseUrl, '/token');
        if (!RequestValidation.validateCreateTokenInput(body))
            throw new ValidationError('Request validation failed!', RequestValidation.validateCreateTokenInput.errors);
        const response = await this.fetch(new URL(url).toString().replace(this.baseUrl, this.serviceUrl), {
            method: 'POST',
            headers: [
                ['Content-Type', 'application/json'],
                ...this.fixedHeaders,
                ...(options?.headers ?? []),
            ],
            body: JSON.stringify(body),
        });
        if (!RequestValidation.validateCreateTokenOutput(response))
            throw new ValidationError('Response validation failed!', RequestValidation.validateCreateTokenOutput.errors);
        if (Types.isErrorResponse(response))
            throw new UnsuccessfulRequestError(`Server returned response with status ${response.status}`, response);
        return response.body;
    }
}
//# sourceMappingURL=client.js.map