package com.qmth.exam.reserve.weixin;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.ParameterizedType;
import java.net.HttpURLConnection;
import java.net.URL;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.qmth.boot.core.exception.StatusException;
import com.qmth.exam.reserve.util.JsonHelper;
import com.qmth.exam.reserve.weixin.response.WxResponseJson;

public abstract class AbstractRequest<T extends WxResponseJson, K, V> {

    private static final Logger log = LoggerFactory.getLogger(AbstractRequest.class);

    /**********************
     * 返回的结果转换成的json串
     */
    protected T jsonEntity;

    /**********************
     * 所有业务处理完成之后返回的实体类
     */
    protected K returnEntity;

    /**********************
     * 请求的实体类
     */
    protected V requestEntity;

    protected String method = "get";

    /*************
     * 请求次数
     */
    protected int requestTotal = 1;

    public static int HttpConnectTimeoutSeconds = 30;

    protected HttpURLConnection http = null;

    /***************************
     * 请求的地址
     */
    protected abstract String makeUrl();

    /********************
     * 完成请求后逻辑处理
     */
    @SuppressWarnings("unchecked")
    public void processBusiness() {
        this.returnEntity = (K) this.jsonEntity;

    }

    @SuppressWarnings("unchecked")
    public K request() {
        Class<?> clazz = getGenericsClass(this.getClass());
        String ul = this.makeUrl();
        try {
            URL url = new URL(ul);
            http = (HttpURLConnection) url.openConnection();
            // get还是post方式
            http.setRequestMethod(this.method.equalsIgnoreCase("post") ? "POST" : "GET");
            // 连接超时时间
            http.setConnectTimeout(HttpConnectTimeoutSeconds * 1000);
            // 读取数据超时时间
            http.setReadTimeout(HttpConnectTimeoutSeconds * 1000);
            // 允许输出
            http.setDoOutput(true);
            // 允许传入
            http.setDoInput(true);
            http.setRequestProperty("Connection", "Keep-Alive");
            http.setRequestProperty("Charset", "UTF-8");
        } catch (Exception e) {
            throw new StatusException("HTTP无法连接，请检查URL地址[" + ul + "]");
        }
        this.httpRequest();
        String message = receiveMessage();
        if (StringUtils.isNotEmpty(message)) {
            jsonEntity = (T) JsonHelper.toObj(message, clazz);
        }
        if (jsonEntity != null) {
            if (jsonEntity.getErrcode() == 40001 || jsonEntity.getErrcode() == 40014 || jsonEntity.getErrcode() == 40029
                    || jsonEntity.getErrcode() == 42001) {
                if (this.requestTotal < 5) {
                    this.requestTotal++;
                    this.request();
                } else {
                    log.info("error_code:" + jsonEntity.getErrcode() + ";err_message:" + jsonEntity.getErrmsg()
                            + ";weixin_json:" + jsonEntity.getWeixin_json());
                    throw new StatusException("无法获取openId");
                }
            }
            this.processBusiness();
        }
        return returnEntity;
    }

    public static Class<?> getGenericsClass(Class<?> clazz) {
        ParameterizedType superClass = (ParameterizedType) clazz.getGenericSuperclass();
        Class<?> target = (Class<?>) superClass.getActualTypeArguments()[0];
        return target;
    }

    /********************************
     * http发出请求，发送json串
     */
    protected void httpRequest() {
        try {
            http.connect();
            http.setConnectTimeout(15000);
            http.setReadTimeout(15000);
        } catch (Exception e) {
        }
        if (this.requestEntity != null) {
            try {
                OutputStream os = http.getOutputStream();
                os.write(JsonHelper.toJson(this.requestEntity).getBytes("UTF-8"));
                os.flush();
                os.close();
            } catch (Exception e) {
            }
        }
    }

    protected String receiveMessage() {
        String message = null;
        try {
            InputStream is = http.getInputStream();
            byte[] bcache = new byte[2048];
            int readSize = 0;// 每次读取的字节长度
            ByteArrayOutputStream infoStream = new ByteArrayOutputStream();
            while ((readSize = is.read(bcache)) > 0) {
                infoStream.write(bcache, 0, readSize);
            }
            message = infoStream.toString("UTF-8");
            is.close();
        } catch (Exception e) {

        } finally {
            try {
                http.disconnect();
                http = null;
            } catch (Exception e) {

            }
        }
        return message;
    }

}
