package code;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Base64;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpsExchange;

import db.DBC;
import db.Dominio;
import io.fusionauth.jwt.InvalidJWTSignatureException;
import io.fusionauth.jwt.Verifier;
import io.fusionauth.jwt.domain.Algorithm;
import io.fusionauth.jwt.domain.JWT;
import io.fusionauth.jwt.rsa.RSAVerifier;

public class TokenHandler implements HttpHandler {

	public void handle(HttpExchange hex) throws IOException {
		HttpsExchange he = (HttpsExchange) hex;

		String requestMethod = he.getRequestMethod();

		if (requestMethod.compareToIgnoreCase("options") == 0) {
			Helper.sendCors(he, 200);
			return;
		}
		if (requestMethod.compareToIgnoreCase("GET") != 0) {
			Helper.sendCors(he, 405);
			return;
		}

		String user = Helper.checkTokenGetUser(he);
		if (user == null) {
			Helper.sendCors(he, 401);
			return;
		}

		// ricavo da token

		JSONObject res = new JSONObject();
		JSONArray rs = new JSONArray();

		ArrayList<String> domList;
		try {
			domList = DBC.getDomainsUser(user);

			for (String k : domList) {
				JSONObject ogg = new JSONObject();
				ogg.put("nome", k);

				Dominio d = DBC.getDomain(k);
				ogg.put("stato", d.getStatus());
				ogg.put("admin", false);

				rs.put(ogg);
			}
			domList.clear();
			domList = DBC.getDomainsAdmin(user);
			for (String k : domList) {
				JSONObject ogg = new JSONObject();
				ogg.put("nome", k);// domain

				Dominio d = DBC.getDomain(k);
				ogg.put("stato", d.getStatus());
				ogg.put("admin", true);

				rs.put(ogg);

			}

			res.put("response", rs);
		} catch (SQLException | JSONException e) {
			e.printStackTrace();
			return;
		}

		String response = res.toString();
		Helper.sendCors(he, 200, response);

	}

	public static String verificaToken(String encodedJWT, String signature)
			throws IOException, JSONException, NoSuchAlgorithmException {

		URL url = new URL(Helper.getKeycloakURL() + "realms/" + Helper.getKeycloakRealm() + "/protocol/openid-connect/certs");// maybe, 8080
		HttpURLConnection con = (HttpURLConnection) url.openConnection();
		setConnectionSettings(con, "GET");

		// leggo risposta
		int status = con.getResponseCode();

		String content = getResponseFromConnection(con);
		con.disconnect();

		JSONObject j = new JSONObject(content);
		JSONArray arr = j.getJSONArray("keys");
		JSONObject ogg = arr.getJSONObject(0);
		String chiave = ogg.getJSONArray("x5c").get(0).toString();
		String cert = "-----BEGIN CERTIFICATE-----\n" + chiave + "\n-----END CERTIFICATE-----";

		Verifier verifier = RSAVerifier.newVerifier(cert);
		try {
			int index = encodedJWT.lastIndexOf('.');
			byte[] message = encodedJWT.substring(0, index).getBytes(StandardCharsets.UTF_8);
			byte[] signatureBytes = Base64.getUrlDecoder().decode(signature);// signature = tokSplit[2]
			verifier.verify(Algorithm.RS256, message, signatureBytes);
		} catch (InvalidJWTSignatureException e) {
			return null;
		}
		// Verify and decode the encoded string JWT to a rich object
		JWT jwt = JWT.getDecoder().decode(encodedJWT, verifier);
		return jwt.getString("preferred_username");
	}

	private static void setConnectionSettings(HttpURLConnection connection, String method) throws IOException{
		connection.setRequestMethod(method);
		connection.setRequestProperty("Content-Type", "application/json");
		connection.setRequestProperty("Accept", "application/json");
		connection.setDoOutput(true);
		connection.setConnectTimeout(5000);
		connection.setReadTimeout(5000);
	}

	private static String getResponseFromConnection(HttpURLConnection con) throws IOException {
		BufferedReader reader = new BufferedReader(new InputStreamReader(con.getInputStream()));
		String inputLine;
		StringBuffer content = new StringBuffer();
		while ((inputLine = reader.readLine()) != null) {
			content.append(inputLine);
		}
		reader.close();
		return content.toString();
	}
}