// Keep the preview consistent with MoneyMath::distribute on the server.
const toHundredths = (value: number | string): bigint => {
    const match = String(value).match(/^(\d+)(?:\.(\d{1,2}))?$/);
    return match ? BigInt(match[1]) * 100n + BigInt((match[2] ?? '').padEnd(2, '0')) : 0n;
};

export const allocateInvestment = (amount: number | string, percentages: (number | string)[]): string[] => {
    const capital = toHundredths(amount);
    const weights = percentages.map(toHundredths);
    const totalWeight = weights.reduce((sum, weight) => sum + weight, 0n);
    if (capital === 0n || totalWeight === 0n) return weights.map(() => '0.00');

    const allocations = weights.map((weight, index) => ({
        index,
        cents: capital * weight / totalWeight,
        // PHP truncates monetary shares to eight decimals: six places below a paisa.
        remainder: (capital * weight % totalWeight) * 1_000_000n / totalWeight,
    }));
    const remainderOrder = [...allocations].sort((a, b) =>
        a.remainder === b.remainder ? a.index - b.index : (a.remainder > b.remainder ? -1 : 1)
    );
    const leftover = capital - allocations.reduce((sum, allocation) => sum + allocation.cents, 0n);
    for (let index = 0; index < Number(leftover); index++) {
        remainderOrder[index].cents += 1n;
    }

    return allocations.map(({ cents }) => `${cents / 100n}.${String(cents % 100n).padStart(2, '0')}`);
};
