package com.elphel.imagej.gpu.jna;

import com.sun.jna.Library;
import com.sun.jna.Pointer;

/**
 * JNA boundary to the native tile-processor library (libtileproc.so) for the JCuda->JNA migration.
 * Stage-0b surface only: prove module compile/load across JNA. The full set (instances, set/exec/get)
 * follows the design doc handoffs/2026-06-25_JCuda-to-JNA-migration-design.md. By Claude on 2026-06-25.
 */
public interface TpJna extends Library {
    /** NVRTC-compile the kernels in srcdir (+ getTpDefines), cuLink(libcudadevrt), load the module.
     *  Returns an opaque module handle, or null on failure (see tp_last_error()). */
    Pointer tp_create_module(String srcdir, String libcudadevrt);
    /** Number of kernel functions resolved in the module (19 expected), or -1 if handle is null. */
    int     tp_module_num_functions(Pointer module);
    /** Last error message (NVRTC/CUDA log), empty if none. */
    String  tp_last_error();
    /** Free the module (cuModuleUnload + cuCtxDestroy). */
    void    tp_destroy_module(Pointer module);

    // ---- Stage 1: instance + geometry path ----
    /** Create a per-config GPU instance (allocates geometry device buffers). Null on failure. */
    Pointer tp_create_instance(Pointer module);
    /** Upload gc.expandSensors(16).toFloatArray() (n floats) to gpu_geometry_correction. 0 on success. */
    int     tp_set_geometry_correction(Pointer instance, float[] fgc, int n);
    /** Upload cv.toFullRollArray() (n floats) to gpu_correction_vector. 0 on success. */
    int     tp_set_correction_vector(Pointer instance, float[] fcv, int n);
    /** Run calcReverseDistortionTable -> gpu_rByRDist. 0 on success. */
    int     tp_exec_calc_reverse_distortions(Pointer instance);
    /** Run calc_rot_deriv(num_cams) -> gpu_rot_deriv. 0 on success. */
    int     tp_exec_rot_derivs(Pointer instance, int num_cams);
    /** Read gpu_rByRDist back into out[RBYRDIST_LEN=5001]. 0 on success. */
    int     tp_get_rbyrdist(Pointer instance, float[] out);
    /** Read gpu_rot_deriv back into out[5*16*3*3=720]. 0 on success. */
    int     tp_get_rot_deriv(Pointer instance, float[] out);
    /** Free the instance device buffers. */
    void    tp_destroy_instance(Pointer instance);

    // ---- Stage 2: convert_direct selftest ----
    /** Run the full convert_direct path (mirrors TpHostGpu allTests convert chain) against the
     *  tile_processor_gpu/clt golden data under data_root. lwir!=0 -> 16-cam LWIR set.
     *  Writes max |CLT-golden| into outMaxErr[0] and the kernel-computed active-tile count into
     *  outNumActive[0]. Returns 0 on success. */
    int     tp_convert_direct_selftest(Pointer module, int lwir, String data_root,
                                       double[] outMaxErr, int[] outNumActive);

    // ---- Stage 3: convert_direct + imclt_rbg_all ----
    /** Run convert_direct then imclt_rbg_all; compare CLT to clt/aux_chnN.clt (outCltErr[0]) and
     *  the de-pitched RBG to clt/aux_chnN.rbg (outRbgErr[0]). Returns 0 on success. */
    int     tp_imclt_selftest(Pointer module, int lwir, String data_root,
                              double[] outCltErr, double[] outRbgErr, int[] outNumActive);

    // ---- Stage 4: correlate2D + corr2D_combine + corr2D_normalize ----
    /** Run convert_direct then the intra TD-correlation quad path; compare CLT to clt/aux_chnN.clt
     *  (outCltErr[0]) and the quad-combined correlation to clt/aux_corr-quad.corr (outCorrErr[0]). */
    int     tp_corr_selftest(Pointer module, int lwir, String data_root,
                             double[] outCltErr, double[] outCorrErr, int[] outNumActive);

    // ---- Stage 5: textures_nonoverlap (DP; CDP-launches textures_accumulate) ----
    /** Run convert_direct then textures_nonoverlap; compare CLT to clt/aux_chnN.clt (outCltErr[0])
     *  and the de-interleaved diff_rgb_combo to clt/aux_diff_rgb_combo_dp.drbg (outTexErr[0]). */
    int     tp_tex_selftest(Pointer module, int lwir, String data_root,
                            double[] outCltErr, double[] outTexErr, int[] outNumActive);

    // ---- Step 1: persistent granular API (TpProc) — production-facing surface ----
    Pointer tp_proc_create(Pointer module);
    int     tp_proc_setup(Pointer proc, int num_cams, int num_colors, int img_w, int img_h, int kernels_hor, int kern_tiles);
    int     tp_proc_set_geometry(Pointer proc, float[] fgc, int n);
    int     tp_proc_set_correction_vector(Pointer proc, float[] fcv, int n);
    int     tp_proc_set_kernels(Pointer proc, int cam, float[] d, int n);
    int     tp_proc_set_kernel_offsets(Pointer proc, int cam, float[] d, int n);
    int     tp_proc_set_image(Pointer proc, int cam, float[] d);
    /** use_center_image: broadcast one center image to all sensors (FPN back-prop mode). */
    int     tp_proc_set_center_image(Pointer proc, float[] d);
    int     tp_proc_set_tasks(Pointer proc, float[] ftasks, int ntiles, int totalFloats);
    int     tp_proc_get_tasks(Pointer proc, float[] out, int totalFloats);
    int     tp_proc_exec_geometry(Pointer proc, int uniformGrid);
    /** convert_direct: ref_scene (0/1 -> clt vs clt_ref), erase_clt (-1/0/1), no_kernels (0/1). */
    int     tp_proc_exec_convert_direct(Pointer proc, int refScene, int eraseClt, int noKernels);
    int     tp_proc_get_clt(Pointer proc, int cam, int refScene, float[] out);
    int     tp_proc_set_clt(Pointer proc, int cam, float[] data, int refScene);
    /** Allocate imclt(RBG) + correlation buffers and store corr config. */
    int     tp_proc_setup_rbg_corr(Pointer proc, int numPairs, int s0,int s1,int s2,int s3,
                                   float cw0,float cw1,float cw2, int corrOutRad);
    int     tp_proc_exec_imclt(Pointer proc, int applyLpf);
    int     tp_proc_get_rbg(Pointer proc, int cam, float[] out);
    int     tp_proc_exec_corr2d(Pointer proc, double fatZero);
    /** de-pitch quad correlation; returns num_corr_combo. */
    int     tp_proc_get_corr2d_combo(Pointer proc, float[] out);

    // ---- granular correlations (match GpuQuad's separate exec calls) ----
    int     tp_proc_exec_corr2d_td(Pointer proc, int s0,int s1,int s2,int s3, float sc0,float sc1,float sc2);
    int     tp_proc_exec_corr2d_inter_td(Pointer proc, int selSensors, float sc0,float sc1,float sc2);
    int     tp_proc_exec_corr2d_combine(Pointer proc, int initCorrCombo, int numPairs, int pairsMask);
    int     tp_proc_exec_corr2d_normalize(Pointer proc, int combo, double fatZero, int corrRadius);
    int     tp_proc_get_corr2d(Pointer proc, float[] out, int corrRad);
    int     tp_proc_num_corr_tiles(Pointer proc);
    int     tp_proc_num_corr_combo(Pointer proc);
    /** Upload to a named __constant__ symbol (lpf_data / lpf_corr / lpf_rb_corr). 0 on success. */
    int     tp_proc_set_const(Pointer proc, String name, float[] data, int n);
    void    tp_proc_destroy(Pointer proc);
    /** Validate the persistent path: convert CLT (outCltErr), imclt RBG (outRbgErr), quad corr
     *  order-independent (outCorrErr), + no_kernels smoke (outNokernMax). */
    int     tp_proc_convert_selftest(Pointer module, int lwir, String data_root,
                                     double[] outCltErr, double[] outRbgErr, double[] outCorrErr,
                                     double[] outNokernMax, int[] outNumActive);
}
