<?php

/**
 * ReconciliationHelper.php
 *
 * Pure logic functions for the Daily Transaction Reconciliation feature.
 * All functions are stateless and have no side effects — safe to unit-test
 * and property-test without a database connection.
 *
 * Feature: daily-transaction-reconciliation
 */

/**
 * Validate and sanitise a date string.
 *
 * Accepts a string in YYYY-MM-DD format. If the string is empty, malformed,
 * or does not represent a real calendar date, today's server date is returned
 * instead. The raw input is never used in any database query when invalid.
 *
 * @param  string $input  Raw date string from user input.
 * @return string         A valid YYYY-MM-DD date string.
 */
function validateReconciliationDate(string $input): string
{
    if ($input === '') {
        return date('Y-m-d');
    }

    $dt = DateTime::createFromFormat('Y-m-d', $input);

    // createFromFormat can return a DateTime even for overflow dates (e.g. 2025-13-01)
    // so we must also verify the re-formatted string matches the original input exactly.
    if ($dt === false || $dt->format('Y-m-d') !== $input) {
        return date('Y-m-d');
    }

    return $input;
}

/**
 * Format a monetary amount as a Naira string.
 *
 * Returns a string beginning with the ₦ symbol followed by the amount
 * formatted with thousands separators and exactly two decimal places.
 *
 * @param  float $amount  Non-negative amount in Naira.
 * @return string         e.g. "₦125,000.00"
 */
function formatNaira(float $amount): string
{
    return '₦' . number_format($amount, 2);
}

/**
 * Compute the reconciliation variance.
 *
 * Variance = Paystack inflows (from the `payments` table) minus the sum of
 * Paystack-method approved allocations (from the `payment` table).
 * A positive variance means more money entered Paystack than was allocated.
 * A negative variance means more was allocated than entered Paystack.
 * Zero means the books are balanced.
 *
 * @param  float $paystackTotal      Total Paystack inflows for the day.
 * @param  float $approvedPaystack   Total Paystack-method approved allocations.
 * @return float                     Signed variance amount.
 */
function computeVariance(float $paystackTotal, float $approvedPaystack): float
{
    return $paystackTotal - $approvedPaystack;
}

/**
 * Convert a Paystack API amount from kobo to Naira.
 *
 * The Paystack API returns all amounts in the smallest currency unit (kobo).
 * This function divides by 100 to convert to Naira.
 *
 * @param  int $kobo  Amount in kobo (integer, as returned by Paystack API).
 * @return float      Amount in Naira.
 */
function convertKoboToNaira(int $kobo): float
{
    return $kobo / 100;
}

/**
 * Classify payment references against Paystack API transaction references.
 *
 * Compares two sets of references and returns three groups:
 *  - matched:         references present in both local DB and Paystack API
 *  - missing_locally: references in Paystack API but NOT in local DB
 *  - not_in_paystack: references in local DB but NOT in Paystack API
 *
 * @param  array $localRefs  References from the local `payments` table.
 * @param  array $apiRefs    References returned by the Paystack API.
 * @return array{
 *     matched: array,
 *     missing_locally: array,
 *     not_in_paystack: array
 * }
 */
function classifyReferences(array $localRefs, array $apiRefs): array
{
    $localSet = array_values($localRefs);
    $apiSet   = array_values($apiRefs);

    $matched         = array_values(array_intersect($localSet, $apiSet));
    $missingLocally  = array_values(array_diff($apiSet, $localSet));
    $notInPaystack   = array_values(array_diff($localSet, $apiSet));

    return [
        'matched'         => $matched,
        'missing_locally' => $missingLocally,
        'not_in_paystack' => $notInPaystack,
    ];
}

/**
 * Compute the grand total of a collection of payment amounts.
 *
 * Sums all values in the provided array regardless of payment method.
 * Returns 0.0 for an empty array.
 *
 * @param  float[] $amounts  Array of individual payment amounts in Naira.
 * @return float             Sum of all amounts.
 */
function computeGrandTotal(array $amounts): float
{
    return (float) array_sum($amounts);
}
