import { clamp } from "./clamp.jsx";
import { getPushedThumbValues } from "./get-pushed-thumb-values.jsx";

/**
 * Strategy for how a moving thumb interacts with its neighbours.
 *
 * - `"none"`: thumbs cannot cross; the pressed thumb is clamped at its
 *   neighbour's boundary.
 * - `"push"`: the pressed thumb pushes its neighbours along.
 * - `"swap"`: thumbs swap identities when they cross.
 */

/**
 * Applies the chosen collision `behavior` to compute the new thumb values
 * when the thumb at `pressedIndex` attempts to move to `nextValue`. Returns
 * both the updated values and the resolved thumb index (swap may change it).
 */
export function resolveThumbCollision({
  behavior,
  values,
  currentValues,
  initialValues,
  pressedIndex,
  nextValue,
  min,
  max,
  step,
  minStepsBetweenValues
}) {
  const activeValues = currentValues ?? values;
  const baselineValues = initialValues ?? values;
  const range = activeValues.length > 1;
  if (!range) {
    return {
      value: nextValue,
      thumbIndex: 0,
      didSwap: false
    };
  }
  const minValueDifference = step * minStepsBetweenValues;
  switch (behavior) {
    case "swap":
      {
        const pressedInitialValue = activeValues[pressedIndex];
        const epsilon = 1e-7;
        const candidateValues = activeValues.slice();
        const previousNeighbor = candidateValues[pressedIndex - 1];
        const nextNeighbor = candidateValues[pressedIndex + 1];
        const lowerBound = previousNeighbor != null ? previousNeighbor + minValueDifference : min;
        const upperBound = nextNeighbor != null ? nextNeighbor - minValueDifference : max;
        const constrainedValue = clamp(nextValue, lowerBound, upperBound);
        const pressedValueAfterClamp = Number(constrainedValue.toFixed(12));
        candidateValues[pressedIndex] = pressedValueAfterClamp;
        const movingForward = pressedInitialValue != null && nextValue > pressedInitialValue;
        const movingBackward = pressedInitialValue != null && nextValue < pressedInitialValue;
        const shouldSwapForward = movingForward && nextNeighbor != null && nextValue >= nextNeighbor - epsilon;
        const shouldSwapBackward = movingBackward && previousNeighbor != null && nextValue <= previousNeighbor + epsilon;
        if (!shouldSwapForward && !shouldSwapBackward) {
          return {
            value: candidateValues,
            thumbIndex: pressedIndex,
            didSwap: false
          };
        }
        const targetIndex = shouldSwapForward ? pressedIndex + 1 : pressedIndex - 1;
        const initialValuesForPush = candidateValues.map((_, index) => {
          if (index === pressedIndex) {
            return pressedValueAfterClamp;
          }
          const baseline = baselineValues[index];
          if (baseline != null) {
            return baseline;
          }

          // biome-ignore lint/style/noNonNullAssertion: index is within activeValues bounds
          return activeValues[index];
        });
        let nextValueForTarget = nextValue;
        if (shouldSwapForward) {
          // biome-ignore lint/style/noNonNullAssertion: targetIndex = pressedIndex + 1 is in range for swap-forward
          nextValueForTarget = Math.max(nextValue, candidateValues[targetIndex]);
        } else {
          // biome-ignore lint/style/noNonNullAssertion: targetIndex = pressedIndex - 1 is in range for swap-backward
          nextValueForTarget = Math.min(nextValue, candidateValues[targetIndex]);
        }
        const adjustedValues = getPushedThumbValues({
          values: candidateValues,
          index: targetIndex,
          nextValue: nextValueForTarget,
          min,
          max,
          step,
          minStepsBetweenValues,
          initialValues: initialValuesForPush
        });
        const neighborIndex = shouldSwapForward ? targetIndex - 1 : targetIndex + 1;
        if (neighborIndex >= 0 && neighborIndex < adjustedValues.length) {
          const previousValue = adjustedValues[neighborIndex - 1];
          const nextValueAfter = adjustedValues[neighborIndex + 1];
          let neighborLowerBound = previousValue != null ? previousValue + minValueDifference : min;
          neighborLowerBound = Math.max(neighborLowerBound, min + neighborIndex * minValueDifference);
          let neighborUpperBound = nextValueAfter != null ? nextValueAfter - minValueDifference : max;
          neighborUpperBound = Math.min(neighborUpperBound, max - (adjustedValues.length - 1 - neighborIndex) * minValueDifference);
          const restoredValue = clamp(pressedValueAfterClamp, neighborLowerBound, neighborUpperBound);
          adjustedValues[neighborIndex] = Number(restoredValue.toFixed(12));
        }
        return {
          value: adjustedValues,
          thumbIndex: targetIndex,
          didSwap: true
        };
      }
    case "push":
      {
        const nextValues = getPushedThumbValues({
          values: activeValues,
          index: pressedIndex,
          nextValue,
          min,
          max,
          step,
          minStepsBetweenValues
        });
        return {
          value: nextValues,
          thumbIndex: pressedIndex,
          didSwap: false
        };
      }
    default:
      {
        const candidateValues = activeValues.slice();
        const previousNeighbor = candidateValues[pressedIndex - 1];
        const nextNeighbor = candidateValues[pressedIndex + 1];
        const lowerBound = previousNeighbor != null ? previousNeighbor + minValueDifference : min;
        const upperBound = nextNeighbor != null ? nextNeighbor - minValueDifference : max;
        const constrainedValue = clamp(nextValue, lowerBound, upperBound);
        candidateValues[pressedIndex] = Number(constrainedValue.toFixed(12));
        return {
          value: candidateValues,
          thumbIndex: pressedIndex,
          didSwap: false
        };
      }
  }
}
//# sourceMappingURL=resolve-thumb-collision.jsx.map
