<?php
namespace SabaiApps\Directories\Component\PaymentGateway\Helper;

use SabaiApps\Directories\Application;
use SabaiApps\Directories\Exception;
use SabaiApps\Directories\Component\PaymentGateway\Gateway\IGateway;
use SabaiApps\Directories\Component\Entity\Type\IEntity;
use SabaiApps\Directories\Component\Payment\IPlan;

class UtilHelper {

	/**
	 * @param Application $application
	 * @param bool        $useCache
	 * @return array
	 */
	public function gateways( Application $application, $useCache = true ) {
		if ( ! $useCache
			|| ( ! $components = $application->getPlatform()->getCache( 'paymentgateway_gateways' ) )
		) {
			$components = $labels = array();
			foreach ( $application->InstalledComponentsByInterface( 'PaymentGateway\IGateways' ) as $component_name ) {
				if ( ! $application->isComponentLoaded( $component_name ) ) {
					continue;
				}

				foreach ( $application->getComponent( $component_name )->paymentGetGatewayNames() as $gateway_name ) {
					if ( ! $component = $application->getComponent( $component_name )->paymentGetGateway( $gateway_name ) ) {
						continue;
					}

					$components[ $gateway_name ] = $component_name;
					$labels[ $gateway_name ]     = $component->paymentGatewayInfo( 'label' );
				}
			}
			asort( $labels );
			$components_sorted = array();
			foreach ( array_keys( $labels ) as $gateway_name ) {
				$components_sorted[ $gateway_name ] = $components[ $gateway_name ];
			}
			$application->getPlatform()->setCache( $components_sorted, 'paymentgateway_gateways' );
		}

		return $components;
	}

	private $_gateways = array();

	/**
	 * @param Application $application
	 * @param string      $gateway
	 * @return IGateway
	 */
	public function gateway( Application $application, $gateway, $returnFalse = false ) {
		if ( ! isset( $this->_gateways[ $gateway ] ) ) {
			if ( ( ! $gateways = $this->gateways( $application ) )
				|| ! isset( $gateways[ $gateway ] )
				|| ! $application->isComponentLoaded( $gateways[ $gateway ] )
			) {
				if ( $returnFalse ) {
					return false;
				}
				throw new Exception\UnexpectedValueException( sprintf( 'Invalid payment gateway: %s', $gateway ) );
			}
			$this->_gateways[ $gateway ] = $application->getComponent( $gateways[ $gateway ] )->paymentGetGateway( $gateway );
		}

		return $this->_gateways[ $gateway ];
	}

	public function renderLabel( Application $application, $label, $color = 'secondary', $badge = false ) {
		if ( $badge ) {
			$class = DRTS_BS_PREFIX . 'badge ' . DRTS_BS_PREFIX . 'bg-' . $color;
			$style = 'font-size:90%;';
		} else {
			$class = DRTS_BS_PREFIX . 'text-' . $color;
			$style = '';
		}
		return '<span class="' . $application->H( $class ) . '" style="' . $style . '">' . $application->H( $label ) . '</span>';
	}

	public function renderNote( Application $application, array $note, $isFormField = false, array $labels = array() ) {
		$labels += array(
			'added_by' => __( 'Added by: %s', 'directories-pro' ),
		);
		if ( empty( $note['lv'] ) ) {
			$color = DRTS_BS_PREFIX . 'bg-light';
		} else {
			$color = DRTS_BS_PREFIX . 'bg-' . $note['lv'] . ' ' . DRTS_BS_PREFIX . 'text-white';
		}
		if ( ! empty( $note['by'] )
			&& ( $identity = $application->UserIdentity( $note['by'] ) )
			&& ! $identity->isAnonymous()
		) {
			$by = $identity->name;
		} else {
			$by = __( 'System', 'directories-pro' );
		}
		if ( $isFormField ) {
			$input  = '<input type="hidden" name="__FORM_FIELD_NAME__" value="' . $application->H( $note['msg'] ) . '" />';
			$button = '<button type="button" class="' . DRTS_BS_PREFIX . 'ml-2 ' . DRTS_BS_PREFIX . 'mb-1 ' . DRTS_BS_PREFIX . 'btn-close" data-bs-dismiss="toast" aria-label="Close"></button>';
		} else {
			$input = $button = '';
		}
		$data_note_id = empty( $note['id'] ) ? '' : ' data-note-id="' . $application->H( $note['id'] ) . '"';
		return '<div class="drts-paymentgateway-order-note ' . DRTS_BS_PREFIX . 'toast ' . DRTS_BS_PREFIX . 'show ' . DRTS_BS_PREFIX . 'mb-2" style="opacity:1; max-width:none; width:100%; border-radius:0; box-shadow:none;"' . $data_note_id . '>'
			. '<div class="' . DRTS_BS_PREFIX . 'toast-header ' . $color . '" style="border-radius:0;">'
			. '<span class="' . DRTS_BS_PREFIX . 'me-auto">' . $application->H( sprintf( $labels['added_by'], $by ) ) . '</span>'
			. '<small>' . $application->System_Date_datetime( $note['ts'], true ) . '</small>' . $button
			. '</div><div class="' . DRTS_BS_PREFIX . 'toast-body">' . $application->Htmlize( nl2br( $note['msg'] ), true ) . '</div>' . $input . '</div>';
	}

	public function note( Application $application, $message, $level = null, $by = null, $id = null, $timestamp = null ) {
		$note = array(
			'msg' => $message,
			'ts'  => isset( $timestamp ) ? (int) $timestamp : time(),
		);
		if ( isset( $level ) ) {
			$note['lv'] = $level;
		}
		if ( isset( $by ) ) {
			$note['by'] = (int) $by;
		}
		if ( isset( $id ) ) {
			$note['id'] = $id;
		}
		return $note;
	}

	public function notesForm( Application $application, $title, $value = null, array $currentNotes = array(), $allowAdd = true, $horizontal = true, array $labels = array() ) {
		$form = array(
			'#title'      => $title,
			'#js_ready'   => '$(".drts-paymentgateway-order-note button").click(".' . DRTS_BS_PREFIX . 'close", function() {
    $(this).closest(".drts-paymentgateway-order-note").fadeOut("normal", function() {$(this).remove();});
});',
			'#horizontal' => $horizontal,
		);
		if ( isset( $value ) ) { // value is not set on submit
			$notes = $value;
		} else {
			$notes = $currentNotes;
		}
		if ( ! empty( $notes ) ) {
			$form[-1] = array(
				'#type'   => 'markup',
				'#markup' => '<div style="max-height:500px; overflow:auto;">',
			);
			uasort(
				$notes,
				function ( $a, $b ) {
					return $b['ts'] <=> $a['ts'];
				}
			);
			foreach ( $notes as $note ) {
				if ( ! $note ) {
					continue;
				}

				$form[] = array(
					'#type'   => 'item',
					'#markup' => $this->renderNote( $application, $note, true, $labels ),
				);
			}
			$form[] = array(
				'#type'   => 'markup',
				'#markup' => '</div>',
			);
		}
		if ( $allowAdd ) {
			$form[ count( $currentNotes ) + 1 ] = array(
				'#type'             => 'textarea',
				'#rows'             => 1,
				'#placeholder'      => __( 'Add a new note.', 'directories-pro' ),
				'#element_validate' => array(
					function ( $form, &$value ) use ( $application ) {
						if ( ! strlen( $value ) ) {
							return;
						}
							$value = array(
								'msg' => $value,
								'by'  => $application->getUser()->id,
							);
					},
				),
			);
		}
		return $form;
	}

	public function renderPaymentSummary( Application $application, $title, $description, $price, $currency, $tax, array $fees = array(), array $discounts = array() ) {
		$total           = $subtotal = $price;
		$discount_amount = 0;
		if ( ! empty( $discounts ) ) {
			foreach ( array_keys( $discounts ) as $i ) {
				if ( ! is_array( $discounts[ $i ] ) ) {
					continue;
				}

				if ( $discounts[ $i ]['type'] === 'percentage' ) {
					$_discount_amount         = $price * $discounts[ $i ]['value'] / 100;
					$discounts[ $i ]['price'] = $application->System_Currency_format( $_discount_amount, $currency );
					$total                   -= $_discount_amount;
					$discount_amount         += $_discount_amount;
					break;
				} else {
					$discounts[ $i ]['price'] = $application->System_Currency_format( $discounts[ $i ]['value'], $currency );
					$total                   -= $discounts[ $i ]['value'];
					$discount_amount         += $discounts[ $i ]['value'];
				}
			}
		}
		if ( ! empty( $fees ) ) {
			foreach ( array_keys( $fees ) as $fee_name ) {
				$amount = $fees[ $fee_name ]['price'];
				if ( ! empty( $fees[ $fee_name ]['is_discount'] ) ) {
					$amount *= -1;
				}
				$total                     += $amount;
				$fees[ $fee_name ]['price'] = $application->System_Currency_format( $amount, $currency );
				$fees[ $fee_name ]['label'] = $application->Payment_Fee_label( $fee_name );
			}
		}
		$tax_price = 0;
		if ( ! empty( $tax ) ) {
			$tax_price = $total * $tax / 100;
		}
		$total += $tax_price;
		return $application->Render(
			array( 'paymentgateway_payment_summary', 'directories-pro' ),
			array(
				'title'           => $title,
				'description'     => $description,
				'currency'        => $currency,
				'price'           => $price,
				'tax'             => empty( $tax_price ) ? null : $tax_price,
				'tax_rate'        => $tax,
				'subtotal'        => $subtotal,
				'total'           => $total,
				'fees'            => $fees,
				'discounts'       => $discounts,
				'discount_amount' => $discount_amount,
			),
			true
		);
	}

	public function formatPrice( Application $application, $price, $includeTax = true ) {
		$payment_component = $application->Payment_Components_impl( 'default' );
		if ( $includeTax
			&& ( $settings = $payment_component->getSettings() )
			&& ! empty( $settings['tax_enable'] )
			&& ! empty( $settings['tax']['rate'] )
		) {
			$tax   = $settings['tax']['rate'];
			$price = $price * ( 1 + $tax / 100 );
		}
		$currency = $payment_component->paymentGetCurrency();
		if ( $currency_format = $application->System_Currency_formats( $currency ) ) {
			$price = round( $price, $currency_format[0] );
			if ( ! empty( $currency_format[0] ) ) {
				// Pad 0s or will not work with PayPal
				$price = str_replace( ',', '', number_format( $price, $currency_format[0] ) );
			}
		}
		return $price;
	}

	public function planTypes( Application $application ) {
		return array(
			'base'         => __( 'Base', 'directories-pro' ),
			'subscription' => __( 'Subscription', 'directories-pro' ),
			'addon'        => __( 'Add-on', 'directories-pro' ),
		);
	}

	public function discountTypes( Application $application ) {
		return array(
			'fixed'      => __( 'Fixed amount', 'directories-pro' ),
			'percentage' => __( 'Percentage', 'directories-pro' ),
		);
	}

	public function isValidDiscount( Application $application, IEntity $discount, IPlan $plan = null ) {
		$application->Entity_Field_load( $discount );
		if ( ( ! $discount_info = $discount->getSingleFieldValue( 'paymentgateway_discount' ) )
			|| empty( $discount_info['active'] )
			|| ( ! empty( $discount_info['starts_at'] ) && $discount_info['starts_at'] > time() )
			|| ( ! empty( $discount_info['expires_at'] ) && $discount_info['expires_at'] <= time() )
			|| ( ! empty( $discount_info['max_redemptions'] ) && ! empty( $discount_info['usage_count'] ) && $discount_info['max_redemptions'] <= $discount_info['usage_count'] )
		) {
			return false;
		}

		return $application->Filter( 'paymentgateway_discount_is_valid', true, array( $discount_info, $plan ) ) ? $discount_info : false;
	}

	public function hasDiscount( Application $application, IPlan $plan ) {
		if ( ! $discount = $plan->getPlan()->getSingleFieldValue( 'paymentgateway_plan_discount' ) ) {
			return false;
		}
		return $this->isValidDiscount( $application, $discount, $plan ) ? $discount : false;
	}
}
