package com.sonic.common.rpc;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;

import com.sonic.common.exception.BizException;
import org.apache.commons.lang3.StringUtils;

import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

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

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

    @Getter
    private HttpClient httpClient;

    private AuthRequestProxy authRequestProxy;

    public RpcAuthClientImpl(AuthRequestProxy authRequestProxy) {
        this(authRequestProxy, HttpClient.Config.EMPTY);
    }

    public RpcAuthClientImpl(AuthRequestProxy authRequestProxy, HttpClient.Config config) {
        this.authRequestProxy = authRequestProxy;
        httpClient = new OkHttpClientImpl(config);
    }

    public RpcAuthClientImpl(AuthRequestProxy authRequestProxy, Supplier<Map<String, String>> requestHeaderSupplier) {
        this(authRequestProxy);
        customHeaderSupplier = requestHeaderSupplier;
    }

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

    @Override
    public <T> T execute(HttpClient.HttpMethod httpMethod, String url, RequestParams requestParams, Function<String, Result<T>> converter) {
        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) {
        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.stream()
                .forEach(headerSupplier -> headerSupplier.get().entrySet()
                        .forEach(headerEntry ->
                                requestParams.addHeaderIfAbsent(headerEntry.getKey(), headerEntry.getValue())
                        ));

        if (customHeaderSupplier != null) {
            Map<String, String> map = customHeaderSupplier.get();
            map.entrySet().forEach(e -> {
                requestParams.addHeader(e.getKey(), e.getValue());
            });
        }

        return authRequestProxy.request(token -> {
            ///XXX 注意此处有一个副作用
            requestParams.addAuthorization(token);
            return supplier.get();
        });
    }
}
