package com.usky.demo.feign;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.CollectionType;
import com.usky.common.core.bean.ApiResult;
import com.usky.demo.domain.HistorysInnerResultVO;
import com.usky.demo.domain.LastInnerResultVO;
import feign.Response;
import feign.Util;
import feign.codec.Decoder;

import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Optional;

/**
 * 兼容 TSDB 两种响应：裸 JSON 数组（旧实现）与 {@link ApiResult} 包装（新实现）。
 */
public class TsdbProxyApiResultFeignDecoder implements Decoder {

    private final Decoder delegate;
    private final ObjectMapper objectMapper;

    public TsdbProxyApiResultFeignDecoder(Decoder delegate, ObjectMapper objectMapper) {
        this.delegate = delegate;
        this.objectMapper = objectMapper;
    }

    @Override
    public Object decode(Response response, Type type) throws IOException {
        if (response.body() == null) {
            return delegate.decode(response, type);
        }
        byte[] bodyData = Util.toByteArray(response.body().asInputStream());
        String trimmed = new String(bodyData, StandardCharsets.UTF_8).trim();
        if (trimmed.startsWith("[")) {
            Optional<Object> wrapped = wrapJsonArrayAsApiResult(bodyData, type);
            if (wrapped.isPresent()) {
                return wrapped.get();
            }
        }
        Response rebuilt = Response.builder()
                .status(response.status())
                .reason(response.reason())
                .headers(response.headers())
                .request(response.request())
                .body(bodyData)
                .build();
        return delegate.decode(rebuilt, type);
    }

    @SuppressWarnings("unchecked")
    private Optional<Object> wrapJsonArrayAsApiResult(byte[] bodyData, Type type) throws IOException {
        if (!(type instanceof ParameterizedType)) {
            return Optional.empty();
        }
        ParameterizedType pt = (ParameterizedType) type;
        if (!ApiResult.class.isAssignableFrom((Class<?>) pt.getRawType())) {
            return Optional.empty();
        }
        Type dataType = pt.getActualTypeArguments()[0];
        if (!(dataType instanceof ParameterizedType)) {
            return Optional.empty();
        }
        ParameterizedType listPt = (ParameterizedType) dataType;
        if (!List.class.isAssignableFrom((Class<?>) listPt.getRawType())) {
            return Optional.empty();
        }
        Type elemType = listPt.getActualTypeArguments()[0];
        if (!(elemType instanceof Class)) {
            return Optional.empty();
        }
        Class<?> elemClass = (Class<?>) elemType;
        if (elemClass != LastInnerResultVO.class && elemClass != HistorysInnerResultVO.class) {
            return Optional.empty();
        }
        CollectionType listJavaType = objectMapper.getTypeFactory().constructCollectionType(List.class, elemClass);
        List<?> list = objectMapper.readValue(bodyData, listJavaType);
        return Optional.of(ApiResult.success((List) list));
    }
}
