package com.sonic.common.rpc;

import com.sonic.common.exception.BizException;
import com.sonic.common.utils.LogUtils;
import com.google.common.collect.Lists;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * @author code
 */
@Slf4j
public class RpcClientImpl implements RpcClient {

    protected Supplier<Map<String, String>> customHeaderSupplier;

    @Getter
    private HttpClient httpClient;

    private List<String> uriPathPrefix = Lists.newArrayList("/api/");

    public RpcClientImpl() {
        this(HttpClient.Config.EMPTY);
    }

    public RpcClientImpl(HttpClient.Config config) {
        httpClient = new OkHttpClientImpl(config);
    }

    public RpcClientImpl(HttpClient.Config config, List<String> rootPath) {
        httpClient = new OkHttpClientImpl(config);
        if(!CollectionUtils.isEmpty(rootPath)) {
            uriPathPrefix = rootPath;
        }
    }

    public RpcClientImpl(Supplier<Map<String, String>> requestHeaderSupplier) {
        this(HttpClient.Config.EMPTY);
        customHeaderSupplier = requestHeaderSupplier;
    }

    public RpcClientImpl(HttpClient.Config config, Supplier<Map<String, String>> requestHeaderSupplier) {
        this(config);
        customHeaderSupplier = requestHeaderSupplier;
    }


    @Override
    public <T> T execute(HttpClient.HttpMethod httpMethod, String url, RequestParams requestParams, Function<String, Result<T>> converter) {
        String traceId = LogUtils.getTraceId();
        if(StringUtils.isNotEmpty(traceId)){
            requestParams.addHeader("X-TRACE-ID",traceId);
        }
        Objects.requireNonNull(url);

        Optional<String> resp = requestBySupplier(requestParams, () -> this.getHttpClient().execute(httpMethod, url, requestParams));
        Result<T> result = converter.apply(resp.orElse(StringUtils.EMPTY));
        if (!result.isSuccess()) {
            throw new BizException(result.getErrorCode(), result.getErrorMsg());
        }
        return result.getContent();
    }

    @Override
    public <R> R execute(HttpClient.HttpMethod httpMethod, String url, RequestParams requestParams, BiFunction<byte[], Map<String, List<String>>, R> responder) {
        String traceId = LogUtils.getTraceId();
        if(StringUtils.isNotEmpty(traceId)){
            requestParams.addHeader("X-TRACE-ID",traceId);
        }
        Objects.requireNonNull(url);

        Optional<R> resp = requestBySupplier(requestParams, () -> this.getHttpClient().execute(httpMethod, url, requestParams, responder));
        return resp.orElseGet(() -> responder.apply(new byte[0], Collections.emptyMap()));
    }

    <T> Optional<T> requestBySupplier(RequestParams requestParams, Supplier<T> supplier) {
        Objects.requireNonNull(requestParams);

        //XXX 附加默认的header, 以及自定义的header
        DEFAULT_HEADER_SUPPLIERS
                .forEach(headerSupplier -> headerSupplier.get().forEach(requestParams::addHeaderIfAbsent));

        if (customHeaderSupplier != null) {
            Map<String, String> map = customHeaderSupplier.get();
            map.forEach(requestParams::addHeader);
        }

        return Optional.ofNullable(supplier.get());
    }

}
