import axios from 'axios';
import axiosRetry from 'axios-retry';
import { BaseError, mergeOptions } from 'ebec';

function isClientError(error) {
    if (typeof error !== 'object') {
        return false;
    }
    if (Object.prototype.hasOwnProperty.call(error, 'config') && Object.prototype.hasOwnProperty.call(error, 'isAxiosError') && typeof error.isAxiosError === 'boolean') {
        return !!error.isAxiosError;
    }
    return axios.isAxiosError(error);
}

/*
 * Copyright (c) 2021.
 * Author Peter Placzek (tada5hi)
 * For the full copyright and license information,
 * view the LICENSE file that was distributed with this source code.
 */ // eslint-disable-next-line @typescript-eslint/ban-types
function hasOwnProperty(obj, prop) {
    return Object.prototype.hasOwnProperty.call(obj, prop);
}

/*
 * Copyright (c) 2022.
 * Author Peter Placzek (tada5hi)
 * For the full copyright and license information,
 * view the LICENSE file that was distributed with this source code.
 */ function _extends() {
    _extends = Object.assign || function(target) {
        for(var i = 1; i < arguments.length; i++){
            var source = arguments[i];
            for(var key in source){
                if (Object.prototype.hasOwnProperty.call(source, key)) {
                    target[key] = source[key];
                }
            }
        }
        return target;
    };
    return _extends.apply(this, arguments);
}
function buildConfig(config) {
    config = config || {};
    var _config_retry;
    return _extends({}, config, {
        extra: config.extra || {},
        retry: (_config_retry = config.retry) != null ? _config_retry : false
    });
}

const instanceMap$1 = {};
function hasConfig(key) {
    return hasOwnProperty(instanceMap$1, key || 'default');
}
function setConfig(value, key) {
    key = key || 'default';
    instanceMap$1[key] = buildConfig(value);
    return instanceMap$1[key];
}
function useConfig(key) {
    key = key || 'default';
    if (typeof instanceMap$1[key] === 'undefined') {
        return buildConfig();
    }
    return instanceMap$1[key];
}
function unsetConfig(key) {
    key = key || 'default';
    if (hasOwnProperty(instanceMap$1, key)) {
        delete instanceMap$1[key];
    }
}

/*
 * Copyright (c) 2022.
 * Author Peter Placzek (tada5hi)
 * For the full copyright and license information,
 * view the LICENSE file that was distributed with this source code.
 */ var AuthorizationHeaderType;
(function(AuthorizationHeaderType) {
    AuthorizationHeaderType["BEARER"] = 'Bearer';
    AuthorizationHeaderType["BASIC"] = 'Basic';
    AuthorizationHeaderType["X_API_KEY"] = 'X-API-Key';
    AuthorizationHeaderType["API_KEY"] = 'API-Key';
})(AuthorizationHeaderType || (AuthorizationHeaderType = {}));

/*
 * Copyright (c) 2022.
 * Author Peter Placzek (tada5hi)
 * For the full copyright and license information,
 * view the LICENSE file that was distributed with this source code.
 */ var ErrorCode;
(function(ErrorCode) {
    ErrorCode["AUTHORIZATION_HEADER_INVALID"] = 'auth_header_invalid';
    ErrorCode["AUTHORIZATION_HEADER_PARSE"] = 'auth_header_parse';
    ErrorCode["AUTHORIZATION_HEADER_TYPE_PARSE"] = 'auth_header_type_parse';
})(ErrorCode || (ErrorCode = {}));

class AuthorizationHeaderError extends BaseError {
    /* istanbul ignore next */ static parse() {
        throw new AuthorizationHeaderError({
            code: ErrorCode.AUTHORIZATION_HEADER_PARSE,
            message: 'The authorization header value could not be parsed.'
        });
    }
    /* istanbul ignore next */ static parseType() {
        throw new AuthorizationHeaderError({
            code: ErrorCode.AUTHORIZATION_HEADER_TYPE_PARSE,
            message: 'The authorization header value type must either be \'Bearer\' or \'Basic\''
        });
    }
    constructor(options){
        super(mergeOptions(options || {}), {
            code: ErrorCode.AUTHORIZATION_HEADER_INVALID,
            message: 'The authorization header is not valid.'
        });
    }
}

function parseAuthorizationHeader(value) {
    const parts = value.split(' ');
    if (parts.length < 2) {
        throw AuthorizationHeaderError.parseType();
    }
    const type = parts[0].toLowerCase();
    const id = parts[1];
    switch(type){
        case 'basic':
            {
                const base64Decoded = Buffer.from(id, 'base64').toString('utf-8');
                const base64Parts = base64Decoded.split(':');
                if (base64Parts.length !== 2) {
                    throw AuthorizationHeaderError.parse();
                }
                return {
                    type: AuthorizationHeaderType.BASIC,
                    username: base64Parts[0],
                    password: base64Parts[1]
                };
            }
        case 'bearer':
            return {
                type: AuthorizationHeaderType.BEARER,
                token: id
            };
        case 'api-key':
        case 'x-api-key':
            return {
                type: type === 'api-key' ? AuthorizationHeaderType.API_KEY : AuthorizationHeaderType.X_API_KEY,
                key: id
            };
        default:
            throw AuthorizationHeaderError.parseType();
    }
}
function stringifyAuthorizationHeader(header) {
    switch(header.type){
        case AuthorizationHeaderType.BASIC:
            {
                const basicStr = Buffer.from(`${header.username}:${header.password}`).toString('base64');
                return `Basic ${basicStr}`;
            }
        case AuthorizationHeaderType.BEARER:
            return `Bearer ${header.token}`;
        case AuthorizationHeaderType.X_API_KEY:
        case AuthorizationHeaderType.API_KEY:
            return `${header.type} ${header.key}`;
    }
    return '';
}

class Client {
    // ---------------------------------------------------------------------------------
    setDriver(client) {
        this.driver = client;
    }
    /**
     * Return driver config.
     *
     * @return AxiosDefaults<any>
     */ get config() {
        return this.driver.defaults;
    }
    /**
     * Return base url
     *
     * @param config
     *
     * @return string
     */ getUri(config) {
        return this.driver.getUri(config);
    }
    // ---------------------------------------------------------------------------------
    /**
     * Set a header for all upcoming requests.
     *
     * @param key
     * @param value
     */ setHeader(key, value) {
        this.driver.defaults.headers.common[key] = value;
        return this;
    }
    /**
     * Unset a specific for all upcoming requests.
     *
     * @param key
     */ unsetHeader(key) {
        if (key in this.driver.defaults.headers.common) {
            delete this.driver.defaults.headers.common[key];
        }
        return this;
    }
    /**
     * Unset all defined headers for the upcoming requests.
     */ resetHeader() {
        this.driver.defaults.headers.common = {};
        return this;
    }
    // ---------------------------------------------------------------------------------
    /**
     * Set an authorization header (basic, api-key, bearer).
     *
     * @param options
     */ setAuthorizationHeader(options) {
        this.setHeader('Authorization', stringifyAuthorizationHeader(options));
        return this;
    }
    /**
     * Unset an authorization header.
     */ unsetAuthorizationHeader() {
        this.unsetHeader('Authorization');
        return this;
    }
    // ---------------------------------------------------------------------------------
    /**
     * Make a custom request.
     *
     * @param config
     */ request(config) {
        return this.driver.request(config);
    }
    // ---------------------------------------------------------------------------------
    /**
     * Request a resource with the GET method.
     *
     * @param url
     * @param config
     */ get(url, config) {
        return this.driver.get(url, config);
    }
    // ---------------------------------------------------------------------------------
    /**
     * Delete a resource with the DELETE method.
     *
     * @param url
     * @param config
     */ delete(url, config) {
        return this.driver.delete(url, config);
    }
    // ---------------------------------------------------------------------------------
    /**
     * Make a verification resource with the HEAD method.
     *
     * @param url
     * @param config
     */ head(url, config) {
        return this.driver.head(url, config);
    }
    // ---------------------------------------------------------------------------------
    /**
     * Create a resource with the POST method.
     *
     * @param url
     * @param data
     * @param config
     */ post(url, data, config) {
        return this.driver.post(url, data, config);
    }
    /**
     * Create a resource with the POST method and FormData formatted payload.
     *
     * @param url
     * @param data
     * @param config
     */ postForm(url, data, config) {
        return this.driver.postForm(url, data, config);
    }
    // ---------------------------------------------------------------------------------
    /**
     * Update a resource with the PUT method.
     *
     * @param url
     * @param data
     * @param config
     */ put(url, data, config) {
        return this.driver.put(url, data, config);
    }
    /**
     * Update a resource with the PUT method and FormData formatted payload.
     *
     * @param url
     * @param data
     * @param config
     */ putForm(url, data, config) {
        return this.driver.putForm(url, data, config);
    }
    // ---------------------------------------------------------------------------------
    /**
     * Update a resource with the PATCH method.
     *
     * @param url
     * @param data
     * @param config
     */ patch(url, data, config) {
        return this.driver.patch(url, data, config);
    }
    /**
     * Update a resource with the PATCH method and FormData formatted payload.
     *
     * @param url
     * @param data
     * @param config
     */ patchForm(url, data, config) {
        return this.driver.patchForm(url, data, config);
    }
    //---------------------------------------------------------------------------------
    /**
     * Mount a response interceptor.
     *
     * @param onFulfilled
     * @param onRejected
     */ mountResponseInterceptor(onFulfilled, onRejected) {
        return this.driver.interceptors.response.use(onFulfilled, onRejected);
    }
    /**
     * Unmount a response interceptor.
     *
     * @param id
     */ unmountResponseInterceptor(id) {
        this.driver.interceptors.response.eject(id);
        return this;
    }
    //---------------------------------------------------------------------------------
    /**
     * Mount a request interceptor.
     *
     * @param onFulfilled
     * @param onRejected
     */ mountRequestInterceptor(onFulfilled, onRejected) {
        return this.driver.interceptors.request.use(onFulfilled, onRejected);
    }
    /**
     * Unmount a request interceptor.
     *
     * @param id
     */ unmountRequestInterceptor(id) {
        this.driver.interceptors.request.eject(id);
        return this;
    }
    // ---------------------------------------------------------------------------------
    constructor(input){
        const config = buildConfig(input);
        const client = axios.create(config.driver);
        if (config.retry) {
            let retryConfig = {};
            if (typeof config.retry !== 'boolean') {
                retryConfig = config.retry;
            }
            axiosRetry(client, retryConfig);
        }
        this.driver = client;
    }
}

const instanceMap = {};
function hasClient(key) {
    return hasOwnProperty(instanceMap, key || 'default');
}
function setClient(client, key) {
    key = key || 'default';
    instanceMap[key] = client;
    return client;
}
function useClient(key) {
    key = key || 'default';
    if (Object.prototype.hasOwnProperty.call(instanceMap, key)) {
        return instanceMap[key];
    }
    const config = useConfig(key);
    const instance = createClient(config);
    instanceMap[key] = instance;
    return instance;
}
function unsetClient(key) {
    key = key || 'default';
    if (hasOwnProperty(instanceMap, key)) {
        delete instanceMap[key];
    }
}
function createClient(input) {
    return new Client(input);
}

const client = createClient();

export { AuthorizationHeaderError, AuthorizationHeaderType, Client, ErrorCode, buildConfig, createClient, client as default, hasClient, hasConfig, hasOwnProperty, isClientError, parseAuthorizationHeader, setClient, setConfig, stringifyAuthorizationHeader, unsetClient, unsetConfig, useClient, useConfig };
//# sourceMappingURL=index.mjs.map
