import axios from 'axios';
import qs from 'qs';
import isFunction from 'lodash/isFunction';

const CancelToken = axios.CancelToken;
let source = CancelToken.source();

const ax = axios.create({
    cancelToken: source.token,
    paramsSerializer: function(params) {
        return qs.stringify(params, { arrayFormat: 'brackets' });
    },
});

export class Api {
    static request(config, successCb, failCb) {
        const promise = ax.request(config);
        if (isFunction(successCb)) {
            promise.then(successCb);
        }
        if (isFunction(failCb)) {
            promise.catch(failCb);
        }
        return promise;
    }

    static cancel() {
        source.cancel();
        source = CancelToken.source();
        ax.defaults.cancelToken = source.token;
    }

    static setLanguage(language) {
        const formattedLanguage = language.replace('-', '_') || 'de_DE';

        if (ax.defaults.params && ax.defaults.params._language === formattedLanguage) {
            // already set, nothing to do
            return 0;
        } else {
            ax.defaults.params = {
                ...ax.defaults.params,
                _language: formattedLanguage,
            };
            return 1;
        }
    }

    static setChannel(channel) {
        if (ax.defaults.params && ax.defaults.params._channel === channel) {
            // already set, nothing to do
            return 0;
        } else {
            ax.defaults.params = {
                ...ax.defaults.params,
                _channel: channel,
            };
            return 1;
        }
    }

    /**
     * Sets a token in the request params
     * @param token
     */
    static setToken(token) {
        ax.defaults.params = {
            ...ax.defaults.params,
            _token: token,
        };
    }

    /**
     * Sets the Authorization header, or removes it if token is falsy
     * @param token
     */
    static setTokenHeader(token) {
        Api.setHeader('Authorization', token ? `Bearer ${token}` : false);
    }

    /**
     * Sets the Cache-Control header, or removes it if value is falsy
     * @param value
     */
    static setCacheControlHeader(value) {
        Api.setHeader('Cache-Control', value);
    }

    /**
     * Set a value to the specified header key, or remove it if value is falsy
     * @param key
     * @param value
     */
    static setHeader(key, value) {
        if (value) {
            ax.defaults.headers = {
                ...ax.defaults.headers,
                [key]: value,
            };
        } else {
            delete ax.defaults.headers[key];
        }
    }

    static setGETParameter(parameter, value) {
        ax.defaults.params = {
            ...ax.defaults.params,
        };

        ax.defaults.params[parameter] = value;
    }

    static getGETParameters() {
        return {
            ...ax.defaults.params,
        };
    }

    static setBaseURL(url) {
        ax.defaults.baseURL = url;
    }

    static init(config) {
        for (let key in config) {
            ax.defaults[key] = config[key];
        }
    }
}

export const isCancelError = error => {
    return error instanceof axios.Cancel;
};

export default Api;
