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 (33 expected:
     *  19 base + 2 conditioning + 4 consolidation + 2 peak + pose-fx/J + 4 pose-LMA + LMA-products),
     *  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);
    /** De-pitch one resident source image into out[width*height]. */
    int     tp_proc_get_image(Pointer proc, int cam, float[] out);
    /** Resident production calibration maps, contiguous [camera][height][width]. */
    int     tp_proc_set_conditioning_maps(Pointer proc, float[] scales, float[] offsets, int numPixels);
    /** Java-expression validation calibration; FPN is contiguous [camera][height][width]. */
    int     tp_proc_set_conditioning_oracle(Pointer proc, double[] scales, double[] offsets,
                                            double[] scales2, double[] fpn, int numPixels);
    /** Condition all resident source images in place; useDouble=0 selects production two-map float. */
    int     tp_proc_exec_conditioning(Pointer proc, int useDouble, double dcLevel);
    /** 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);
    /** Explicit persistent task slots (0/1); the selected slot becomes the live kernel stream. */
    int     tp_proc_set_tasks_slot(Pointer proc, float[] ftasks, int ntiles, int totalFloats, int slot);
    int     tp_proc_get_tasks_slot(Pointer proc, float[] out, int totalFloats, int slot);
    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);
    /** On-device 16-sensor TD consolidation (tp_consolidate.cu v1 chain, roadmap 2c):
     *  index_consolidate -> consolidate_oob (soft/hard margins, px; 0/0 = v0 no filtering) ->
     *  clt_average_sensors_list; the average lands in the cam-0 CLT slice (the per-sensor TD
     *  never leaves the device — replaces the getCltData/consolidateSensorsTD/setCltData CPU
     *  bridge). ftasks0/1 = flattened TpTask streams (TpTask.asFloatArray), ftasks1 null = no-MB.
     *  stats (int[3], may be null) = {MB pairs kept, surviving tiles, misaligned pairs}.
     *  0 on success. By Claude on 07/12/2026. */
    int     tp_proc_exec_consolidate(Pointer proc, float[] ftasks0, float[] ftasks1,
                                     int numEntries, int taskSize,
                                     float softMargin, float hardMargin, int[] stats);
    /** Same consolidation chain, consuming post-geometry task slots directly; slot1 < 0 = no-MB. */
    int     tp_proc_exec_consolidate_slots(Pointer proc, int slot0, int slot1,
                                           int numEntries, int taskSize,
                                           float softMargin, float hardMargin, int[] stats);
    /** 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 useRef);
    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);
    // ---- peak measurement (tp_peak.cu corr2D_peak_eig{,_f}, roadmap 3-C rung 2) ---- // By Claude on 07/14/2026
    /** Optional envelope de-bias array ((2*corrRad+1)^2 floats); len 0/null clears -> kernel gets NULL. */
    int     tp_proc_set_peak_debias(Pointer proc, float[] data, int len);
    /** Frozen 15-arg getMaxXYCmEig contract on the normalized PD buffer (run AFTER
     *  tp_proc_exec_corr2d_normalize combo=0): one {dx,dy,str,e0x,e0y,l0,l1,valid} row per
     *  resident corr tile. pairSelect 0xff = lean sum slots (-1 = all); useFloat: 0 = double
     *  (oracle-matched validation tier), 1 = float (production - ratified 07/14/2026, real-case
     *  float-vs-double dx/dy <= 7.2e-7 px). Returns the row count or <0. */
    int     tp_proc_exec_corr2d_peak(Pointer proc, int pairSelect,
                                     float absMin, float relMin, float minPeak, float eigSubFrac,
                                     int refine, float eigSubFrac1, float scaleAxes, float incAxes,
                                     int useFloat);
    /** D2H the peak rows (count x 8 floats). Returns the count. */
    int     tp_proc_get_peaks(Pointer proc, float[] out);
    /** Primitive-float raw pose fx/J, before eigen transforms. Camera metadata is
     *  {width,height,focal,pixel,distortionRadius,disparityRadius,lineTime,stepR}. */
    int     tp_proc_exec_pose_fx_jacobian(
                                      Pointer proc,
                                      float[] refMeta, float[] refRadial,
                                      float[] refRbr, int refRbrLen, float[] refErs, int refErsLen,
                                      float[] sceneMeta, float[] sceneRadial,
                                      float[] sceneRbr, int sceneRbrLen, float[] sceneErs, int sceneErsLen,
                                      float[] poseVectors, float[] centers, byte[] selection,
                                      int numTiles, int calculateJacobian,
                                      float[] fx, float[] jt, byte[] valid);
    /** One-thread fixed three-angle float candidate calculation. Result layout is
     *  {valid, raw H[9], raw b[3], delta[3], candidate[3]}. */
    int     tp_proc_exec_pose_lma_step(Pointer proc,
                                      float lambda, float[] weights, float[] jt,
                                      float[] ymfxWeighted, float[] vector,
                                      int numValues, float[] result);
    /** Continue from raw fx/J left by the most recent pose kernel. Result has
     *  the 19 candidate floats, current/candidate full/pure RMS, then accepted/stop.
     *  Prepared arrays are nullable unless capturePrepared is nonzero. */
    int     tp_proc_exec_pose_lma_resident_step(Pointer proc,
                                      float lambda, float[] weights, float[] y,
                                      float[] eigen, float[] vector, float pureWeight,
                                      float rmsDiff, int numTiles, int capturePrepared, float[] result,
                                      float[] preparedJt, float[] preparedYmfx);
    /** Rung C1 (design 2026-07-16): resident prepareLMA. Assembles y/weights/eigen
     *  from the RESIDENT peak/corr-index buffers, projects fx/J at the current pose
     *  (no readback) and normalizes weights on-device. prepResult layout:
     *  {valid, numMeas, sumWRaw, pureWeight, fullWeight, regW0, regW1, regW2}.
     *  outY/outWeights/outEigen nullable unless capture != 0 (one-shot oracle).
     *  By Claude on 07/17/2026. */
    int     tp_proc_exec_pose_lma_prepare_resident(Pointer proc,
                                      float[] refMeta, float[] refRadial,
                                      float[] refRbr, int refRbrLen, float[] refErs, int refErsLen,
                                      float[] sceneMeta, float[] sceneRadial,
                                      float[] sceneRbr, int sceneRbrLen, float[] sceneErs, int sceneErsLen,
                                      float[] poseVectors, float[] centers,
                                      int numTiles, int numComponents,
                                      int corrSlot, int ntileShift,
                                      int useEigen, float eigMinSqrt, float eigMaxSqrt,
                                      float minConfidence, int sameWeights,
                                      float[] pullTargets, float[] paramRegweights,
                                      int light, // rung C3: 1 = frozen conditioning, fresh y only // By Claude on 07/17/2026
                                      float[] prepResult, int capture,
                                      float[] outY, float[] outWeights, float[] outEigen);
    /** Deterministic double normal-equation products for the lean pose LMA.
     *  jt is parameter-major [numParams][numValues]; out is row-major H followed by b.
     *  Damping and the small solve remain in Java. 0 on success. */
    int     tp_proc_exec_lma_products(Pointer proc,
                                      double[] weights, double[] jt, double[] ymfxWeighted,
                                      int numParams, int numValues, double[] out);
    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);
    // ---- oracle TD-correlation readback / erase ----
    int     tp_proc_get_corr_indices(Pointer proc, int[] out, int n);
    int     tp_proc_get_corr_combo_indices(Pointer proc, int[] out, int n);
    int     tp_proc_get_corr_td(Pointer proc, float[] out);
    /** Upload host-built TD per-pair corr indices + data (TD->PD re-conversion path). 0 on success. */
    int     tp_proc_set_corr_indices_td(Pointer proc, int[] corr_indices, float[] fdata, int num_tiles);
    int     tp_proc_erase_corrs(Pointer proc);
    // ---- oracle textures: textures_nonoverlap (DP) + readback (matches GpuQuad.execTextures_DP) ----
    /** textures_nonoverlap<<<1,1>>>: CDP-builds the index list + accumulate. params5={min_shot,scale_shot,
     *  diff_sigma,diff_threshold,min_agree}; weights3=R,B,G. calc_textures->gpu_textures, calc_extra->
     *  diff_rgb_combo, linescan_order=0 in production. Returns the kernel-built texture-tile count. */
    int     tp_proc_exec_textures(Pointer proc, float[] params5, float[] weights3, int isLwir,
                                  int dustRemove, int keepWeights, int calcTextures, int calcExtra, int linescanOrder);
    /** Read min(count,n) packed texture indices into out; returns the true count (gpu_texture_indices_len). */
    int     tp_proc_get_texture_indices(Pointer proc, int[] out, int n);
    /** Read n = num_tex*num_cams*(num_colors+1) floats of diff_rgb_combo (texture_indices order). */
    int     tp_proc_get_diff_rgb_combo(Pointer proc, float[] out, int n);
    /** De-pitch gpu_textures into out[num_tiles * slices*256], slices per keep_weights. */
    int     tp_proc_get_textures(Pointer proc, float[] out, int numTiles, int numColors, int keepWeights);
    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);
}
