import * as R from "remeda";

/**
 * Rounds a number to a specified number of decimal places.
 *
 * @example
 * ```typescript
 * roundToNDecimalPlaces(3.14159); // returns 3.14
 * roundToNDecimalPlaces(3.14159, 3); // returns 3.142
 * roundToNDecimalPlaces(2.5, 0); // returns 3
 * ```
 */
export function roundToNDecimalPlaces(num: number, n = 2) {
	return Number((Math.round(num * 10 ** n) / 10 ** n).toFixed(n));
}

/**
 * Truncates a number to a specified number of decimal places without rounding.
 *
 * @example
 * ```typescript
 * cutToNDecimalPlaces(3.9999, 2); // returns 3.99
 * cutToNDecimalPlaces(3.12, 1); // returns 3.1
 * cutToNDecimalPlaces(100, 2); // returns 100
 * cutToNDecimalPlaces(3.0001, 2); // returns 3
 * ```
 */
export function cutToNDecimalPlaces(num: number, n = 2) {
	const multiplier = 10 ** n;
	// Round away floating point representation error (e.g. 0.29 * 100 = 28.999...) before truncating
	const scaled = Number((num * multiplier).toFixed(8));
	const truncatedNum = Math.trunc(scaled) / multiplier;
	const result = truncatedNum.toFixed(n);
	return Number(n > 0 ? result.replace(/\.?0+$/, "") : result);
}

/**
 * Calculates the average (arithmetic mean) of an array of numbers.
 * Returns 0 if the array is empty.
 *
 * @example
 * ```typescript
 * averageArray([2, 4, 6, 8]); // returns 5
 * averageArray([-2, -4, -6, -8]); // returns -5
 * averageArray([10, -10, 20, -20]); // returns 0
 * averageArray([42]); // returns 42
 * averageArray([]); // returns 0
 * ```
 */
export function averageArray(arr: number[]) {
	if (arr.length === 0) return 0;

	return R.sum(arr) / arr.length;
}

/**
 * Safely parses a string into a number, returning `null` if the input is `null`,
 * empty, or not a valid number.
 *
 * Trims whitespace from the input before parsing. If the trimmed string is empty
 * or cannot be converted to a valid number, returns `null`.
 *
 * @example
 * ```typescript
 * safeNumberParse("42"); // returns 42
 * safeNumberParse("  3.14 "); // returns 3.14
 * safeNumberParse(""); // returns null
 * safeNumberParse("abc"); // returns null
 * safeNumberParse(null); // returns null
 * ```
 */
export function safeNumberParse(value: string | null) {
	if (value === null) return null;

	const trimmed = value.trim();
	if (trimmed === "") return null;

	const result = Number(trimmed);
	return Number.isNaN(result) ? null : result;
}
