package com.qmth.boot.core.retrofit.interceptor;

import com.qmth.boot.core.retrofit.exception.RetrofitResponseError;
import okhttp3.*;
import okio.Buffer;
import okio.BufferedSource;
import okio.GzipSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

public class ErrorDecodeInterceptor implements Interceptor {

    public static final Logger log = LoggerFactory.getLogger(ErrorDecodeInterceptor.class);

    public static final String GZIP = "gzip";

    public static final String CONTENT_ENCODING = "Content-Encoding";

    public static final String IDENTITY = "identity";

    @Override
    public Response intercept(Chain chain) throws IOException {
        Response response = chain.proceed(chain.request());
        if (response.isSuccessful()) {
            return response;
        }
        throw new RetrofitResponseError(response.code(), readResponseBody(response));
    }

    /**
     * read ResponseBody as String
     *
     * @param response response
     * @return ResponseBody String
     * @throws IOException
     */
    public static String readResponseBody(Response response) {
        try {
            Headers headers = response.headers();
            if (bodyHasUnknownEncoding(headers)) {
                return null;
            }
            ResponseBody responseBody = response.body();
            if (responseBody == null) {
                return null;
            }

            BufferedSource source = responseBody.source();
            // Buffer the entire body.
            source.request(Long.MAX_VALUE);
            Buffer buffer = source.getBuffer();

            if (GZIP.equalsIgnoreCase(headers.get(CONTENT_ENCODING))) {
                try (GzipSource gzippedResponseBody = new GzipSource(buffer.clone())) {
                    buffer = new Buffer();
                    buffer.writeAll(gzippedResponseBody);
                }
            }
            Charset charset = StandardCharsets.UTF_8;
            MediaType contentType = responseBody.contentType();
            if (contentType != null) {
                charset = contentType.charset(StandardCharsets.UTF_8);
            }
            return buffer.clone().readString(charset);
        } catch (Exception e) {
            log.error("Retrofit response decode error", e);
            return null;
        }
    }

    private static boolean bodyHasUnknownEncoding(Headers headers) {
        String contentEncoding = headers.get(CONTENT_ENCODING);
        return contentEncoding != null && !IDENTITY.equalsIgnoreCase(contentEncoding) && !GZIP
                .equalsIgnoreCase(contentEncoding);
    }
}
