import axios, {AxiosInstance, AxiosRequestConfig, AxiosResponse, Method} from 'axios';
import {ContentType, MsHttpClient} from './MsHttpClient'
import {GlobalSettings, SIDStore} from './GlobalSettings'

export interface MsAxiosRequestConfig extends AxiosRequestConfig {
    action?: string;
    inParams?: object;
}

export interface MsAxiosResponse extends AxiosResponse {
    config: MsAxiosRequestConfig;
}

export class DefaultClient implements MsHttpClient {

    private _axios: AxiosInstance;
    private _globalSettings?: GlobalSettings;

    constructor(baseURL: string, responseTimeoutMs: number = 10000) {
        this._axios = axios.create({
            timeout: responseTimeoutMs,
            baseURL: baseURL
        });
    }

    /**
     * 创建默认基于Axios 实现的微服务请求客户端
     * @param globalSettings
     */
    public static create(globalSettings: GlobalSettings) {
        const client = new DefaultClient(globalSettings.gatewayUrl, globalSettings.responseTimeoutMs);
        client._globalSettings = globalSettings;

        client.setRequestInterceptors((config) => {
            const token = DefaultClient.getCookie('midend-token');
            if (token) {
                config.headers.Authorization = token;
            }
            if (globalSettings.sidStore === SIDStore.URI) {
                let uri = config.headers.sid + '/' + config.headers.version
                if (!globalSettings.gatewayUrl.endsWith('/')) {
                    uri = '/' + uri
                }
                config.url = config.url + uri;
            }
            return Promise.resolve(config);
        }, async (error) => {
            if (globalSettings.onFailed) {
                await globalSettings.onFailed(error)
            }
            return Promise.reject(error);
        });

        client.setResponseInterceptors(async (response) => {
            if (response.status === 200) {
                const data = response.data;
                if (globalSettings.onSucceed) {
                    await globalSettings.onSucceed(data)
                }
                return data;
            }
            return Promise.reject(response);
        }, async (error) => {
            if (globalSettings.onFailed) {
                await globalSettings.onFailed(error)
            }
            return Promise.reject(error);
        });
        return client
    }

    private static getCookie(name) {
        if (typeof document === 'undefined' || !document.cookie) {
            return
        }
        let match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
        if (match) {
            return match[2];
        }
        return null
    };

    /**
     * 设置axios Request拦截器
     *
     * @param onFulfilled
     * @param onRejected
     */
    setRequestInterceptors(onFulfilled: (value: MsAxiosRequestConfig) => Promise<MsAxiosRequestConfig>, onRejected?: (error: any) => any) {
        this._axios.interceptors.request.use(
            async (config: MsAxiosRequestConfig) => {
                config.action = config.url;
                config.url = config.url;
                config.inParams = config.params || config.data || {};
                return await onFulfilled(config);
            }
            , onRejected);
    }


    /**
     * 设置axios Response拦截器
     *
     * @param onFulfilled
     * @param onRejected
     */
    setResponseInterceptors(onFulfilled: (value: MsAxiosResponse) => Promise<MsAxiosResponse>, onRejected?: (error: any) => any) {
        this._axios.interceptors.response.use(
            (response: MsAxiosResponse) => {
                return onFulfilled(response);
            }
            , onRejected);
    }

    /**
     * 微服务请求
     *
     * @param method
     * @param contentType
     * @param headers
     * @param parameters
     */
    request(method: Method, contentType: ContentType, headers: object, parameters: any): Promise<any> {
        if (this._isUploadFileRequest(contentType)) {
            return this._upload(contentType, headers, parameters)
        } else {
            return this._request(method, contentType, headers, parameters)
        }
    }


    /**
     * ajax 请求
     *
     * @param method
     * @param contentType
     * @param headers
     * @param parameters
     */
    private _request(method: Method, contentType: string, headers: object, parameters: any) {
        const config: AxiosRequestConfig = {}
        config.method = method
        config.headers = this._parseHeaders(contentType, headers)
        if (method === 'GET') {
            config.params = parameters
        } else {
            config.data = parameters
        }

        return this._axios.request(config)
    }

    /**
     * 文件上传
     */
    private _upload(contentType: string, headers: object, parameters: any) {
        const config: AxiosRequestConfig = {}
        config.headers = this._parseHeaders(contentType, headers)
        const formData: FormData = new FormData()
        for (let attr in parameters) {
            formData.append(attr, parameters[attr])
        }
        return this._axios.post('', formData, config);
    }


    private _isUploadFileRequest(contentType: string): boolean {
        return contentType.indexOf("multipart") > -1
    }


    private _parseHeaders(contentType: string, headers: object): object {
        const _headers = {...headers}
        _headers['Content-Type'] = contentType
        return _headers
    }

}


