# BRIDGE SCRIPT: Connects JuliaMSI framework to the CNN Preprocessing pipeline.
# VERSION (V3): Relying directly on precomputed analytics and multiple mz slices for max throughtput

using Pkg
juliamsi_path = "/app/JuliaMSI"
push!(LOAD_PATH, joinpath(juliamsi_path, "src"))

# Load JuliaMSI core
include(joinpath(juliamsi_path, "src", "MSI_src.jl"))

using .MSI_src
using Statistics, Images, Interpolations, BenchmarkTools

# CONFIGURATION
data_path = "/app/data/Leaf.imzML"
mask_path = "/app/data/region_of_interest.png"
output_folder = "/app/datos_para_ai"
img_size = (256, 256)
tolerance = 0.05
mkpath(output_folder)

println("--- JULIA BATCH ENGINE ---")

function run_production_pipeline()
    # 1. LOAD DATA
    println("Step 1: Ingesting Data...")
    data = OpenMSIData(data_path)

    orig_height = data.image_dims[2]
    orig_width  = data.image_dims[1]
    if orig_height < 256 || orig_width < 256
        final_img_size = (orig_height, orig_width)
        println("  [Notice] Original image is smaller than 256x256. Keeping original size: ", final_img_size)
    else
        final_img_size = (256, 256)
        println("  [Notice] Resizing down to target size: ", final_img_size)
    end
    
    # 2. RUN FRAMEWORK ANALYTICS
    println("Step 2: Checking Dataset Precomputed Boundaries...")
    # This matches the framework's internal logic to safely discover the true boundaries.
    # It populates global_min_mz and global_max_mz by reading the binary headers properly.
    MSI_src.precompute_analytics(data)
    
    # 3. EXTRACT AVERAGE SPECTRUM 
    println("Step 3: Calculating ROI Average Spectrum...")
    mzs, avg_ints = MSI_src.get_average_spectrum(data, mask_path=mask_path)
    
    println("  True Dataset Min m/z: ", round(minimum(mzs), digits=2))
    println("  True Dataset Max m/z: ", round(maximum(mzs), digits=2))

    # 4. PEAK PICKING USING TRUE SPECTRA LIMITS
    # Identify relevant ion channels above a 2% intensity base peak threshold
    threshold = maximum(avg_ints) * 0.02
    peak_indices = findall(x -> x > threshold, avg_ints)

    min_vis_mz = data.global_min_mz[] > 0.0 ? data.global_min_mz[] : 50.0
    max_vis_mz = data.global_max_mz[] > 0.0 ? data.global_max_mz[] : 1000.0
    
    # Isolate targets that fall strictly within the standard CNN metabolic training window
    target_masses = Float64[]
    for idx in peak_indices
        mz_val = mzs[idx]
        if mz_val >= min_vis_mz && mz_val <= max_vis_mz
            push!(target_masses, mz_val)
        end
    end
    
    total_ions = length(target_masses)
    println("Found $total_ions ions within training range ($(min_vis_mz) to $(max_vis_mz) m/z) above threshold.")
    if total_ions == 0
        println("Warning: No peaks met the criteria. Check your threshold or mask alignment.")
        return
    end

    # 5. MULTI-CHANNEL BATCH EXTRACTION (Single pass over binary data)
    println("Step 4: Multi-channel Batch Extraction (Optimized I/O)...")
    slice_dict = MSI_src.get_multiple_mz_slices(data, target_masses, tolerance, mask_path=mask_path)

    # 6. THREADED PROCESSING & EXPORT
    println("Step 5: Threaded TrIQ Normalization & Safe 256x256 Zero-Padding...")
    mask_matrix = MSI_src.load_and_prepare_mask(mask_path, (data.image_dims[1], data.image_dims[2]))
    exported_count = Threads.Atomic{Int}(0)

    # Fixed target dimensions for the CNN
    target_size = (256, 256)

    Threads.@threads for mz_val in target_masses
        slice = get(slice_dict, mz_val, nothing)
        if slice === nothing || all(iszero, slice) continue end

        # 1. Framework-Native TrIQ (0.0 to 255.0 Scaling)
        slice_quant, _ = MSI_src.TrIQ(slice, 256, 0.98, mask_matrix=mask_matrix)
        
        # 2. Allocate an empty 256x256 background matrix
        padded_matrix = zeros(Float32, target_size)
        
        # 3. Compute structural centering offsets based on true resolution (161x106)
        h_orig, w_orig = size(slice_quant, 1), size(slice_quant, 2)
        offset_y = div(target_size[1] - h_orig, 2) + 1
        offset_x = div(target_size[2] - w_orig, 2) + 1
        
        # 4. Map the pristine, raw pixels directly into the center
        padded_matrix[offset_y:offset_y+h_orig-1, offset_x:offset_x+w_orig-1] .= slice_quant
        
        # 5. Convert safely to 0.0 - 1.0 float mapping for Gray image export
        normalized_gray = padded_matrix ./ 255.0
        
        # 6. Save the unblurred, structurally perfect map
        filename = "ion_$(round(mz_val, digits=2)).png"
        save(joinpath(output_folder, filename), Gray.(normalized_gray))
        
        Threads.atomic_add!(exported_count, 1)
    end
    
    println("\nSuccess: $(exported_count[]) target image maps exported to $output_folder.")
end

@time run_production_pipeline()
