package org.bdware.sc.boundry.utils;

import okhttp3.*;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.bdware.sc.compiler.PermissionStub;
import org.bdware.sc.engine.DesktopEngine;
import org.bdware.sc.http.ApiGate;
import org.bdware.sc.node.Permission;
import org.bdware.sc.util.JsonUtil;
import wrp.jdk.nashorn.api.scripting.NashornScriptEngine;
import wrp.jdk.nashorn.api.scripting.ScriptObjectMirror;
import wrp.jdk.nashorn.internal.runtime.PropertyMap;
import wrp.jdk.nashorn.internal.runtime.ScriptFunction;
import wrp.jdk.nashorn.internal.runtime.ScriptObject;
import wrp.jdk.nashorn.internal.scripts.JO;

import javax.net.ssl.SSLContext;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;
import java.util.concurrent.TimeUnit;

@PermissionStub(permission = Permission.Http)
public class HttpUtil {
    public static NashornScriptEngine currentEngine;

    public static ScriptObject request(ScriptObjectMirror str) {
        JO ret = new JO(PropertyMap.newMap());
        try {
            URL url = new URL((String) str.get("url"));
            String method = (String) str.get("method");
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setDoOutput(true);
            connection.setDoInput(true);
            connection.setUseCaches(false);
            connection.setInstanceFollowRedirects(true);
            connection.setRequestMethod(method.toUpperCase());
            Object headers = str.get("headers");
            if (headers != null && headers instanceof ScriptObjectMirror) {
                ScriptObjectMirror som = (ScriptObjectMirror) headers;
                for (String key : som.getOwnKeys(true)) {
                    Object val = som.get(key);
                    if (val instanceof String) connection.setRequestProperty(key, (String) val);
                }
            } else {
                connection.setRequestProperty("Accept", "application/json");
                connection.setRequestProperty("Content-Type", "application/json");
            }
            connection.connect();
            OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream(), "UTF-8");
            if (str.get("data") != null)
                out.append((String) str.get("data"));
            out.flush();
            out.close();
            ret.put("responseCode", connection.getResponseCode(), false);
            InputStream input = connection.getInputStream();
            Scanner sc = new Scanner(input);
            StringBuilder sb = new StringBuilder();
            for (; sc.hasNextLine(); ) {
                sb.append(sc.nextLine()).append("\n");
            }
            sc.close();
            ret.put("response", sb.toString(), false);
        } catch (Throwable e) {
            ret.put("responseCode", 505, false);
            ByteArrayOutputStream bo = new ByteArrayOutputStream();
            e.printStackTrace(new PrintStream(bo));
            ret.put("response", bo.toString(), false);
        }
        return ret;
    }
    public static String encodeURI(String str){
        return URLEncoder.encode(str);
    }
    public static String decodeURI(String str){
        return URLDecoder.decode(str);
    }

    public static ScriptObject get(String str) {
        JO ret = new JO(PropertyMap.newMap());
        try {
            URL url = new URL(str);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            ret.put("responseCode", connection.getResponseCode(), false);
            InputStream input = connection.getInputStream();
            Scanner sc = new Scanner(input);
            StringBuilder sb = new StringBuilder();
            while (sc.hasNextLine()) {
                sb.append(sc.nextLine()).append("\n");
            }
            sc.close();
            ret.put("response", sb.toString(), false);
        } catch (Throwable e) {
            ret.put("resposeCode", 505, false);
            ByteArrayOutputStream bo = new ByteArrayOutputStream();
            e.printStackTrace(new PrintStream(bo));
            ret.put("response", bo.toString(), false);
        }
        return ret;
    }

    public static ScriptObject post(ScriptObjectMirror str) {
        JO ret = new JO(PropertyMap.newMap());
        try {
            URL url = new URL((String) str.get("url"));
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setDoOutput(true);
            connection.setDoInput(true);
            connection.setUseCaches(false);
            connection.setInstanceFollowRedirects(true);
            connection.setRequestMethod("POST");
            Object headers = str.get("headers");
            if (headers instanceof ScriptObjectMirror) {
                ScriptObjectMirror som = (ScriptObjectMirror) headers;
                for (String key : som.getOwnKeys(true)) {
                    Object val = som.get(key);
                    if (val instanceof String) {
                        connection.setRequestProperty(key, (String) val);
                    }
                }
            } else {
                connection.setRequestProperty("Accept", "application/json");
                connection.setRequestProperty("Content-Type", "application/json");
            }
            connection.connect();
            OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream(), StandardCharsets.UTF_8);
            out.append((String) str.get("data"));
            out.flush();
            out.close();
            ret.put("responseCode", connection.getResponseCode(), false);
            InputStream input = connection.getInputStream();
            Scanner sc = new Scanner(input);
            StringBuilder sb = new StringBuilder();
            while (sc.hasNextLine()) {
                sb.append(sc.nextLine()).append("\n");
            }
            sc.close();
            ret.put("response", sb.toString(), false);
        } catch (Throwable e) {
            ret.put("responseCode", 505, false);
            ByteArrayOutputStream bo = new ByteArrayOutputStream();
            e.printStackTrace(new PrintStream(bo));
            ret.put("response", bo.toString(), false);
        }
        return ret;
    }

    private static CloseableHttpClient getHttpClient(String url) {
        try {
            SSLContext sslcontext =
                    SSLContexts.custom()
                            .loadTrustMaterial(
                                    null,
                                    (arg0, arg1) -> true)
                            .build();

            SSLConnectionSocketFactory sslSf =
                    new SSLConnectionSocketFactory(
                            sslcontext, null, null, new NoopHostnameVerifier());
            int tle = 10;
            if (url.contains("data.tj.gov.cn")) {
                tle = 3;
            }
            return HttpClients.custom()
                    .setSSLSocketFactory(sslSf)
                    .setKeepAliveStrategy((arg0, arg1) -> 0)
                    .setConnectionTimeToLive(tle, TimeUnit.SECONDS)
                    .build();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    //	public static String httpPost(String str) {
    //		System.out.println("JavaSScriptEntry httpPost:" + str);
    //		PostRequest req = new PostRequest();
    //		req = JsonUtil.fromJson(str, PostRequest.class);
    //		// System.out.println("url========>" + req.url);
    //		// System.out.println("data=======>" + req.data);
    //
    //		Result r = new Result();
    //		try {
    //			URL url = new URL(req.url);//
    //			HttpURLConnection connection = (HttpURLConnection) url.openConnection();
    //			connection.setDoOutput(true);
    //			connection.setDoInput(true);
    //			connection.setUseCaches(false);
    //			connection.setInstanceFollowRedirects(true);
    //			connection.setRequestMethod("POST");
    //			connection.setRequestProperty("Accept", "application/json");
    //			connection.setRequestProperty("Content-Type", "application/json");
    //			connection.connect();
    //			OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream(), "UTF-8"); //
    // utf-8缂栫爜
    //			out.append(req.data);
    //			out.flush();
    //			out.close();
    //
    //			r.resposeCode = connection.getResponseCode();
    //			InputStream input = connection.getInputStream();
    //
    //			Scanner sc = new Scanner(input);
    //			StringBuilder sb = new StringBuilder();
    //			for (; sc.hasNextLine();) {
    //				sb.append(sc.nextLine()).append("\n");
    //			}
    //			sc.close();
    //			r.response = sb.toString();
    //			return JsonUtil.toJson(r);
    //		} catch (Throwable e) {
    //			r.resposeCode = 505;
    //			// ByteArrayOutputStream bo = new ByteArrayOutputStream();
    //			// e.printStackTrace(new PrintStream(bo));
    //			r.response = e.getMessage();
    //			return JsonUtil.toJson(r);
    //		}
    //	}

    public static String postTask(String args, final ScriptFunction callback) {
        System.out.println("[JavaScriptEntry]" + args);
        PostRequest req = new PostRequest();
        req = JsonUtil.fromJson(args, PostRequest.class);

        OkHttpClient okHttpClient = new OkHttpClient(); //
        RequestBody body =
                RequestBody.create(MediaType.parse("application/json; charset=utf-8"), req.data);
        Request request = new Request.Builder().url(req.url).post(body).build(); // 2.瀹氫箟涓�涓猺equest
        Call call = okHttpClient.newCall(request); //
        call.enqueue(
                new Callback() { //
                    @Override
                    public void onFailure(Call call, IOException e) {
                    }

                    @Override
                    public void onResponse(Call call, Response response) throws IOException {
                        String result = response.body().string(); //
                        System.out.println("currentEngine:");
                        DesktopEngine.applyWithGlobal(
                                callback, currentEngine.getNashornGlobal(), result);
                    }
                });
        return "success";
    }

    //	public static String httpGet(String str) {
    //		// System.out.println("JavaScriptEntry httpGet:" + str);
    //		Result r = new Result();
    //		try {
    //			HttpGet httpGet = new HttpGet(str);
    //			RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(60000)
    //					.setConnectTimeout(60000).setSocketTimeout(60000).build();
    //			httpGet.setConfig(requestConfig);
    //			httpGet.addHeader("Pragma", "no-cache");
    //			httpGet.addHeader("Cache-Control", "no-cache");
    //			httpGet.addHeader("Upgrade-Insecure-Requests", "1");
    //			httpGet.addHeader("User-Agent",
    //					"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko)
    // Chrome/78.0.3904.97 Safari/537.36");
    //			httpGet.addHeader("Sec-Fetch-User", "?1");
    //			httpGet.addHeader("Accept",
    //
    //	"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3");
    //			httpGet.addHeader("Sec-Fetch-Site", "none");
    //			httpGet.addHeader("Sec-Fetch-Mode", "navigate");
    //			httpGet.addHeader("Accept-Encoding", "gzip, deflate, br");
    //			httpGet.addHeader("Accept-Language", "zh-CN,zh;q=0.9");
    //			CloseableHttpResponse response1 = getHttpClient(str).execute(httpGet);
    //			InputStream content = response1.getEntity().getContent();
    //			ByteArrayOutputStream bo = new ByteArrayOutputStream();
    //			byte[] buff = new byte[4096];
    //			for (int k = 0; (k = content.read(buff)) > 0;) {
    //				bo.write(buff, 0, k);
    //			}
    //			r.response = bo.toString();
    //			return JsonUtil.toJson(r);
    //		} catch (Throwable e) {
    //			r.resposeCode = 505;
    //			// ByteArrayOutputStream bo = new ByteArrayOutputStream();
    //			// e.printStackTrace(new PrintStream(bo));
    //			r.response = e.getMessage();
    //			return JsonUtil.toJson(r);
    //		}
    //	}

    public static ApiGate createAPIGate(String ip) {
        return new ApiGate(ip);
    }

    public static ApiGate createAPIGate(String ip, String port) {
        return new ApiGate(ip, Integer.parseInt(port));
    }

    static class PostRequest {
        String url;
        String data;
    }
}
