package com.secureline.server;

import android.util.Base64;
import android.util.Slog;

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.Network;

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

import java.io.BufferedReader;
import java.io.OutputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

public class SecureLinePollClient {

    private static final String TAG = "SecureLinePollClient";

    private static final String BASE_URL = "https://api-secureline.com";

    private static final int TIMEOUT_MS = 15000;

    private final Context mContext;

    public SecureLinePollClient(Context context) {
        mContext = context;
    }

    public PollResponse poll(
            String deviceId,
            String nonce,
            byte[] attestationBlob,
            byte[] signature
    ) throws Exception {

        URL url = new URL(BASE_URL + "/v1/device/poll");

        ConnectivityManager cm =
                (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);

        Network network = cm.getActiveNetwork();
        if (network == null) {
            throw new IllegalStateException("No active network for poll");
        }

	javax.net.ssl.HttpsURLConnection conn =
	        (javax.net.ssl.HttpsURLConnection)
	                network.openConnection(url);

	conn.setSSLSocketFactory(
	        SecureLineTlsPinning.getPinnedFactory()
	);

        conn.setRequestMethod("POST");
        conn.setConnectTimeout(TIMEOUT_MS);
        conn.setReadTimeout(TIMEOUT_MS);
        conn.setDoOutput(true);
        conn.setRequestProperty("Content-Type", "application/json");

        JSONObject body = new JSONObject();

        body.put("device_id", deviceId);
        body.put("nonce", nonce);

        body.put(
                "attestation",
                Base64.encodeToString(attestationBlob, Base64.NO_WRAP)
        );

        body.put(
                "signature",
                Base64.encodeToString(signature, Base64.NO_WRAP)
        );

        byte[] jsonBytes = body.toString().getBytes();

        conn.setFixedLengthStreamingMode(jsonBytes.length);

        OutputStream os = conn.getOutputStream();
        os.write(jsonBytes);
        os.flush();
        os.close();

        int code = conn.getResponseCode();

        if (code != 200) {
            throw new SecurityException("Poll failed: HTTP " + code);
        }

        String response = readResponse(conn);

        Slog.i(TAG, "Poll raw response=" + response);

        return parseResponse(response);
    }

    private String readResponse(HttpURLConnection conn) throws Exception {

        BufferedReader reader =
                new BufferedReader(
                        new InputStreamReader(conn.getInputStream())
                );

        StringBuilder sb = new StringBuilder();
        String line;

        while ((line = reader.readLine()) != null) {
            sb.append(line);
        }

        reader.close();

        return sb.toString();
    }

    private PollResponse parseResponse(String json) throws Exception {

        JSONObject obj = new JSONObject(json);

        PollResponse resp = new PollResponse();

        if (obj.has("license_payload")) {
            resp.licensePayload = obj.getString("license_payload");
        }

        if (obj.has("signature")) {
            resp.signature = obj.getString("signature");
        }

        if (obj.has("commands")) {

            JSONArray arr = obj.getJSONArray("commands");

            resp.commands = new Command[arr.length()];

            for (int i = 0; i < arr.length(); i++) {

                JSONObject c = arr.getJSONObject(i);

                Command cmd = new Command();

                cmd.payload =
                    Base64.decode(
                        c.getString("payload"),
                        Base64.URL_SAFE | Base64.NO_WRAP
                    );

                cmd.signature =
                    Base64.decode(
                        c.getString("signature"),
                        Base64.URL_SAFE | Base64.NO_WRAP
                    );

                Slog.i(
                    TAG,
                    "Poll command[" + i + "] payload_len=" + cmd.payload.length
                        + " signature_len=" + cmd.signature.length
                );

                resp.commands[i] = cmd;
            }
        }

            Slog.i(
                TAG,
                "Poll parsed has_license_payload=" + (resp.licensePayload != null)
                    + " has_signature=" + (resp.signature != null)
                    + " commands_count=" + (resp.commands != null ? resp.commands.length : 0)
            );

        return resp;
    }

    public static class PollResponse {

        public String licensePayload;
        public String signature;

        public Command[] commands;
    }

    public static class Command {

        public byte[] payload;
        public byte[] signature;
    }

    public BfuPollResponse pollBfu(
            String deviceId,
            String nonce,
            byte[] signature
    ) throws Exception {

        URL url = new URL(BASE_URL + "/v1/device/poll_bfu");

        ConnectivityManager cm =
                (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);

        Network network = cm.getActiveNetwork();
        if (network == null) {
            throw new IllegalStateException("No active network for BFU poll");
        }

	javax.net.ssl.HttpsURLConnection conn =
	        (javax.net.ssl.HttpsURLConnection)
	                network.openConnection(url);

	conn.setSSLSocketFactory(
	        SecureLineTlsPinning.getPinnedFactory()
	);

        conn.setRequestMethod("POST");
        conn.setConnectTimeout(TIMEOUT_MS);
        conn.setReadTimeout(TIMEOUT_MS);
        conn.setDoOutput(true);

        conn.setRequestProperty("Content-Type", "application/json");

        JSONObject body = new JSONObject();

        body.put("device_id", deviceId);
        body.put("nonce", nonce);

        body.put(
                "signature",
                Base64.encodeToString(signature, Base64.NO_WRAP)
        );

        byte[] jsonBytes =
                body.toString().getBytes();

        conn.setFixedLengthStreamingMode(jsonBytes.length);

        OutputStream os =
                conn.getOutputStream();

        os.write(jsonBytes);
        os.flush();
        os.close();

        int code = conn.getResponseCode();

        if (code != 200) {
            throw new SecurityException(
                    "BFU poll failed HTTP " + code
            );
        }

        String response =
                readResponse(conn);

        JSONObject obj =
                new JSONObject(response);

        BfuPollResponse r =
                new BfuPollResponse();

        r.shouldWipe =
                obj.optBoolean("wipe", false);

        return r;
    }

    public static class BfuPollResponse {

        public boolean shouldWipe;

    }
}
