<?php
/**
 * Monetary arithmetic.
 *
 * @package Harbor_EU_EInvoicing_For_WooCommerce
 */

defined( 'ABSPATH' ) || exit;

class HEIN_Money {

	/**
	 * The single float boundary in the plugin. BR-CO-10/13/14/15/16 are exact xs:decimal
	 * comparisons with zero tolerance, so everything downstream is integer-cent arithmetic
	 */
	public static function cents( float|string $value ): int {
		return (int) round( (float) $value * 100, 0, PHP_ROUND_HALF_UP );
	}

	public static function from_cents( int $cents ): string {
		return number_format( $cents / 100, 2, '.', '' );
	}

	public static function amount( float|string $value ): string {
		return self::from_cents( self::cents( $value ) );
	}

	public static function sum( array $amounts ): string {
		$total = 0;
		foreach ( $amounts as $amount ) {
			$total += self::cents( $amount );
		}
		return self::from_cents( $total );
	}

	public static function subtract( string $a, string $b ): string {
		return self::from_cents( self::cents( $a ) - self::cents( $b ) );
	}

	public static function tax_of( string $taxable, string $percent ): string {
		return self::from_cents(
			(int) round( self::cents( $taxable ) * (float) $percent / 100, 0, PHP_ROUND_HALF_UP )
		);
	}

	public static function percent( float|string $value ): string {
		return number_format( round( (float) $value, 2 ), 2, '.', '' );
	}

	public static function quantity( float|string $value ): string {
		return number_format( (float) $value, 4, '.', '' );
	}

	/**
	 * PEPPOL-EN16931-R120 allows only 0.02 between LineExtensionAmount and quantity x
	 * (price / base_quantity). The base_quantity = quantity fallback makes the product
	 * identically equal to the net amount, and R121 requires base_quantity > 0
	 */
	public static function price( string $net_amount, float $quantity ): array {
		$qty = $quantity <= 0 ? 1.0 : $quantity;
		$net = (float) $net_amount;
		$unit = round( $net / $qty, 4 );

		if ( abs( $qty * $unit - $net ) <= 0.005 ) {
			return [
				'price'         => number_format( $unit, 4, '.', '' ),
				'base_quantity' => self::quantity( 1 ),
			];
		}

		return [
			'price'         => number_format( $net, 4, '.', '' ),
			'base_quantity' => self::quantity( $qty ),
		];
	}

	public static function is_zero( string $amount ): bool {
		return 0 === self::cents( $amount );
	}

	public static function is_negative( string $amount ): bool {
		return self::cents( $amount ) < 0;
	}

	public static function abs( string $amount ): string {
		return self::from_cents( abs( self::cents( $amount ) ) );
	}
}
