import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.LinkedHashMap;
import java.util.Map;

public class Main {

    private static String bytesToHex(byte[] bytes) {
        StringBuilder result = new StringBuilder();
        for (byte b : bytes) {
            result.append(String.format("%02x", b));
        }
        return result.toString();
    }

    public static String toJson(Map<String, Object> map) {
        StringBuilder sb = new StringBuilder();
        sb.append("{");

        boolean first = true;
        for (Map.Entry<String, Object> e : map.entrySet()) {
            if (!first) sb.append(",");
            first = false;

            sb.append("\"").append(e.getKey()).append("\":");

            Object val = e.getValue();

            if (val == null) {
                sb.append("null");
            } else if (val instanceof Number) {
                sb.append(val);
            } else {
                sb.append("\"").append(val.toString().replace("\"", "\\\"")).append("\"");
            }
        }
        sb.append("}");
        return sb.toString();
    }

    public static String generateSignature(String secret, String method, String path, String body, String timestamp) {
        try {
            String message = method + "\n" + path + "\n" + body + "\n" + timestamp + "\n";

            Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
            SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
            sha256_HMAC.init(secret_key);

            return bytesToHex(sha256_HMAC.doFinal(message.getBytes(StandardCharsets.UTF_8)));

        } catch (Exception e) {
            throw new RuntimeException("Error generating signature", e);
        }
    }

    public static void main(String[] args) {

        String secret = "{{YOUR_SECRET_KEY}}";
        String method = "POST";
        String path = "api/v1/payout/initiate";

        // EXACT SAME VALUES AS PHP
        LinkedHashMap<String, Object> map = new LinkedHashMap<>();
        map.put("beneficiary_name", "Test");
        map.put("beneficiary_email", "test.test@gmail.com");
        map.put("beneficiary_mobile_no", 7537537533L); // NUMBER
        map.put("beneficiary_address", "TEST");
        map.put("payment_method", "IMPS");
        map.put("beneficiary_acc_no", "016501549624");
        map.put("bank_name", "ICICI");
        map.put("ifsc", "ICIC0000165");
        map.put("amount", 100); // SAME AS PHP
        map.put("order_id", "d33s1e-43asyde-sdn11hh3e");
        map.put("user_id", "aseq-2d2fss-22a4sd-44a33");
        map.put("remarks", null);

        String body = toJson(map);  // NO SLASH 
        String timestamp = String.valueOf(System.currentTimeMillis());

        String signature = generateSignature(secret, method, path, body, timestamp);

        System.out.println("Body: " + body);
        System.out.println("Signature: " + signature);
        System.out.println("Timestamp: " + timestamp);
    }
}
