package com.elphel.imagej.tileprocessor;

import com.elphel.imagej.cameras.CLTParameters;

/**
 * Classic-LMA structured global refinement path.
 *
 * <p>Phase-1 implementation keeps behavior stable by delegating numeric solve to
 * {@link IntersceneGlobalRefine} while exposing a minimal {@code prepareLMA/getFxDerivs/lmaStep/runLma}
 * skeleton for incremental migration to the classic block-based style.
 */
public class IntersceneGlobalLmaRefine {

	private final CLTParameters cltParameters;
	private final QuadCLT[] quadCLTs;
	private final QuadCLT centerCLT;
	private final int centerIndex;
	private final int earliestScene;
	private final int lastScene;
	private final double[][][] scenesXyzatr;
	private final double[][][] scenesXyzatrPull;
	private final boolean[] paramSelect;
	private final double[] paramRegweights;
	private final double[] paramLpf;
	private final double[] centerDisparity;
	private final boolean[] reliableRef;
	private final boolean disableErs;
	private final double mbMaxGain;
	private final IntersceneGlobalRefine.Options options;

	private IntersceneGlobalLmaRefine(
			final CLTParameters cltParameters,
			final QuadCLT[] quadCLTs,
			final QuadCLT centerCLT,
			final int centerIndex,
			final int earliestScene,
			final int lastScene,
			final double[][][] scenesXyzatr,
			final double[][][] scenesXyzatrPull,
			final boolean[] paramSelect,
			final double[] paramRegweights,
			final double[] paramLpf,
			final double[] centerDisparity,
			final boolean[] reliableRef,
			final boolean disableErs,
			final double mbMaxGain,
			final IntersceneGlobalRefine.Options options) {
		this.cltParameters = cltParameters;
		this.quadCLTs = quadCLTs;
		this.centerCLT = centerCLT;
		this.centerIndex = centerIndex;
		this.earliestScene = earliestScene;
		this.lastScene = lastScene;
		this.scenesXyzatr = scenesXyzatr;
		this.scenesXyzatrPull = scenesXyzatrPull;
		this.paramSelect = paramSelect;
		this.paramRegweights = paramRegweights;
		this.paramLpf = paramLpf;
		this.centerDisparity = centerDisparity;
		this.reliableRef = reliableRef;
		this.disableErs = disableErs;
		this.mbMaxGain = mbMaxGain;
		this.options = options;
	}

	public static IntersceneGlobalRefine.Result refineAllToReference(
			final CLTParameters cltParameters,
			final QuadCLT[] quadCLTs,
			final QuadCLT centerCLT,
			final int centerIndex,
			final int earliestScene,
			final int lastScene,
			final double[][][] scenesXyzatr,
			final double[][][] scenesXyzatrPull,
			final boolean[] paramSelect,
			final double[] paramRegweights,
			final double[] paramLpf,
			final double[] centerDisparity,
			final boolean[] reliableRef,
			final boolean disableErs,
			final double mbMaxGain,
			final IntersceneGlobalRefine.Options options,
			final int debugLevel) {
		final IntersceneGlobalLmaRefine solver = new IntersceneGlobalLmaRefine(
				cltParameters,
				quadCLTs,
				centerCLT,
				centerIndex,
				earliestScene,
				lastScene,
				scenesXyzatr,
				scenesXyzatrPull,
				paramSelect,
				paramRegweights,
				paramLpf,
				centerDisparity,
				reliableRef,
				disableErs,
				mbMaxGain,
				options);
		solver.prepareLMA(debugLevel);
		return solver.runLma(debugLevel);
	}

	/**
	 * Prepare solver state for the classic LMA-structured implementation.
	 */
	private void prepareLMA(final int debugLevel) {
		if (debugLevel > -4) {
			System.out.println(
					"IntersceneGlobalLmaRefine: prepareLMA() phase-1 wrapper enabled; " +
					"numeric solve delegated to IntersceneGlobalRefine");
		}
	}

	/**
	 * Placeholder for future application-specific residual/Jacobian assembly blocks.
	 */
	@SuppressWarnings("unused")
	private double[] getFxDerivs(
			final double[] vector,
			final double[][] jt,
			final int debugLevel) {
		return null;
	}

	/**
	 * Placeholder for future classic LMA step implementation.
	 */
	@SuppressWarnings("unused")
	private boolean[] lmaStep(
			final double lambda,
			final double rmsDiff,
			final int debugLevel) {
		return new boolean[] {false, false};
	}

	/**
	 * Run global refinement. Phase-1 delegates to the current sparse/banded solver.
	 */
	private IntersceneGlobalRefine.Result runLma(final int debugLevel) {
		return IntersceneGlobalRefine.refineAllToReference(
				cltParameters,
				quadCLTs,
				centerCLT,
				centerIndex,
				earliestScene,
				lastScene,
				scenesXyzatr,
				scenesXyzatrPull,
				paramSelect,
				paramRegweights,
				paramLpf,
				centerDisparity,
				reliableRef,
				disableErs,
				mbMaxGain,
				options,
				debugLevel);
	}
}
