<?php

namespace SugarCalendarBookings\Payments;

use SugarCalendarBookings\Appointments\AppointmentModel;
use SugarCalendarBookings\Payments\Gateways\Onsite\OnSitePaymentGateway;
use SugarCalendarBookings\Payments\Gateways\PaymentGatewayRegistry;
use SugarCalendarBookings\Options;
use SugarCalendarBookings\Plugin;

/**
 * Payments helpers.
 *
 * @since 1.0.0
 */
class PaymentsHelpers {

	/**
	 * Payment callback parameter.
	 *
	 * @since 1.0.0
	 *
	 * @var string
	 */
	const PAYMENT_CALLBACK_PARAMETER = 'scbookings_payment_callback';

	/**
	 * Format currency for display.
	 *
	 * @since 1.0.0
	 *
	 * @param float  $amount   Amount.
	 * @param string $currency Currency.
	 *
	 * @return string Formatted currency.
	 */
	public static function format_currency( $amount, $currency = null ) { // phpcs:ignore Generic.Metrics.CyclomaticComplexity.MaxExceeded

		if ( empty( $amount ) ) {
			$amount = 0;
		}

		if ( $currency === null ) {
			$currency = self::get_currency();
		}

		$position = Plugin::get( Options::class )->get( 'payments.currency_position' );
		$negative = $amount < 0;

		if ( $negative === true ) {
			$amount = abs( $amount );
		}

		$amount = self::format_amount( $amount );

		if ( $position === 'before' ) {

			switch ( $currency ) {
				case 'GBP':
					$formatted = '&pound;' . $amount;
					break;

				case 'BRL':
					$formatted = 'R&#36;' . $amount;
					break;

				case 'BTC':
					$formatted = '&#579;' . $amount;
					break;

				case 'EUR':
					$formatted = '&euro;' . $amount;
					break;

				case 'USD':
				case 'AUD':
				case 'CAD':
				case 'HKD':
				case 'MXN':
				case 'SGD':
					$formatted = '&#36;' . $amount;
					break;

				case 'RON':
					$formatted = 'lei' . $amount;
					break;

				case 'UAH':
					$formatted = '&#8372;' . $amount;
					break;

				case 'JPY':
					$formatted = '&yen;' . $amount;
					break;

				case 'KRW':
					$formatted = '&#8361;' . $amount;
					break;

				case 'PKR':
					$formatted = '&#8360;' . $amount;
					break;

				default:
					$formatted = $currency . ' ' . $amount;
					break;
			}
		} else {

			switch ( $currency ) {
				case 'GBP':
					$formatted = $amount . '&pound;';
					break;

				case 'BRL':
					$formatted = $amount . 'R&#36;';
					break;

				case 'EUR':
					$formatted = $amount . '&euro;';
					break;

				case 'USD':
				case 'AUD':
				case 'CAD':
				case 'HKD':
				case 'MXN':
				case 'SGD':
					$formatted = $amount . '&#36;';
					break;

				case 'RON':
					$formatted = $amount . 'lei';
					break;

				case 'UAH':
					$formatted = $amount . '&#8372;';
					break;

				case 'JPY':
					$formatted = $amount . '&yen;';
					break;

				case 'KRW':
					$formatted = $amount . '&#8361;';
					break;

				case 'IRR':
					$formatted = $amount . '&#65020;';
					break;

				case 'RUB':
					$formatted = $amount . '&#8381;';
					break;

				default:
					$formatted = $amount . ' ' . $currency;
					break;
			}
		}

		// Prepend the mins sign before the currency sign.
		if ( $negative === true ) {
			$formatted = '-' . $formatted;
		}

		return $formatted;
	}

	/**
	 * Retrieves the currency.
	 *
	 * @since 1.0.0
	 *
	 * @return string Currency
	 */
	public static function get_currency() {

		return Plugin::get( Options::class )->get( 'payments.currency' );
	}

	/**
	 * Format the amount.
	 *
	 * @since 1.0.0
	 *
	 * @param float $amount   Amount.
	 * @param bool  $decimals Decimals.
	 *
	 * @return string Formatted amount.
	 */
	public static function format_amount( $amount, $decimals = true ) {

		if ( empty( $amount ) ) {
			$amount = 0;
		}

		$thousands_sep = Plugin::get( Options::class )->get( 'payments.thousands_separator' );
		$decimal_sep   = Plugin::get( Options::class )->get( 'payments.decimal_separator' );
		$decimals      = self::get_decimal_count();

		return number_format( $amount, $decimals, $decimal_sep, $thousands_sep );
	}

	/**
	 * Get the number of decimals to round to based on the currency.
	 *
	 * @since 1.0.0
	 *
	 * @return int Number of decimal places.
	 */
	public static function get_decimal_count() { // phpcs:ignore Generic.Metrics.CyclomaticComplexity.TooHigh

		$currency = self::get_currency();

		switch ( $currency ) {
			case 'RIAL':
			case 'JPY':
			case 'TWD':
			case 'KRW':
				$decimals = 0;
				break;

			case 'BTC':
				$decimals = 9;
				break;

			default:
				$decimals = 2;
				break;
		}

		return $decimals;
	}

	/**
	 * Get the list of available currencies.
	 *
	 * @since 1.0.0
	 *
	 * @return array $currencies A list of the available currencies.
	 */
	public static function get_currencies() {

		$currencies = [
			'USD' => esc_html__( 'US Dollar', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'EUR' => esc_html__( 'Euro', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'ARS' => esc_html__( 'Argentine Peso', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'AUD' => esc_html__( 'Australian Dollar', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'BDT' => esc_html__( 'Bangladeshi Taka', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'BTC' => esc_html__( 'Bitcoin', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'BRL' => esc_html__( 'Brazilian Real', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'BGN' => esc_html__( 'Bulgarian Lev', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'CAD' => esc_html__( 'Canadian Dollar', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'CLP' => esc_html__( 'Chilean Peso', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'CNY' => esc_html__( 'Chinese Yuan', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'COP' => esc_html__( 'Colombian Peso', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'HRK' => esc_html__( 'Croatia Kuna', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'CZK' => esc_html__( 'Czech Koruna', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'DKK' => esc_html__( 'Danish Krone', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'DOP' => esc_html__( 'Dominican Peso', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'EGP' => esc_html__( 'Egyptian Pound', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'HKD' => esc_html__( 'Hong Kong Dollar', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'HUF' => esc_html__( 'Hungarian Forint', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'ISK' => esc_html__( 'Icelandic Krona', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'IDR' => esc_html__( 'Indonesia Rupiah', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'INR' => esc_html__( 'Indian Rupee', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'ILS' => esc_html__( 'Israeli Shekel', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'IRR' => esc_html__( 'Iranian Rial', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'JPY' => esc_html__( 'Japanese Yen', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'KES' => esc_html__( 'Kenyan Shilling', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'KZT' => esc_html__( 'Kazakhstani Tenge', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'KIP' => esc_html__( 'Lao Kip', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'MYR' => esc_html__( 'Malaysian Ringgit', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'MXN' => esc_html__( 'Mexican Peso', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'NPR' => esc_html__( 'Nepali Rupee', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'NGN' => esc_html__( 'Nigerian Naira', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'NOK' => esc_html__( 'Norwegian Krone', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'NZD' => esc_html__( 'New Zealand Dollar', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'PKR' => esc_html__( 'Pakistani Rupee', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'PYG' => esc_html__( 'Paraguayan Guaraní', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'PHP' => esc_html__( 'Philippine Peso', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'PLN' => esc_html__( 'Polish Zloty', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'GBP' => esc_html__( 'Pounds Sterling', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'RON' => esc_html__( 'Romanian Leu', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'RUB' => esc_html__( 'Russian Ruble', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'SAR' => esc_html__( 'Saudi Arabian Riyal', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'SGD' => esc_html__( 'Singapore Dollar', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'ZAR' => esc_html__( 'South African Rand', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'KRW' => esc_html__( 'South Korean Won', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'SEK' => esc_html__( 'Swedish Krona', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'CHF' => esc_html__( 'Swiss Franc', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'TWD' => esc_html__( 'Taiwan New Dollar', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'THB' => esc_html__( 'Thai Baht', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'TND' => esc_html__( 'Tunisian Dinar', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'TRY' => esc_html__( 'Turkish Lira', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'AED' => esc_html__( 'United Arab Emirates Dirham', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'UAH' => esc_html__( 'Ukrainian Hryvnia', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'VND' => esc_html__( 'Vietnamese Dong', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
		];

		return $currencies;
	}

	/**
	 * Get a payment redirect URL.
	 *
	 * @since 1.0.0
	 *
	 * @param string $url        Redirect URL.
	 * @param string $gateway_id Gateway ID.
	 *
	 * @return string
	 */
	public static function get_redirect_url( $url, $gateway_id ) {

		return add_query_arg( self::PAYMENT_CALLBACK_PARAMETER, $gateway_id, $url );
	}

	/**
	 * Check if given request is a payment redirect URL.
	 *
	 * @since 1.0.0
	 *
	 * @param array  $request    Request data.
	 * @param string $gateway_id Gateway ID.
	 *
	 * @return bool
	 */
	public static function is_redirect_url( $request, $gateway_id ) {

		if ( ! isset( $request[ self::PAYMENT_CALLBACK_PARAMETER ] ) ) {
			return false;
		}

		return $request[ self::PAYMENT_CALLBACK_PARAMETER ] === $gateway_id;
	}

	/**
	 * Get the first payment for an appointment.
	 *
	 * @since 1.1.0
	 *
	 * @param AppointmentModel $appointment Appointment model instance.
	 *
	 * @return PaymentModel|null First payment or null if not found.
	 */
	public static function get_payment( $appointment ) {

		if ( empty( $appointment->payments ) || ! is_array( $appointment->payments ) || count( $appointment->payments ) === 0 ) {
			return null;
		}

		return $appointment->payments[0];
	}

	/**
	 * Get refundable payment for an appointment.
	 *
	 * @since 1.1.0
	 *
	 * @param AppointmentModel $appointment Appointment model instance.
	 *
	 * @return PaymentModel|null Refundable payment or null if not found.
	 */
	public static function get_refundable_payment( AppointmentModel $appointment ) {

		$payment = self::get_payment( $appointment );

		if ( ! $payment ) {
			return null;
		}

		// Only refund online payments (not onsite) that are completed.
		if ( $payment->gateway === OnSitePaymentGateway::ID || $payment->status !== PaymentModel::STATUS_COMPLETED ) {
			return null;
		}

		return $payment;
	}

	/**
	 * Get payment gateway display name.
	 *
	 * @since 1.1.0
	 *
	 * @param PaymentModel $payment Payment model instance.
	 *
	 * @return string Gateway display name.
	 */
	public static function get_payment_gateway_display_name( PaymentModel $payment ) {

		// Get the gateway name from the registry.
		$gateway_registry = Plugin::get( PaymentGatewayRegistry::class );
		$gateway          = $gateway_registry->get( $payment->gateway );

		if ( ! $gateway ) {
			return ucfirst( $payment->gateway );
		}

		return $gateway::get_name();
	}
}
