import { ServiceClient } from './ServiceClient'
import { HttpMethodType } from "./enums/HttpMethodType";
import { RequestBodyType } from "./enums/RequestBodyType";
import { IHttpResponse } from "./utils/http/IHttpResponse";
import { SimpleHttpUtil } from "./utils/http/SimpleHttpUtil";
import { GatewayConfig } from "./config/GatewayConfig";
import { ServiceClientConfig } from "../core/config/ServiceClientConfig";
import UuidUtil from "./utils/UuidUtil";
import { MsConsts } from "./defines/MsConsts";
import CookieUtils from "./utils/CookieUtils"


/**
 * 微服务客户端使用接口
 * @author WuFenglin
 **/
export class ServiceClientImpl implements ServiceClient {

    private gatewayConfig: GatewayConfig = new GatewayConfig();
    private serviceClientConfig: ServiceClientConfig;
    private simpleHttpUtil: SimpleHttpUtil;

    constructor(serviceClientConfig: ServiceClientConfig) {
        this.serviceClientConfig = serviceClientConfig;
        this.simpleHttpUtil = new SimpleHttpUtil(this.serviceClientConfig)
    }


    async call<T = any, R = IHttpResponse<T>>(httpMethod: HttpMethodType, headers: object, params: object, bodyObj: object, bodyType: RequestBodyType): Promise<R> {
        let requestBodyObj = bodyObj;
        if (bodyType == RequestBodyType.WWW_FORM) {
            requestBodyObj = params
        }
        return this.sendRequest(httpMethod, headers, params, requestBodyObj, bodyType)
    }

    async get<T = any, R = IHttpResponse<T>>(headers: object, params: object): Promise<R> {
        return this.sendRequest(HttpMethodType.GET, headers, params, {}, RequestBodyType.WWW_FORM)
    }

    async upload<T = any, R = IHttpResponse<T>>(headers: object, params: object, formData: FormData): Promise<R> {
        let bodyObj = params || {}
        return this.sendRequest(HttpMethodType.UPLOAD, headers, params, bodyObj, RequestBodyType.WWW_FORM, formData)
    }


    private async sendRequest<T = any, R = IHttpResponse<T>>(method: HttpMethodType, headers: object
        , params: object, bodyObj: object, bodyType: RequestBodyType, formData?: FormData): Promise<R> {
        let result: IHttpResponse<R> | undefined;
        const gatewayUrl = this.gatewayConfig.getHostAddress()
        this.processHeaders(headers);

        switch (method) {
            case HttpMethodType.UPLOAD:
                if (formData != null) {
                    result = await this.simpleHttpUtil.upload(gatewayUrl, params, formData, headers);
                } else {
                    throw new Error('Upload Error files is not empty...')
                }
                break;
            default:
                result = await this.simpleHttpUtil.request(method, gatewayUrl, params, bodyObj, headers, bodyType);
                break;
        }

        return result.data;

    }

    private processHeaders(headers: object) {
        let parentCallId = "";
        let uuid = UuidUtil.get();
        headers[MsConsts.MS_CLIENT_VERSION_KEY] = MsConsts.MS_CLIENT_VERSION;
        headers[MsConsts.PARENT_CALL_ID_KEY] = parentCallId;
        headers[MsConsts.TRACE_ID_KEY] = uuid;
        headers[MsConsts.CALL_ID_KEY] = uuid;
        headers[MsConsts.SPAN_ID_KEY] = uuid;

    }
}