package com.mogo.cloud.network.listener;

import android.util.Log;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.util.List;

import okhttp3.Call;
import okhttp3.Connection;
import okhttp3.EventListener;
import okhttp3.Handshake;
import okhttp3.Protocol;
import okhttp3.Request;
import okhttp3.Response;

/**
 * EventListener监听实现类
 * HTTP请求的基本链路
 * 整个过程中，DNS 解析、建立 TCP 连接、发送请求、服务器处理请求和发送响应、接收响应等环节都涉及到协议层和网络层的操作。
 * HTTP 协议定义了请求和响应的格式，而 TCP/IP 协议栈提供了底层的网络传输支持
 * <p>
 * DNS 解析： 客户端首先通过 DNS 解析获取服务器的 IP 地址，将主机名转换为 IP 地址
 * 建立 TCP 连接： 客户端通过 IP 地址和端口号与服务器建立 TCP 连接。这个过程通常包括 TCP 的三次握手
 * 组装 HTTP 请求： 客户端构建 HTTP 请求报文，包括请求行（方法、URL、协议版本）、请求头（Headers）、请求体（如果是 POST 请求等带有主体的请求）等
 * 发送请求： 客户端将构建好的 HTTP 请求报文通过建立的 TCP 连接发送给服务器
 * 服务器处理请求： 服务器收到请求后，根据请求报文中的信息进行相应的处理。这可能包括解析请求、执行请求对应的处理逻辑、生成响应内容等
 * 服务器发送响应： 服务器构建 HTTP 响应报文，包括状态行（协议版本、状态码、状态消息）、响应头（Headers）、响应体（实际的响应内容）等
 * 接收响应： 客户端通过 TCP 连接接收服务器发送的 HTTP 响应报文
 * 解析响应： 客户端解析响应报文，获取状态码、响应头和响应体等信息
 * 关闭连接： 根据 HTTP 版本和服务器端的要求，决定是否保持连接或断开连接。在 HTTP/1.1 中，默认是保持连接，而在 HTTP/1.0 中默认是断开连接
 * 处理响应： 客户端根据收到的响应进行相应的处理，可能包括渲染页面、执行后续操作等
 */
public class OkHttpEventListener extends EventListener {

    // 请求开始
    private long mCallStartTime;
    // DNS开始
    private long mDnsStartTime;
    // 建立 TCP 连接
    private long mConnectStartTime;
    // TLS安全连接开始
    private long mSecureConnectStartTime;
    // 连接绑定开始
    private long mConnectionStartTime;
    // 请求Header开始
    private long mRequestHeadersStartTime;
    // 请求Body开始
    private long mRequestBodyStartTime;
    // 响应Header开始
    private long mResponseHeadersStartTime;
    // 响应Body开始
    private long mResponseBodyStartTime;

    /**
     * 请求开始
     */
    @Override
    public void callStart(Call call) {
        super.callStart(call);
        mCallStartTime = System.nanoTime();
    }

    /**
     * 请求正常结束
     */
    @Override
    public void callEnd(Call call) {
        super.callEnd(call);
        logMethod(call.request().toString() + "方法的 callEnd", mCallStartTime);
    }

    /**
     * 请求异常结束
     */
    @Override
    public void callFailed(Call call, IOException ioe) {
        super.callFailed(call, ioe);
        logMethod(call.request().toString() + "方法的 callFailed IOException =" + ioe.getMessage(), mCallStartTime);
    }

    /**
     * dns解析开始
     * DNS解析是请求DNS（Domain Name System）服务器。将域名解析成ip的过程。
     */
    @Override
    public void dnsStart(Call call, String domainName) {
        super.dnsStart(call, domainName);
        mDnsStartTime = System.nanoTime();
    }

    /**
     * dns解析结束
     */
    @Override
    public void dnsEnd(Call call, String domainName, List<InetAddress> inetAddressList) {
        super.dnsEnd(call, domainName, inetAddressList);
        logMethod(call.request().toString() + "方法的 dnsEnd", mDnsStartTime);
    }

    /**
     * 连接开始
     */
    @Override
    public void connectStart(Call call, InetSocketAddress inetSocketAddress, Proxy proxy) {
        super.connectStart(call, inetSocketAddress, proxy);
        mConnectStartTime = System.nanoTime();
    }

    /**
     * 连接结束
     */
    @Override
    public void connectEnd(Call call, InetSocketAddress inetSocketAddress, Proxy proxy, Protocol protocol) {
        super.connectEnd(call, inetSocketAddress, proxy, protocol);
        logMethod(call.request().toString() + "方法的 connectEnd", mConnectStartTime);
    }

    /**
     * 连接失败
     */
    @Override
    public void connectFailed(Call call, InetSocketAddress inetSocketAddress, Proxy proxy, Protocol protocol, IOException ioe) {
        super.connectFailed(call, inetSocketAddress, proxy, protocol, ioe);
        logMethod(call.request().toString() + "方法的 connectFailed IOException =" + ioe.getMessage(), mConnectStartTime);
    }

    /**
     * TLS安全连接开始
     */
    @Override
    public void secureConnectStart(Call call) {
        super.secureConnectStart(call);
        mSecureConnectStartTime = System.nanoTime();
    }

    /**
     * TLS安全连接结束
     */
    @Override
    public void secureConnectEnd(Call call, Handshake handshake) {
        super.secureConnectEnd(call, handshake);
        logMethod(call.request().toString() + "方法的 secureConnectEnd", mSecureConnectStartTime);
    }

    /**
     * 连接绑定
     */
    @Override
    public void connectionAcquired(Call call, Connection connection) {
        super.connectionAcquired(call, connection);
        mConnectionStartTime = System.nanoTime();
    }

    /**
     * 连接释放
     */
    @Override
    public void connectionReleased(Call call, Connection connection) {
        super.connectionReleased(call, connection);
        logMethod(call.request().toString() + "方法的 connectionReleased", mConnectionStartTime);
    }

    /**
     * 请求Header开始
     */
    @Override
    public void requestHeadersStart(Call call) {
        super.requestHeadersStart(call);
        mRequestHeadersStartTime = System.nanoTime();
    }

    /**
     * 请求Header结束
     */
    @Override
    public void requestHeadersEnd(Call call, Request request) {
        super.requestHeadersEnd(call, request);
        logMethod(call.request().toString() + "方法的 requestHeadersEnd", mRequestHeadersStartTime);
    }

    /**
     * 请求Body开始
     */
    @Override
    public void requestBodyStart(Call call) {
        super.requestBodyStart(call);
        mRequestBodyStartTime = System.nanoTime();
    }

    /**
     * 请求Body结束
     */
    @Override
    public void requestBodyEnd(Call call, long byteCount) {
        super.requestBodyEnd(call, byteCount);
        logMethod(call.request().toString() + "方法的 requestBodyEnd", mRequestBodyStartTime);
    }

    /**
     * 响应Header开始
     */
    @Override
    public void responseHeadersStart(Call call) {
        super.responseHeadersStart(call);
        mResponseHeadersStartTime = System.nanoTime();
    }

    /**
     * 响应Header结束
     */
    @Override
    public void responseHeadersEnd(Call call, Response response) {
        super.responseHeadersEnd(call, response);
        logMethod(call.request().toString() + "方法的 responseHeadersEnd", mResponseHeadersStartTime);
    }

    /**
     * 响应Body开始
     */
    @Override
    public void responseBodyStart(Call call) {
        super.responseBodyStart(call);
        mResponseBodyStartTime = System.nanoTime();
    }

    /**
     * 响应Body结束
     */
    @Override
    public void responseBodyEnd(Call call, long byteCount) {
        super.responseBodyEnd(call, byteCount);
        logMethod(call.request().toString() + "方法的 responseBodyEnd", mResponseBodyStartTime);
    }

    /**
     * 打印公共方法
     */
    public void logMethod(String name, long startTime) {
        long time = System.nanoTime() - startTime;
        // 对超出4秒的网络请求打印日志
        if (time > 4000000000d) {
            Log.d("OkHttpOptimizeActivity", name + "  方法 耗时：" + (time / 1000000000d) + "秒");
        }
    }

}

