<?php

/**
 * Single shared currency formatter — every screen that displays money
 * (folios, invoices, the Phase 4 KPI dashboard) should call this rather
 * than rolling its own number_format(), so GHS formatting never drifts
 * between screens built in different phases.
 *
 * Amounts are always decimal(10,2) in the DB and should be passed here as
 * numeric strings or floats already in GHS (never as float in storage —
 * only at the point of display/math does PHP float precision come into play,
 * and this helper rounds explicitly rather than trusting the caller).
 */
if (! function_exists('format_money')) {
    /**
     * GHS stays the real settlement currency everywhere (matches Hubtel,
     * which only ever settles GHS) — $showConversion adds a second,
     * purely informational line for guest-facing screens only (booking
     * wizard payment step, folio/invoice view), never internal reports/
     * exports, using a manager-entered manual rate (billing.display_
     * currency_code / billing.display_exchange_rate — no live FX API).
     * Renders raw HTML (a <br> + a muted line), matching how every
     * existing call site already echoes this unescaped.
     */
    function format_money($amount, bool $withSymbol = true, bool $showConversion = false): string
    {
        $value  = number_format((float) $amount, 2, '.', ',');
        $result = $withSymbol ? 'GHS ' . $value : $value;

        if (! $showConversion) {
            return $result;
        }

        $settings = service('settings');
        $currency = $settings->get('billing.display_currency_code');
        $rate     = (float) ($settings->get('billing.display_exchange_rate') ?: 0);

        if (! $currency || $rate <= 0) {
            return $result;
        }

        $converted = number_format((float) $amount * $rate, 2, '.', ',');

        return $result . '<br><small class="text-muted">&asymp; ' . esc($converted) . ' ' . esc($currency) . '</small>';
    }
}

if (! function_exists('money_subtract')) {
    /**
     * Subtracts two decimal-string GHS amounts without float rounding
     * drift (bcmath when available; a rounded float fallback otherwise).
     * Used anywhere a folio balance (charges - payments) is computed.
     */
    function money_subtract(string $a, string $b): string
    {
        if (function_exists('bcsub')) {
            return bcsub($a, $b, 2);
        }

        return number_format((float) $a - (float) $b, 2, '.', '');
    }
}

if (! function_exists('money_add')) {
    /**
     * Adds two decimal-string GHS amounts — same bcmath-or-fallback
     * reasoning as money_subtract. Used e.g. by the dashboard to combine
     * the "event" and "other" folio categories into one "Other Services"
     * figure without float drift.
     */
    function money_add(string $a, string $b): string
    {
        if (function_exists('bcadd')) {
            return bcadd($a, $b, 2);
        }

        return number_format((float) $a + (float) $b, 2, '.', '');
    }
}

if (! function_exists('money_multiply')) {
    /**
     * Multiplies a decimal-string GHS amount by a plain quantity (e.g. a
     * POS order line's quantity × unit_price) — same bcmath-or-fallback
     * approach as money_subtract, kept out of views so nothing calls
     * bcmul() directly without the fallback.
     */
    function money_multiply(string $amount, int $quantity): string
    {
        if (function_exists('bcmul')) {
            return bcmul($amount, (string) $quantity, 2);
        }

        return number_format((float) $amount * $quantity, 2, '.', '');
    }
}

if (! function_exists('money_divide')) {
    /**
     * Divides a decimal-string GHS amount by a plain divisor (e.g. total
     * room revenue ÷ room-nights sold, for ADR/RevPAR on the Reports
     * page) — same bcmath-or-fallback approach as money_subtract/
     * money_add/money_multiply. Every caller already checks the divisor
     * for zero before calling this (same "0.00" convention as the rest
     * of this file — division itself never guards against zero).
     */
    function money_divide(string $amount, string $divisor): string
    {
        if (function_exists('bcdiv')) {
            return bcdiv($amount, $divisor, 2);
        }

        return number_format((float) $amount / (float) $divisor, 2, '.', '');
    }
}

if (! function_exists('parse_money')) {
    /**
     * Normalizes user input (which may contain "GHS", commas, stray
     * whitespace) back into a plain decimal string safe to store/validate
     * against decimal(10,2) columns.
     */
    function parse_money($input): string
    {
        $clean = preg_replace('/[^0-9.\-]/', '', (string) $input) ?? '0';

        return number_format((float) $clean, 2, '.', '');
    }
}
