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);
    // ---- 3-B rung B4: pinned staged bayer upload (async per-sensor H2D). By Claude on 07/16/2026. ----
    /** Pinned host staging for slot (0/1): num_cams*img_w*img_h floats, lazily allocated
     *  together with the dedicated non-blocking copy stream + fence event. Null on failure. */
    Pointer tp_proc_bayer_staging(Pointer proc, int slot);
    /** Enqueue the pinned->device async copy of ONE sensor image from staging slot and
     *  return immediately (per-sensor copy/compute pipelining). Image consumers fence
     *  natively, so a partial upload is never visible to kernels or readbacks. */
    int     tp_proc_set_image_staged(Pointer proc, int cam, int slot);
    /** 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);
    /** 3-B rung B1: make a resident slot the live kernel task stream with NO upload
     *  (after pose_task_update rewrote it in place). By Claude on 07/16/2026. */
    int     tp_proc_activate_tasks_slot(Pointer proc, 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);
    /** 3-B rung B1 (design 2026-07-16): resident task build. pose_task_update runs the
     *  C1-validated projection chain over the per-sequence task template and rewrites
     *  the 6-float task headers of BOTH resident slots in place. Nullable groups follow
     *  the rung-C2 configuration-register contract: camera blocks (shared with
     *  prepare_resident), taskMap/taskCenters (per-sequence template), poseVectors
     *  (null = device-authoritative current set). Task slots must hold the
     *  per-sequence skeleton (set_tasks_slot) with exactly numTasks entries.
     *  By Claude on 07/16/2026. */
    int     tp_proc_exec_pose_task_update(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, int[] taskMap, float[] taskCenters,
                                      int numTasks, int numCams,
                                      float disparityCorr,
                                      float minPx, float maxPx, float minPy, float maxPy,
                                      int taskCodeMain, int taskCodeSub,
                                      float dxMain, float dyMain, float dxSub, float dySub,
                                      float scaleMain, float scaleSub);
    // ---- 3-B rung B3: single measure-chain entry (design 2026-07-16). By Claude on 07/16/2026. ----
    /** Store the per-scene measure-cycle descriptor: the union of the fixed chain's
     *  stage arguments (task_update / consolidate / inter-corr / normalize / peak). */
    int     tp_proc_set_pose_cycle(Pointer proc,
                                      int numTasks, int taskSize,
                                      float disparityCorr,
                                      float minPx, float maxPx, float minPy, float maxPy,
                                      int taskCodeMain, int taskCodeSub,
                                      float dxMain, float dyMain, float dxSub, float dySub,
                                      float scaleMain, float scaleSub,
                                      float softMargin, float hardMargin,
                                      int selSensors, float sc0, float sc1, float sc2,
                                      double fatZero, int corrRadius,
                                      int pairSelect,
                                      float absMin, float relMin, float minPeak, float eigSubFrac,
                                      int refine, float eigSubFrac1, float scaleAxes, float incAxes,
                                      int useFloat);
    /** ONE JNA crossing per measure cycle: pose_task_update -> [slot0 geometry+convert(erase)]
     *  -> [slot1 geometry+convert(subtract)] -> consolidate_slots -> inter-corr -> normalize
     *  -> peak, calling the EXACT granular stage functions in the exact order (byte-identical
     *  by construction). Nullable groups forward verbatim to pose_task_update. stats (int[3],
     *  may be null) = consolidation {pairs, surviving, misaligned}. Returns the corr-tile
     *  count (>0) or a stage-tagged negative (-10..-20, see tp_jna.cpp). */
    int     tp_proc_exec_pose_measure_cycle(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, int[] taskMap, float[] taskCenters,
                                      int[] stats);
    /** DP rung D4 (ladder ratified 2026-07-16): the FULL per-scene pose solve as ONE
     *  device entry - numCycles x [D2 measure chain -> full/light prepare -> six-stage
     *  resident step -> commit], self-chained on-device with zero interior host round
     *  trips. Camera/task/centers groups follow the C2 configuration-register contract
     *  (null = keep resident). pull/regw are the full-prepare objective rows (null =
     *  keep resident); vector = the entry anchor [3]. Readbacks: trace [numCycles*25]
     *  per-cycle packed rows, mstats [numCycles*5] per-cycle measure counts, result =
     *  final packed [25], vectorOut = final anchor [3], prepOut = last full prepare [8],
     *  stats = last-cycle {pairs, surviving, misaligned} (each nullable). Peaks/corr
     *  indices stay resident for the unchanged fetch calls. Returns the LAST cycle's
     *  corr-row count (>0) or a negative (host -1xx / device guard codes).
     *  By Claude on 07/17/2026. */
    int     tp_proc_exec_pose_scene_dp(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, int[] taskMap, float[] taskCenters,
                                      int numCycles, float lambda, float pureWeight, float rmsDiff,
                                      int numTiles, int corrSlot, int ntileShift,
                                      int numComponents, int useEigen,
                                      float eigMinSqrt, float eigMaxSqrt,
                                      float minConfidence, int sameWeights,
                                      int prepareLight,
                                      float[] centers, float[] pullTargets, float[] paramRegweights,
                                      float[] vector,
                                      float[] trace, int[] mstats, float[] result,
                                      float[] vectorOut, float[] prepOut, int[] stats);
    /** 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);
}
