package com.yonge.cooleshow.biz.dal.support;

import com.yonge.cooleshow.biz.dal.config.IMProperties;
import io.rong.util.CodeUtil;
import io.rong.util.GsonUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.Map;

@Component
public class HttpHelper {
    private final static Logger log = LoggerFactory.getLogger(HttpHelper.class);

    private static final String APPKEY = "RC-App-Key";
    private static final String NONCE = "RC-Nonce";
    private static final String TIMESTAMP = "RC-Timestamp";
    private static final String SIGNATURE = "RC-Signature";

    private SSLContext sslCtx = null;

    @Autowired
    IMProperties imProperties;

    @PostConstruct
    private void init() {
        log.info("init HttpHelper");
        try {
            sslCtx = SSLContext.getInstance("TLS");
            X509TrustManager tm = new X509TrustManager() {
                public void checkClientTrusted(X509Certificate[] xcs, String string) {
                }

                public void checkServerTrusted(X509Certificate[] xcs, String string) {
                }

                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
            };
            sslCtx.init(null, new TrustManager[]{tm}, null);
        } catch (Exception e) {
            log.error("SSLContext exception:{}", e.getMessage());
        }

        HttpsURLConnection.setDefaultHostnameVerifier((arg0, arg1) -> true);

        HttpsURLConnection.setDefaultSSLSocketFactory(sslCtx.getSocketFactory());
    }

    // 设置body体
    public void setBodyParameter(StringBuilder sb, HttpURLConnection conn)
            throws IOException {
        String str = sb.toString();
        log.info("Call server api with url: {}, data: {}", conn.getURL().toString(), str);
        DataOutputStream out = new DataOutputStream(conn.getOutputStream());
        out.writeBytes(str);
        out.flush();
        out.close();
    }

    public HttpURLConnection createGetHttpConnection(String uri)
            throws MalformedURLException, IOException {
        URL url = new URL(uri);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setConnectTimeout(30000);
        conn.setRequestMethod("GET");
        return conn;
    }

    public void setBodyParameter(String str, HttpURLConnection conn) throws IOException {
        log.info("Call IM server api with url: {}, data: {}", conn.getURL().toString(), str);
        DataOutputStream out = new DataOutputStream(conn.getOutputStream());
        out.write(str.getBytes(StandardCharsets.UTF_8));
        out.flush();
        out.close();
    }

    public HttpURLConnection createWhiteBoardPostHttpConnection(String host, String uri, String contentType)
            throws MalformedURLException, IOException, ProtocolException {

        URL url = new URL(host + uri);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        setConn(conn, contentType);
        return conn;
    }

    public HttpURLConnection createCommonPostHttpConnection(String host, String appKey,
                                                            String appSecret, String uri, String contentType)
            throws IOException {
        HttpURLConnection conn = getHttpURLConnection(host, appKey, appSecret, uri, contentType);
        if (conn == null) return null;

        conn.setConnectTimeout(30000);
        conn.setReadTimeout(30000);
        conn.setRequestMethod("POST");
        return conn;
    }

    public HttpURLConnection createCommonGetHttpConnection(String host, String appKey,
                                                           String appSecret, String uri, String contentType) throws IOException {
        HttpURLConnection conn = getHttpURLConnection(host, appKey, appSecret, uri, contentType);
        if (conn == null) return null;

        conn.setConnectTimeout(10000);
        conn.setReadTimeout(10000);
        conn.setRequestMethod("GET");
        return conn;
    }

    private HttpURLConnection getHttpURLConnection(String host, String appKey, String appSecret, String uri, String contentType) throws IOException {
        String nonce = String.valueOf(Math.random() * 1000000);
        String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
        StringBuilder toSign = new StringBuilder(appSecret).append(nonce).append(timestamp);
        String sign = CodeUtil.hexSHA1(toSign.toString());
        uri = host + uri;
        URL url = new URL(uri);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        if (conn == null) {
            log.info("open url connectin fail, url={}", uri);
            return null;
        }

        conn.setUseCaches(false);
        conn.setDoInput(true);
        conn.setDoOutput(true);
        conn.setInstanceFollowRedirects(true);
        conn.setRequestProperty(APPKEY, appKey);
        conn.setRequestProperty(NONCE, nonce);
        conn.setRequestProperty(TIMESTAMP, timestamp);
        conn.setRequestProperty(SIGNATURE, sign);
        conn.setRequestProperty("Content-Type", contentType);
        return conn;
    }

    public HttpURLConnection createIMGetHttpConnection(String uri, String contentType) throws IOException {
        return createCommonGetHttpConnection(imProperties.getHost(),
                imProperties.getAppKey(), imProperties.getSecret(), uri,
                contentType);
    }

    public HttpURLConnection createIMPostHttpConnection(String uri, String contentType) throws IOException {
        return createCommonPostHttpConnection(imProperties.getHost(),
                imProperties.getAppKey(), imProperties.getSecret(), uri,
                contentType);
    }

    public byte[] readInputStream(InputStream inStream) throws Exception {
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len = 0;
        while ((len = inStream.read(buffer)) != -1) {
            outStream.write(buffer, 0, len);
        }
        byte[] data = outStream.toByteArray();
        outStream.close();
        inStream.close();
        return data;
    }

    public String returnResult(HttpURLConnection conn) throws Exception {
        InputStream input;
        String result;
        try {
            if (conn.getResponseCode() == 200 || conn.getResponseCode() == 201) {
                input = conn.getInputStream();
            } else {
                input = conn.getErrorStream();
            }
            result = new String(readInputStream(input), StandardCharsets.UTF_8);
        } catch (UnknownHostException e) {
            result = getExceptionMessage("request:" + conn.getURL() + " ,UnknownHostException:" + e.getMessage());
        } catch (SocketTimeoutException e) {
            result = getExceptionMessage("request:" + conn.getURL() + " ,SocketTimeoutException:" + e.getMessage());
        } catch (IOException e) {
            result = getExceptionMessage("request:" + conn.getURL() + " ,IOException:" + e.getMessage());
        }
        log.info("IM server api response:{}", result);
        return result;
    }

    private static String getExceptionMessage(String error) {
        Map<String, Object> result = new HashMap<>();
        result.put("code", 400);
        result.put("msg", error);
        return GsonUtil.toJson(result);
    }

    public String returnResult(HttpURLConnection conn, String body) throws Exception, IOException {
        InputStream input = null;
        if (conn.getResponseCode() == 200) {
            input = conn.getInputStream();
        } else {
            input = conn.getErrorStream();
        }
        String result = new String(readInputStream(input), "UTF-8");
        log.info("IM server api response:{}, {}, {}", conn.getURL(), body, result);
        return result;
    }

    public HttpURLConnection createPostHttpConnection(String uri, String contentType) throws IOException {
        URL url = new URL(uri);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        if (conn == null) {
            log.info("open url connection fail, url={}", uri);
            return null;
        }
        setConn(conn, contentType);
        return conn;
    }

    private void setConn(HttpURLConnection conn, String contentType) throws ProtocolException {
        conn.setUseCaches(false);
        conn.setDoInput(true);
        conn.setDoOutput(true);
        conn.setRequestMethod("POST");
        conn.setInstanceFollowRedirects(true);
        conn.setConnectTimeout(30000);
        conn.setReadTimeout(30000);
        conn.setRequestProperty("Content-Type", contentType);
    }

    public HttpURLConnection createIMRtcPostHttpConnection(String uri, String contentType, String roomId)
            throws IOException {
        return createCommonRtcPostHttpConnection(imProperties.getRtcHost(),
                imProperties.getAppKey(), imProperties.getSecret(), uri,
                contentType, roomId);
    }

    public HttpURLConnection createCommonRtcPostHttpConnection(String host, String appKey,
                                                               String appSecret, String uri, String contentType, String roomId)
            throws IOException {
        String nonce = String.valueOf(Math.random() * 1000000);
        String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
        StringBuilder toSign = new StringBuilder(appSecret).append(nonce).append(timestamp);
        String sign = CodeUtil.hexSHA1(toSign.toString());
        uri = host + uri;
        URL url = new URL(uri);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        if (conn == null) {
            log.info("open url connectin fail, url={}", uri);
            return null;
        }

        conn.setUseCaches(false);
        conn.setDoInput(true);
        conn.setDoOutput(true);
        conn.setRequestMethod("POST");
        conn.setInstanceFollowRedirects(true);
        conn.setConnectTimeout(30000);
        conn.setReadTimeout(30000);

        conn.setRequestProperty("App-Key", appKey);
        conn.setRequestProperty("Nonce", nonce);
        conn.setRequestProperty("Timestamp", timestamp);
        conn.setRequestProperty("Signature", sign);
        if (StringUtils.isNotEmpty(roomId)) {
            conn.setRequestProperty("Room-Id", roomId);
        }
        conn.setRequestProperty("Content-Type", contentType);
        return conn;
    }
}
