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

import cn.axzo.framework.jackson.utility.JSON;
import cn.axzo.workflow.common.model.response.BpmPageResult;
import cn.axzo.workflow.starter.common.exception.WorkflowRpcInvokeException;
import cn.azxo.framework.common.model.CommonResponse;
import com.google.common.collect.Lists;
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.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;

import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_W_E;

/**
 * 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 convertWrapper(response, type);
        }
        if (response.status() == 404 || response.status() == 204) {
            return Optional.empty();
        }
        Type enclosedType = Util.resolveLastTypeParameter(type, Optional.class);
        return Optional.ofNullable(convertWrapper(response, enclosedType));
    }

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

    Object convertWrapper(Response response, Type enclosedType) throws IOException {
        if (response.request().headers().containsKey(HEADER_W_E)) {
            return delegate.decode(response, enclosedType);
        } else {
            return convert(response, enclosedType);
        }
    }

    /**
     * 这里做返回数据的解析，并处理引擎返回的一些正常的业务异常
     *
     * @param response
     * @param type
     * @return
     */
    Object convert(Response response, Type type) throws IOException {
        ParameterizedTypeImpl wrappedType;
        List<Class<?>> cls = Lists.newArrayList(BpmPageResult.class, Collection.class, List.class, Map.class);
        if (type instanceof ParameterizedType && !cls.contains(((ParameterizedType) type).getRawType())) {
            wrappedType = (ParameterizedTypeImpl) type;
        } else {
            wrappedType = ParameterizedTypeImpl.make(CommonResponse.class, new Type[]{type}, null);
        }
        Object decode = delegate.decode(response, wrappedType);
        if (log.isDebugEnabled()) {
            log.debug("workflow engine starter response :{}", JSON.toJSONString(decode));
        }
        if (decode instanceof CommonResponse) {
            CommonResponse<?> commonResponse = (CommonResponse<?>) decode;
            if (response.status() == 202) {
                log.warn("workflow engine starter rpc invoke return msg: {}", commonResponse.getMsg());
                throw new WorkflowRpcInvokeException(commonResponse.getMsg());
            } else if (response.status() != 200) {
                log.error("WorkflowEngineStarterDecoder has error, status:{} msg: {}", response.status(), commonResponse.getMsg());
            }
            return commonResponse.getData();
        }
        return decode;
    }
}
