package com.yidianling.ydlcommon.custom.http;

import android.support.annotation.Nullable;
import android.text.TextUtils;
import com.yidianling.ydlcommon.core.base.BaseApplication;
import com.yidianling.common.tools.LogUtil;
import com.yidianling.common.tools.RxNetTool;
import com.yidianling.ydlcommon.BuildConfig;
import okhttp3.Response;
import okhttp3.*;
import okhttp3.internal.http.HttpHeaders;
import okio.Buffer;
import okio.BufferedSource;

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

import static okhttp3.internal.Util.closeQuietly;

/**
 * Created by Jim on 2017/12/20 0020.
 */

class PostCacheInterceptor implements Interceptor {

    final DiskLruCacheHelper cache;

    public PostCacheInterceptor(DiskLruCacheHelper cache) {
        this.cache = cache;
    }

    private final int REQUEST_URL = 0;
    private final int REQUEST_METHOD = 1;
    private final int REQUESTCONTENTTYPE = 2;
    private final int PROTOCAL = 3;
    private final int CODE = 4;
    private final int MESSAGE = 5;
    private final int REPONSE_BODY = 6;
    private final int MEDIA_TYPE = 7;
    private final int SETN_REQUEST_AT_MILLIS = 8;
    private final int RECEIVE_REPONSE_AT_MILLIS = 9;
    private final int CACHE_LENGTH = 10;


    @Override
    public Response intercept(Chain chain) throws IOException {

        //匹配是否为需要读取缓存逻辑
        if (!isNeedCache(chain.request().url().toString())) {
            //没有网络连接的时候 并且不再缓存策略里的 返回无网络
            if (!RxNetTool.isConnected(BaseApplication.Companion.getApp())) {
                Request request = chain.request();
                Response originalResponse = chain.proceed(request);
                int maxTime = 0;
                return originalResponse.newBuilder()
                        //这里的设置的是我们的没有网络的缓存时间，想设置多少就是多少。
                        .header("Cache-Control", "public, only-if-cached, max-stale="+maxTime)
                        .removeHeader("Pragma")
                        .build();
            }
            return chain.proceed(chain.request());
        }

        //获取缓存
        String key = createKey(chain.request());
        LogUtil.d("cache key: " + key);
        Response cacheResponse = null;
        String cacheRes = cache != null && key != null
                ? cache.getAsString(key)
                : null;

        if (!TextUtils.isEmpty(cacheRes)) {
            LogUtil.d("cacheRes: " + cacheRes);
            cacheResponse = combineCacheToResponse(cacheRes);
        }

        //没有网络连接的时候读取缓存
        if (!RxNetTool.isConnected(BaseApplication.Companion.getApp())) {
            if (cacheResponse != null) {
                return cacheResponse;
            }else {
                Request request = chain.request();
                Response originalResponse = chain.proceed(request);
                int maxTime = 0;
                return originalResponse.newBuilder()
                        //这里的设置的是我们的没有网络的缓存时间，想设置多少就是多少。
                        .header("Cache-Control", "public, only-if-cached, max-stale="+maxTime)
                        .removeHeader("Pragma")
                        .build();
            }
        }
        //获取网络响应
        Request netWorkRequest = chain.request();
        Response networkResponse = null;
        try {
            networkResponse = chain.proceed(netWorkRequest);
        } finally {
            if (networkResponse == null) {
                LogUtil.d("close cache response...");
                if (cacheResponse != null && cacheResponse.body() != null) {
                    closeQuietly(cacheResponse.body());
                }
                return networkResponse;
            }
        }
        LogUtil.d("prepare update cache response...");
        //更新缓存
        if (cacheResponse != null) {
            Response response = null;
            response = networkResponse.newBuilder()
                    .request(new Request.Builder()
                            .method("GET", null)
                            .url(netWorkRequest.url())
                            .headers(netWorkRequest.headers())
                            .tag(netWorkRequest.tag())
                            .build())
                    .build();
            LogUtil.d("update cache response");
            if (key != null) {
                cache.put(key, createCache(response));
            }
            return networkResponse;

        }

        Request newRequest = new Request.Builder()
                .method("GET", null)
                .url(netWorkRequest.url())
                .headers(netWorkRequest.headers())
                .tag(netWorkRequest.tag())
                .build();

        Response newResponse = networkResponse.newBuilder()
                .request(newRequest)
                .build();

        LogUtil.d("init cache response");
        //放入缓存
        if (cache != null) {
            LogUtil.d("url: " + netWorkRequest.url().toString());
            if (HttpHeaders.hasBody(newResponse)) {
                try {
                    LogUtil.d("chain request url: " + newResponse.request().url());
                    if (key != null) {
                        cache.put(key, createCache(newResponse));
                        LogUtil.d("put cache response key: " + key);
                    }
                    String resp1 = cache.getAsString(key);
                    LogUtil.d("resp1: " + resp1);
                    return networkResponse;
                } catch (Exception e) {
                    LogUtil.d("put cache exception: " + e);
                }
            }
        }
        return newResponse;
    }


    private String createKey(Request request) {
        RequestBody requestBody = request.body();
        Charset charset = Charset.forName("UTF-8");
        String url = request.url().toString();
        StringBuilder sb = new StringBuilder();
        sb.append(url + "&");
        if (null == requestBody && request.method().equals("GET")){
//            sb.append(request.url().query());
        }else {
            if (null == requestBody){
                return sb.toString();
            }
            MediaType type = requestBody.contentType();
            if (type != null) {
                charset = type.charset() == null ? charset : type.charset();
            }
            Buffer buffer = new Buffer();
            try {
                requestBody.writeTo(buffer);
                sb.append(buffer.readString(charset));
            } catch (Exception e) {
                LogUtil.d("read request error: " + e);
            } finally {
                buffer.close();
            }
        }
        LogUtil.e("http-----------param="+sb.toString());
        if (url.startsWith(BuildConfig.SERVER_URL + "sq-active/active-list")) {
            return createTrendsKey(sb.toString());
        } else if (url.startsWith(BuildConfig.SERVER_URL + "sq-active/topic-list")) {
            return url + "&" + createTopicKey(sb.toString());
        } else if (url.startsWith(BuildConfig.SERVER_URL + "site/index")) {
            return url + "&" + createHomeKey(sb.toString());
        } else if (url.startsWith(BuildConfig.SERVER_JAVA_API_URL + "ask/list-old")){
            return url + "&" + createAskListKey(sb.toString());
        }
        return sb.toString();
//        LogUtil.d("original key: " + sb.toString());
//        int tsStartIndex = sb.indexOf("ts=");
//        int tsEndIndex = sb.indexOf("&", tsStartIndex) >= 0 ? sb.indexOf("&", tsStartIndex) + 1 : sb.length();
//        if (tsStartIndex >= 0 && tsEndIndex >= 0) {
//            sb.delete(tsStartIndex, tsEndIndex);
//        }
//
//        int tokenStartIndex = sb.indexOf("accessToken=");
//        int tokenEndIndex = sb.indexOf("&", tokenStartIndex) >= 0 ? sb.indexOf("&", tokenStartIndex) + 1 : sb.length();
//        if (tokenStartIndex >= 0 && tokenEndIndex >= 0) {
//            sb.delete(tokenStartIndex, tokenEndIndex);
//        }
//
//        int uidStartIndex = sb.indexOf("uid=");
//        int uidEndIndex = sb.indexOf("&", uidStartIndex) >= 0 ? sb.indexOf("&", uidStartIndex) + 1 : sb.length();
//        if (uidStartIndex >= 0 && uidEndIndex >= 0) {
//            sb.delete(uidStartIndex, uidEndIndex);
//        }
    }

    //根据键返回索引
    private int[] getIndexofKeyValue(String str, String originStr) {
        int[] indexs = new int[2];
        indexs[0] = originStr.indexOf(str);
        indexs[1] = originStr.indexOf("&", indexs[0]) >= 0 ? originStr.indexOf("&", indexs[0]) : originStr.length();
        LogUtil.d("index0: " + indexs[0] + " index1: " + indexs[1]);
        return indexs;
    }

    private @Nullable
    String createTrendsKey(String originKey) {
        StringBuilder builder = new StringBuilder();
        builder.append(subString(originKey, getIndexofKeyValue("version=", originKey)) + "&");
        builder.append(subString(originKey, getIndexofKeyValue("tab=", originKey)) + "&");
        builder.append(subString(originKey, getIndexofKeyValue("id=", originKey)) + "&");
        builder.append(subString(originKey, getIndexofKeyValue("topic_id=", originKey)) + "&");
        builder.append(subString(originKey, getIndexofKeyValue("page=", originKey)));
        LogUtil.d("trends key: " + builder.toString());
        if (builder.toString().endsWith("page=1")) {
            return BuildConfig.SERVER_URL + "sq-active/active-list" + "&" + builder.toString();
        }
        return null;
    }

    private String createHomeKey(String originKey) {
        StringBuilder builder = new StringBuilder();
        builder.append(subString(originKey, getIndexofKeyValue("version=", originKey)) + "&");
        builder.append(subString(originKey, getIndexofKeyValue("os_type=", originKey)));
        LogUtil.d("home key: " + builder.toString());
        return builder.toString();
    }

    private String createAskListKey(String originKey){
        StringBuilder builder = new StringBuilder();
        builder.append(subString(originKey, getIndexofKeyValue("tab=", originKey)) + "&");
        builder.append(subString(originKey, getIndexofKeyValue("page=", originKey)));
        builder.append(subString(originKey, getIndexofKeyValue("topicId=", originKey)));
        builder.append(subString(originKey, getIndexofKeyValue("id=", originKey)));
        LogUtil.e("ask key: " + builder.toString());
        return builder.toString();
    }

    private String createTopicKey(String originKey) {
        StringBuilder builder = new StringBuilder();
        builder.append(subString(originKey, getIndexofKeyValue("version=", originKey)) + "&");
        builder.append(subString(originKey, getIndexofKeyValue("cate=", originKey)) + "&");
        builder.append(subString(originKey, getIndexofKeyValue("my=", originKey)));
        LogUtil.d("topic key: " + builder.toString());
        return builder.toString();
    }

    private boolean isNeedCache(String url) {
        return url.startsWith(BuildConfig.SERVER_URL + "sq-active/active-list") ||
                url.startsWith(BuildConfig.SERVER_URL + "sq-active/topic-list") ||
                url.startsWith(BuildConfig.SERVER_URL + "site/index") ||
                url.startsWith(BuildConfig.SERVER_JAVA_API_URL + "ask/list-old");
    }

    private Response combineCacheToResponse(String cache) {
        String[] caches = cache.split("&#&#");
        if (caches == null || caches.length <= 0) {
            return null;
        }
        Request request = new Request.Builder()
                .url(caches[REQUEST_URL])
                .method(caches[REQUEST_METHOD], null)
                .build();
        Response.Builder builder = new Response.Builder();
        try {
            builder.protocol(Protocol.get(caches[PROTOCAL]));
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            LogUtil.e("http----json="+ResponseBody.create(MediaType.parse(caches[MEDIA_TYPE]), caches[REPONSE_BODY]).string());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return builder.message(caches[MESSAGE])
                .code(Integer.valueOf(caches[CODE]))
                .request(request)
                .receivedResponseAtMillis(Long.valueOf(caches[RECEIVE_REPONSE_AT_MILLIS]))
                .sentRequestAtMillis(Long.valueOf(caches[SETN_REQUEST_AT_MILLIS]))
                .body(ResponseBody.create(MediaType.parse(caches[MEDIA_TYPE]), caches[REPONSE_BODY]))
                .build();
    }

    private String createCache(Response response) {
        String[] caches = new String[CACHE_LENGTH];
        caches[REQUEST_URL] = response.request().url().toString();
        caches[REQUEST_METHOD] = response.request().method();
        if (response.request().body() != null && response.request().body().contentType() != null) {
            caches[REQUESTCONTENTTYPE] = response.request().body().contentType().toString();
        } else {
            caches[REQUESTCONTENTTYPE] = "application/x-www-form-urlencoded";
        }
        caches[PROTOCAL] = response.protocol().toString();
        caches[CODE] = response.code() + "";
        caches[MESSAGE] = response.message();
        if (response.body() != null && response.body().contentType() != null) {
            caches[MEDIA_TYPE] = response.body().contentType().toString();
        } else {
            caches[MEDIA_TYPE] = "application/x-www-form-urlencoded";
        }
        caches[SETN_REQUEST_AT_MILLIS] = response.sentRequestAtMillis() + "";
        caches[RECEIVE_REPONSE_AT_MILLIS] = response.receivedResponseAtMillis() + "";
        if (HttpHeaders.hasBody(response)) {
            BufferedSource source = response.body().source();
            Buffer buffer = null;
            try {
                source.request(Long.MAX_VALUE);
                buffer = source.buffer();
                Charset charset = response.body().contentType().charset();
                if (charset == null) {
                    charset = Charset.forName("UTF-8");
                }
                caches[REPONSE_BODY] = buffer.clone().readString(charset);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        String cache = "";
        for (String str : caches) {
            cache += str + "&#&#";
        }
        return cache;
    }

    static boolean isEndToEnd(String fieldName) {
        return !"Connection".equalsIgnoreCase(fieldName)
                && !"Keep-Alive".equalsIgnoreCase(fieldName)
                && !"Proxy-Authenticate".equalsIgnoreCase(fieldName)
                && !"Proxy-Authorization".equalsIgnoreCase(fieldName)
                && !"TE".equalsIgnoreCase(fieldName)
                && !"Trailers".equalsIgnoreCase(fieldName)
                && !"Transfer-Encoding".equalsIgnoreCase(fieldName)
                && !"Upgrade".equalsIgnoreCase(fieldName);
    }

    private String subString(String str, int[] index) {
        if (index == null || index.length < 2) {
            return null;
        }
        if (index[0] < 0 || index[1] < 0) {
            return null;
        }
        return str.substring(index[0], index[1]);
    }
}
