/**
 * @license Copyright (c) 2017-2025, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md.
 */

/**
 * Creates a cubic bezier easing function with the given control points.
 *
 * @param x1 - First control point X coordinate (0-1)
 * @param y1 - First control point Y coordinate (0-1)
 * @param x2 - Second control point X coordinate (0-1)
 * @param y2 - Second control point Y coordinate (0-1)
 * @returns A function that takes a value t (0-1) and returns the interpolated value
 */
export function createCubicBezier( x1, y1, x2, y2 ) {
	return function( t ) {
		// Implementation of cubic bezier calculation
		const cx = 3 * x1;
		const bx = 3 * ( x2 - x1 ) - cx;
		const ax = 1 - cx - bx;

		const cy = 3 * y1;
		const by = 3 * ( y2 - y1 ) - cy;
		const ay = 1 - cy - by;

		const sampleCurveX = t => ( ( ax * t + bx ) * t + cx ) * t;
		const sampleCurveY = t => ( ( ay * t + by ) * t + cy ) * t;

		let t2 = t;

		// Newton-Raphson iteration to solve for t given x
		for ( let i = 0; i < 8; i++ ) {
			const x = sampleCurveX( t2 ) - t;
			if ( Math.abs( x ) < 0.001 ) {
				break;
			}

			const d = ( 3 * ax * t2 + 2 * bx ) * t2 + cx;
			if ( Math.abs( d ) < 0.0001 ) {
				break;
			}

			t2 = t2 - x / d;
		}

		return sampleCurveY( t2 );
	};
}

/**
 * Common easing functions derived from CSS `cubic-bezier()` timing functions.
 */
export const easings = {
	cubicOut: createCubicBezier( 0.215, 0.61, 0.355, 1 )
};
