package com.sonic.common.rpc;

import java.util.List;
import java.util.Map;
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 com.google.common.base.Preconditions;

import lombok.Getter;

/**
 * 一个RpcClient的wrapper. 可以方便的在 RpcClient 和 RpcAuthClient 切换.
 * 对于RpcAuthClient还可以在构造的时候传递hostResolver, 统一处理host.
 */
public class RpcClientWrapper implements RpcClient {
    private Supplier<String> hostResolver;
    @Getter
    private volatile RpcClient activeRpcClient;

    private RpcClient rpcAuthClient;
    private RpcClient rpcClient;

    @lombok.Builder
    public RpcClientWrapper(RpcClient rpcAuthClient, RpcClient rpcClient,
                            Supplier<String> hostResolver, ClientType defaultClientType) {
        Preconditions.checkArgument(rpcAuthClient != null || rpcClient != null, "rpcAuthClient和rpcClient必须有一个填入");
        Preconditions.checkArgument(defaultClientType != null, "clientType必须有值");
        Preconditions.checkArgument(hostResolver != null, "hostResolver必须有值");
        if (rpcAuthClient != null) {
            Preconditions.checkArgument(rpcAuthClient instanceof RpcAuthClientImpl, "rpcAuthClient 必须是 RpcAuthClientImpl.class 实现");
        }
        if (rpcClient != null) {
            Preconditions.checkArgument(rpcClient instanceof RpcClientImpl, "rpcClient 必须是 RpcClientImpl.class 实现");
        }

        this.rpcClient = rpcClient;
        this.rpcAuthClient = rpcAuthClient;
        this.hostResolver = hostResolver;
        activate(defaultClientType);
    }

    @Override
    public <T> T execute(HttpClient.HttpMethod httpMethod, String path, RequestParams requestParams, Function<String, Result<T>> converter) {
        return activeRpcClient.execute(httpMethod, resolvePath(path), requestParams, converter);
    }

    @Override
    public <R> R execute(HttpClient.HttpMethod httpMethod, String path, RequestParams requestParams, BiFunction<byte[], Map<String, List<String>>, R> responder) {
        return activeRpcClient.execute(httpMethod, resolvePath(path), requestParams, responder);
    }

    protected String resolvePath(String path) {
        // 如果hostResolver不为空, 且path没有包含protocol与host. 则尝试将host与path拼接
        if (hostResolver != null && !path.startsWith("http")) {
            String host = hostResolver.get();
            if (!path.startsWith("/")) {
                path = "/" + path;
            }
            //构建时去掉多余的 '/'
            return (host.endsWith("/") ? StringUtils.removeEnd(host, "/") : host) + path;

        }
        return path;
    }

    public void activate(ClientType type) {
        if (type == ClientType.RPC_CLIENT) {
            Preconditions.checkState(rpcClient != null);
            activeRpcClient = rpcClient;
        } else if (type == ClientType.RPC_AUTH_CLIENT) {
            Preconditions.checkState(rpcAuthClient != null);
            Preconditions.checkState(hostResolver != null);
            activeRpcClient = rpcAuthClient;
        } else {
            throw new BizException(GlobalResultCode.INVALID_PARAMS.getErrorCode(), "不支持的 ClientType");
        }
    }

    public enum ClientType {
        /** 服务间访问带 token 认证 */
        RPC_AUTH_CLIENT,
        /** 服务间访问不带 token 认证 */
        RPC_CLIENT
    }
}
