package com.elphel.imagej.gpu.jna;

import com.sun.jna.Native;
import com.sun.jna.Pointer;

/**
 * Step-1 validation: the PERSISTENT granular native API (TpProc) — the production-facing surface that
 * GpuQuadJna (integration step 2) will delegate to. Drives the convert_direct path through the persistent
 * instance (buffers allocated once, reused) and confirms CLT == clt/aux_chnN.clt golden (== Stage 2), plus
 * a no_kernels smoke test (the fragile skip-deconvolution path used by rectilinear / FPN back-prop).
 *
 * Run:
 *   java -Djna.library.path=&lt;dir with libtileproc.so&gt; -cp target/classes:&lt;jna.jar&gt; \
 *        com.elphel.imagej.gpu.jna.StageProc [data_root] [lwir]
 * By Claude on 2026-06-25.
 */
public class StageProc {
    public static void main(String[] args) {
        String root = (args.length > 0) ? args[0] : "/home/elphel/git/tile_processor_gpu";
        int    lwir = (args.length > 1) ? Integer.parseInt(args[1]) : 1;
        String srcdir = "/home/elphel/git/tile_processor_gpu/src";
        String devrt  = "/usr/local/cuda/targets/x86_64-linux/lib/libcudadevrt.a";

        System.out.printf("StageProc (persistent TpProc convert via JNA): root=%s lwir=%d%n", root, lwir);
        TpJna lib = Native.load("tileproc", TpJna.class);
        Pointer m = lib.tp_create_module(srcdir, devrt);
        if (m == null) { System.out.println("FAIL: tp_create_module:\n" + lib.tp_last_error()); System.exit(1); }

        double[] cltErr = new double[1], rbgErr = new double[1], corrErr = new double[1], nokern = new double[1];
        int[] nActive = new int[1];
        int rc = lib.tp_proc_convert_selftest(m, lwir, root, cltErr, rbgErr, corrErr, nokern, nActive);
        if (rc != 0) { System.out.printf("FAIL: selftest rc=%d: %s%n", rc, lib.tp_last_error()); System.exit(2); }

        boolean cltOk  = (cltErr[0] >= 0) && !Double.isNaN(cltErr[0]) && (cltErr[0] < 1.0) && (nActive[0] > 0);
        boolean rbgOk  = (rbgErr[0] >= 0) && !Double.isNaN(rbgErr[0]) && (rbgErr[0] < 1.0);
        boolean corrOk = (corrErr[0] >= 0) && !Double.isNaN(corrErr[0]) && (corrErr[0] < 1e-3); // order-independent value err
        boolean nokernOk = (nokern[0] >= 0);
        System.out.printf("  convert_direct: num_active=%d  max|CLT-golden|=%.6g  %s%n", nActive[0], cltErr[0], cltOk ? "PASS" : "FAIL");
        System.out.printf("  imclt_rbg_all:  max|RBG-golden|=%.6g  %s%n", rbgErr[0], rbgOk ? "PASS" : "FAIL");
        System.out.printf("  correlate2D quad: sorted(value) max=%.6g  %s%n", corrErr[0], corrOk ? "PASS" : "FAIL");
        System.out.printf("  no_kernels smoke: %s (max|CLT|=%.4g)%n",
                nokernOk ? "ran, finite" : (nokern[0] == -1 ? "NON-FINITE" : "launch error"), nokern[0]);
        lib.tp_destroy_module(m);
        boolean ok = cltOk && rbgOk && corrOk && nokernOk;
        System.out.println(ok ? "RESULT: PASS (persistent TpProc: convert+imclt+corr match goldens; no_kernels runs)"
                              : "RESULT: FAIL");
        System.exit(ok ? 0 : 3);
    }
}
