// BAPLIE Viewer Online API: minimal Java client (Java 11 or newer, no libraries).
//
//   export BVO_API_KEY=...  BVO_PRIVATE_KEY=...
//   java BvoApi.java my_baplie.edi
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.MessageDigest;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.stream.Collectors;

public class BvoApi {
    static final String BASE_URL = System.getenv().getOrDefault("BVO_BASE_URL", "https://api-gateway.baplieviewer.com/v4");
    static final String API_KEY = System.getenv("BVO_API_KEY");
    static final String PRIVATE_KEY = System.getenv("BVO_PRIVATE_KEY");
    static final HttpClient CLIENT = HttpClient.newHttpClient();

    // sha512 of the field values joined in the documented order, followed by the private key. Lowercase hex.
    static String makeHash(String... values) throws Exception {
        MessageDigest sha = MessageDigest.getInstance("SHA-512");
        byte[] digest = sha.digest((String.join("", values) + PRIVATE_KEY).getBytes(StandardCharsets.UTF_8));
        StringBuilder hex = new StringBuilder();
        for (byte b : digest) hex.append(String.format("%02x", b));
        return hex.toString();
    }

    // POST form fields to an API call and return the reply body as text
    static String call(String path, Map<String, String> fields) throws Exception {
        String body = fields.entrySet().stream()
            .map(e -> URLEncoder.encode(e.getKey(), StandardCharsets.UTF_8) + "=" + URLEncoder.encode(e.getValue(), StandardCharsets.UTF_8))
            .collect(Collectors.joining("&"));
        HttpRequest request = HttpRequest.newBuilder(URI.create(BASE_URL + "/" + path))
            .header("x-api-key", API_KEY)
            .header("Content-Type", "application/x-www-form-urlencoded")
            .POST(HttpRequest.BodyPublishers.ofString(body)).build();
        return CLIENT.send(request, HttpResponse.BodyHandlers.ofString()).body();
    }

    // very small check; use a JSON library in real code
    static String callOk(String path, Map<String, String> fields) throws Exception {
        String reply = call(path, fields);
        if (!reply.contains("\"ack\":\"success\"")) throw new RuntimeException(path + " failed: " + reply);
        return reply;
    }

    static Map<String, String> map(String... kv) {
        Map<String, String> m = new LinkedHashMap<>();
        for (int i = 0; i < kv.length; i += 2) m.put(kv[i], kv[i + 1]);
        return m;
    }

    public static void main(String[] args) throws Exception {
        String edi = Files.readString(Path.of(args[0]));
        String fileId = "demo" + (System.currentTimeMillis() / 1000);

        // upload: hash = data + file_id + main_json + anomalies_json + private key
        String up = callOk("upload", map("file_id", fileId, "data", edi, "main_json", "0", "anomalies_json", "0", "api_file_type", "BAPLIE",
            "hash", makeHash(edi, fileId, "0", "0")));
        String fileUploadId = up.replaceAll(".*\"file_upload_id\":(\\d+).*", "$1");
        System.out.println("uploaded: file_upload_id " + fileUploadId);

        // read the file back as JSON: hash = file_id + private key
        callOk("read/json", map("file_id", fileId, "hash", makeHash(fileId)));
        System.out.println("read/json ok");

        // 2D view: the reply is an HTML page that opens the viewer (see the integration guide).
        // user_id names the person using YOUR application. If this facility has no container list for that user the call answers error 502:
        // call view/restrictContainers once first (all_bays=1 lets the user see everything).
        String html = call("view/2D", map("file_id", fileId, "user_id", "user-1", "hash", makeHash(fileId, "user-1")));
        System.out.println("view/2D returned " + html.length() + " characters of HTML");

        // delete: hash = file_id + file_upload_id + private key
        callOk("delete/file", map("file_id", fileId, "file_upload_id", fileUploadId, "hash", makeHash(fileId, fileUploadId)));
        System.out.println("deleted");
    }
}
