package cn.axzo.workflow.server.common.util;

import cn.axzo.basics.common.util.AssertUtil;
import cn.axzo.framework.domain.ServiceException;
import cn.axzo.framework.domain.web.result.ApiListResult;
import cn.axzo.framework.domain.web.result.ApiResult;
import cn.azxo.framework.common.model.CommonResponse;
import cn.hutool.core.date.StopWatch;
import cn.hutool.core.lang.Assert;
import cn.hutool.http.HttpStatus;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;

import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Supplier;

/**
 * 外部rpc接口 返回 CommonResponse
 *
 * @author tanjie@axzo.cn
 * @date 2022/5/23 11:08
 */
@Slf4j
public class RpcExternalUtil {

    /**
     * 常用的RPC请求返回值解析，如果 被请求方 返回非200会抛出异常
     */
    public static <T> T rpcProcessor(Supplier<CommonResponse<T>> supplier, String operationType, Object... param) {

        return rpcProcessorMayThrow(supplier, operationType, commonResponse -> {
            throw new ServiceException(commonResponse.getMsg());
        }, param);
    }

    public static <T> T rpcApiResultProcessor(Supplier<ApiResult<T>> supplier, String operationType, Object... param) {
        log.info(operationType + "-Param: " + JSONUtil.toJsonStr(param));
        ApiResult<T> result = printLatency(supplier, operationType);
        log.info(operationType + "-Result: " + JSONUtil.toJsonStr(result));
        Assert.notNull(result, "服务调用异常");
        Assert.isTrue(result.getCode() == 200, "服务调用异常:" + result.getMsg());
        return result.getData();
    }

    /**
     * 常用的RPC请求返回值解析，如果 被请求方 返回非200会抛出异常
     *
     * @param supplier      ApiListResult类型的RPC接口
     * @param operationType 接口方法描述
     * @param param         接口入参
     * @return 接口返回值
     */
    public static <T> List<T> rpcApiListResultProcessor(Supplier<ApiListResult<T>> supplier, String operationType, Object... param) {
        log.info(operationType + "-Param: " + JSONUtil.toJsonStr(param));
        ApiListResult<T> result = printLatency(supplier, operationType);
        log.info(operationType + "-Result: " + JSONUtil.toJsonStr(result));
        Assert.notNull(result, "服务调用异常");
        Assert.isTrue(result.isSuccess(), "服务调用异常:" + result.getMsg());
        return result.getData();
    }

    public static <T> T rpcProcessorMayThrow(Supplier<CommonResponse<T>> supplier, String operationType, Consumer<CommonResponse<T>> throwConsumer, Object... param) {
        AssertUtil.notNull(throwConsumer, "自定义的异常处理不可为空");
        log.info(operationType + "-Param: " + JSONUtil.toJsonStr(param));
        CommonResponse<T> result = printLatency(supplier, operationType);
        log.info(operationType + "-Result: " + JSONUtil.toJsonStr(result));

        Assert.notNull(result, "服务调用异常");
        // 200自定义处理
        if (HttpStatus.HTTP_OK != result.getCode()) {
            throwConsumer.accept(result);
        }
        return result.getData();
    }

    public static <R> R printLatency(Supplier<R> function, String optType) {
        StopWatch stopWatch = new StopWatch(optType);
        stopWatch.start(optType);
        R r = function.get();
        stopWatch.stop();
        log.info(stopWatch.shortSummary(TimeUnit.MILLISECONDS));
        return r;
    }


    public static <T> T rpcProfileProcessor(Supplier<CommonResponse<T>> supplier, String operationType, Object... param) {
        log.info(operationType + "-Param: " + JSONUtil.toJsonStr(param));
        StopWatch stopWatch = new StopWatch(operationType);
        stopWatch.start(operationType);
        CommonResponse<T> result = supplier.get();
        stopWatch.stop();
        log.info("-Result: " + JSONUtil.toJsonStr(result));
        log.info(stopWatch.shortSummary(TimeUnit.MILLISECONDS));
        Assert.notNull(result, "服务调用异常");
        // 200自定义处理
        if (HttpStatus.HTTP_OK != result.getCode() && 404 != result.getCode()) {
            throw new ServiceException(result.getMsg());
        }

        return result.getData();
    }
}
