package cn.axzo.workflow.starter.feign.ext;

import cn.azxo.framework.common.model.CommonResponse;
import feign.Response;
import feign.Util;
import feign.codec.Decoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;

import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Objects;
import java.util.Optional;

/**
 * Workflow Engine Starter Complex Invoke Client Decoder
 *
 * @author wangli
 * @since 2024/5/31 14:55
 */
final class WorkflowEngineStarterDecoder implements Decoder {
    private final Logger log = LoggerFactory.getLogger(WorkflowEngineStarterDecoder.class);
    final Decoder delegate;

    public WorkflowEngineStarterDecoder(Decoder delegate) {
        Objects.requireNonNull(delegate, "Decoder must not be null. ");
        this.delegate = delegate;
    }

    @Override
    public Object decode(Response response, Type type) throws IOException {
        if (!isOptional(type)) {
            return convert(response, type);
        }
        if (response.status() == 404 || response.status() == 204) {
            return Optional.empty();
        }
        Type enclosedType = Util.resolveLastTypeParameter(type, Optional.class);
        return Optional.ofNullable(convert(response, enclosedType));
    }

    static boolean isOptional(Type type) {
        if (!(type instanceof ParameterizedType)) {
            return false;
        }
        ParameterizedType parameterizedType = (ParameterizedType) type;
        return parameterizedType.getRawType().equals(Optional.class);
    }

    /**
     * 这里做返回数据的解析，并处理引擎返回的一些正常的业务异常
     *
     * @param response
     * @param type
     * @return
     */
    Object convert(Response response, Type type) throws IOException {
        ParameterizedTypeImpl wrappedType;
        if (type instanceof ParameterizedType) {
            wrappedType = (ParameterizedTypeImpl) type;
        } else {
            wrappedType = ParameterizedTypeImpl.make(CommonResponse.class, new Type[]{type}, null);
        }
        Object decode = delegate.decode(response, wrappedType);
        if (decode instanceof CommonResponse) {
            CommonResponse<?> commonResponse = (CommonResponse<?>) decode;
            if (response.status() == 202) {
                log.warn("workflow engine starter rpc invoke return msg: {}", commonResponse.getMsg());
            }
            return commonResponse.getData();
        }
        return decode;
    }
}
