<?php
/**
 * Shared helpers for turning one payment amount into several per-fee-item
 * `payments` rows. Used by every path that records a multi-item transaction
 * (the Hubtel/Paystack webhooks, and the bursar bulk-payment flow in
 * fees.php) so there is exactly one definition of "how much of this payment
 * belongs to which fee item".
 */

if (!defined('BASE_URL')) {
    require_once __DIR__ . '/../config.php';
}

if (!function_exists('fetchFeeStructureDetails')) {
    /**
     * @param array<int, int|null> $feeIds
     * @return array<int, array{amount: float, fee_type: string}> Keyed by fee_structure id.
     */
    function fetchFeeStructureDetails(mysqli $conn, array $feeIds): array
    {
        $validIds = array_values(array_unique(array_filter($feeIds, static fn($id) => $id !== null)));
        if ($validIds === []) {
            return [];
        }

        $placeholders = implode(',', array_fill(0, count($validIds), '?'));
        $types = str_repeat('i', count($validIds));
        $stmt = $conn->prepare("SELECT id, amount, fee_type FROM fee_structures WHERE id IN ($placeholders)");
        $stmt->bind_param($types, ...$validIds);
        $stmt->execute();
        $result = $stmt->get_result();

        $details = [];
        while ($row = $result->fetch_assoc()) {
            $details[(int) $row['id']] = [
                'amount'   => (float) $row['amount'],
                'fee_type' => (string) $row['fee_type'],
            ];
        }
        $stmt->close();

        return $details;
    }
}

if (!function_exists('proportionalPaymentShares')) {
    /**
     * Split $totalAmount across $feeIds in proportion to $weightsById — NOT
     * evenly. An even split misattributes the payment as soon as two selected
     * items carry different weights, which corrupts the per-item "amount
     * owed" balance every other page computes from `payments.amount_paid`.
     *
     * What to pass as the weight depends on what the caller actually knows:
     *   - Online gateway webhooks only ever see a combined total + a list of
     *     fee_structure_ids, with no per-item breakdown recorded anywhere —
     *     so each item's sticker `amount` (fetchFeeStructureDetails()) is the
     *     best available signal.
     *   - The bursar bulk-payment flow (fees.php) already knows each selected
     *     item's own outstanding `remaining` balance (rbcStudentFeeBreakdown())
     *     at submission time — using sticker amount there instead would
     *     misallocate between two items with different prior-payment
     *     histories even when the bursar enters exactly the combined
     *     remaining total. Use `remaining`, not `amount`, for that caller.
     *
     * Falls back to an even split only when every weight is zero (e.g. all
     * selected ids are unresolvable). The last item always absorbs the
     * rounding remainder, so shares sum to exactly $totalAmount regardless of
     * how the division rounds.
     *
     * @param array<int, int|null> $feeIds      Same order the caller will insert in.
     * @param array<int, float>    $weightsById Weight per fee_structure id (not per index).
     * @return array<int, float> Share for each index in $feeIds, same keys.
     */
    function proportionalPaymentShares(array $feeIds, array $weightsById, float $totalAmount): array
    {
        $count = count($feeIds);
        if ($count === 0) {
            return [];
        }

        $weights = [];
        $weightSum = 0.0;
        foreach ($feeIds as $index => $feeId) {
            $weight = ($feeId !== null && isset($weightsById[$feeId])) ? (float) $weightsById[$feeId] : 0.0;
            $weights[$index] = $weight;
            $weightSum += $weight;
        }

        $shares = [];
        $remaining = $totalAmount;
        $lastIndex = array_key_last($feeIds);
        foreach ($feeIds as $index => $feeId) {
            if ($index === $lastIndex) {
                $shares[$index] = round($remaining, 2);
                break;
            }
            $share = $weightSum > 0.0
                ? round($totalAmount * ($weights[$index] / $weightSum), 2)
                : round($totalAmount / $count, 2);
            $shares[$index] = $share;
            $remaining -= $share;
        }

        return $shares;
    }
}
