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

use SabaiApps\Directories\Application;
use SabaiApps\Directories\Exception;
use SabaiApps\Directories\Component\Payment;
use SabaiApps\Directories\Component\Entity\Type\IEntity;

class PlansHelper {

	protected $_plans = array();

	/**
	 * @param Application       $application
	 * @param string            $bundleName
	 * @param string|null       $type
	 * @param bool              $purchasableOnly
	 * @param string|null|false $lang Language code or false for all languages
	 * @param string|null       $component
	 * @return array
	 */
	public function help( Application $application, $bundleName, $type = null, $purchasableOnly = false, $lang = null, $component = null ) {
		if ( ! isset( $component ) ) {
			$component = $application->getComponent( 'Payment' )->getPaymentComponent( false, true );
		}
		if ( ! isset( $this->_plans[ $component ][ $bundleName ] ) ) {
			$plans = array();
			if ( ( $payment_component = $application->Payment_Components_impl( $component, true ) )
				&& $payment_component->paymentIsEnabled()
			) {
				foreach ( $payment_component->paymentGetPlanIds( $bundleName, $lang ) as $plan_id ) {
					if ( ! $plan = $payment_component->paymentGetPlanById( $bundleName, $plan_id ) ) {
						continue;
					}

					if ( $purchasableOnly
						&& ! $plan->paymentPlanIsPurchasable()
					) {
						continue;
					}

					$plans[ $plan_id ] = $plan;
				}
			} else {
				$application->logError( 'Invalid component or component not enabled: ' . $component );
			}
			$this->_plans[ $component ][ $bundleName ] = $plans;
		}
		if ( ! isset( $type ) ) {
			$this->sortPlans( $application, $this->_plans[ $component ][ $bundleName ] );
			return $this->_plans[ $component ][ $bundleName ];
		}

		$ret = array();
		settype( $type, 'array' );
		foreach ( array_keys( $this->_plans[ $component ][ $bundleName ] ) as $plan_id ) {
			$plan = $this->_plans[ $component ][ $bundleName ][ $plan_id ];
			if ( in_array( $plan->paymentPlanType(), $type ) ) {
				$ret[ $plan_id ] = $plan;
			}
		}
		return $ret;
	}

	public function sortPlans( Application $application, array &$plans, array $sortOrder = array() ) {
		if ( empty( $sortOrder ) ) {
			$sortOrder = array(
				'base'         => 0,
				'subscription' => 1,
				'addon'        => 2,
			);
		}
		uasort(
			$plans,
			function ( Payment\IPlan $a, Payment\IPlan $b ) use ( $sortOrder ) {
				$a_type  = $a->paymentPlanType();
				$b_type  = $b->paymentPlanType();
				$a_order = isset( $sortOrder[ $a_type ] ) ? $sortOrder[ $a_type ] : 99;
				$b_order = isset( $sortOrder[ $b_type ] ) ? $sortOrder[ $b_type ] : 99;
				if ( $a_order === $b_order ) {
					return strnatcasecmp( $a->paymentPlanTitle(), $b->paymentPlanTitle() );
				}
				return $a_order < $b_order ? -1 : 1;
			}
		);
	}

	public function orderableAddons( Application $application, $entityOrPlan ) {
		$current_features = array();
		if ( $entityOrPlan instanceof IEntity ) {
			if ( ! $plan = $application->Payment_Plan( $entityOrPlan ) ) {
				throw new Exception\RuntimeException( 'Could not fetch payment plan from entity' );
			}
			$current_features = (array) $entityOrPlan->getSingleFieldValue( 'payment_plan', 'addon_features' );
		} elseif ( $entityOrPlan instanceof Payment\IPlan ) {
			$plan = $entityOrPlan;
		} else {
			throw new Exception\InvalidArgumentException( 'Invalid 2nd argument for ' . __CLASS__ . '::' . __METHOD__ );
		}
		$current_features += $application->Payment_Plan_features( $plan );

		$ret = array();
		if ( ( $payment_component = $application->Payment_Components_impl( $plan->paymentPlanComponent(), true ) )
			&& ( $content_bundle_name = $payment_component->paymentGetPlanContentBundleName( $plan ) )
			&& ( $plans = $application->Payment_Plans( $content_bundle_name, 'addon' ) )
		) {
			foreach ( $plans as $plan_id => $addon_plan ) {
				if ( ! $addon_plan->paymentPlanIsPurchasable() ) {
					continue;
				}

				foreach ( (array) $addon_plan->paymentPlanFeatures() as $feature_name => $feature_settings ) {
					if ( ( $feature = $application->Payment_Features_impl( $feature_name, true ) )
						&& $feature instanceof Payment\Feature\IAddonFeature
						&& $feature->paymentAddonFeatureIsOrderable( $feature_settings, $current_features )
					) {
						$ret[ $plan_id ] = $addon_plan;
						continue 2; // the plan is orderable, so skip other features
					}
				}
			}
		}

		return $ret;
	}

	public function form( Application $application, $entityOrBundleName, $type = 'base', $excludeCurrent = false, $pricingTable = false, $addFreePlan = true ) {
		$plan_descriptions = $plans_disabled = array();
		$current_plan_id   = null;
		if ( ! is_array( $type )
			&& $type === 'addon'
		) {
			try {
				if ( ! $entityOrBundleName instanceof IEntity ) {
					throw new Exception\InvalidArgumentException( 'Invalid 1st argument for ' . __CLASS__ . '::' . __METHOD__ );
				}
				$bundle_name = $entityOrBundleName->getBundleName();
				$plans       = $this->orderableAddons( $application, $entityOrBundleName );
			} catch ( Exception\IException $e ) {
				$plans = array();
				$application->logError( $e );
			}
			foreach ( array_keys( $plans ) as $plan_id ) {
				$plan                          = $plans[ $plan_id ];
				$plan_descriptions[ $plan_id ] = $plan->paymentPlanDescription();
				$plans[ $plan_id ]             = $application->H( $plan->paymentPlanTitle() ) . ' - ' . $application->Payment_Plan_formattedPrice( $plan );
			}
		} else {
			if ( $entityOrBundleName instanceof IEntity ) {
				$bundle_name     = $entityOrBundleName->getBundleName();
				$current_plan_id = $entityOrBundleName->getSingleFieldValue( 'payment_plan', 'plan_id' );
			} else {
				$bundle_name = $entityOrBundleName;
			}
			$plans = $application->Payment_Plans( $bundle_name, $type );
			foreach ( array_keys( $plans ) as $plan_id ) {
				$plan_descriptions[ $plan_id ] = $plans[ $plan_id ]->paymentPlanDescription();
				$title                         = $application->H( $plans[ $plan_id ]->paymentPlanTitle() );
				if ( $current_plan_id
					&& $current_plan_id === $plan_id
				) {
					if ( $excludeCurrent ) {
						$plans_disabled[] = $plan_id;
					}
					$title .= '<strong> — <span class="drts-payment-select-plan-state">'
						. $application->H( __( 'Current plan', 'directories-pro' ) )
						. '</span></strong>';
				} else {
					if ( ! $plans[ $plan_id ]->paymentPlanIsPurchasable()
						|| ( ! $addFreePlan && $application->Payment_Plan_isFree( $plans[ $plan_id ] ) )
					) {
						unset( $plans[ $plan_id ] );
						continue;
					}

					$title .= ' - ' . $application->Payment_Plan_formattedPrice( $plans[ $plan_id ] );
				}
				if ( $plans[ $plan_id ]->paymentPlanIsFeatured() ) {
					$title = '<span class="drts-payment-select-plan-featured">' . $title . '</span>';
				}
				$plans[ $plan_id ] = $title;
			}

			if ( $addFreePlan
				&& $this->noPaymentPlanEnabled( $application, $bundle_name )
			) {
				$no_payment_plan_label = $this->noPaymentPlanLabel( $application );
				$plans[0]              = $no_payment_plan_label[0];
				if ( strlen( $no_payment_plan_label[1] ) ) {
					$plan_descriptions[0] = $no_payment_plan_label[1];
				}
			}
		}

		if ( ! empty( $plans ) ) {
			$plans = $application->Filter( 'payment_plans_form', $plans, array( $bundle_name, $type ) );
		}

		if ( empty( $plans ) ) {
			return array(
				'#header' => array(
					'<div class="' . DRTS_BS_PREFIX . 'alert ' . DRTS_BS_PREFIX . 'alert-warning">'
						. $application->H( __( 'There are currently no payment plans available.', 'directories-pro' ) )
						. '</div>',
				),
			);
		}

		if ( $pricingTable ) {
			$bundle                 = $application->Entity_Bundle( $entityOrBundleName );
			$pricing_table_settings = array(
				'plans'                 => array_keys( $plans ),
				'add_no_payment_plan'   => isset( $plans[0] ),
				'no_payment_plan_title' => isset( $plans[0] ) ? $plans[0] : null,
				'no_payment_plan_desc'  => isset( $plan_descriptions[0] ) ? $plan_descriptions[0] : null,
			);
			if ( is_array( $pricingTable ) ) {
				$pricing_table_settings += $pricingTable;
			}
			return array(
				'#class'        => 'drts-payment-pricing-table-form',
				'pricing_table' => array(
					'#type'     => 'markup',
					'#markup'   => $application->getPlatform()->render( $bundle->getPath() . '/pricing', array( 'settings' => $pricing_table_settings ) ),
					'#js_ready' => '$("#__FORM_ID__").on("click", ".drts-payment-plan-footer a", function(){
    $("#__FORM_ID__").append($("<input>", {
        type: "hidden",
        name: "plan",
        value: $(this).closest(".drts-payment-plan").data("plan-id")
    })).append($("<input>", {
        type: "hidden",
        name: "bundle",
        value: "' . $bundle->name . '"
    })).find("button[value=select_plan]").click();
    return false;
});',
				),
			);
		}

		return array(
			'plan' => array(
				'#type'                => 'radios',
				'#columns'             => 1,
				'#title'               => __( 'Select Plan', 'directories-pro' ),
				'#required'            => true,
				'#options'             => $plans,
				'#options_description' => $plan_descriptions,
				'#options_disabled'    => $plans_disabled,
				'#option_no_escape'    => true,
				'#default_value'       => isset( $current_plan_id ) ? $current_plan_id : ( isset( $plans[0] ) ? 0 : null ),
				'#default_value_auto'  => true,
				'#class'               => 'drts-payment-select-plan',
				'#horizontal'          => true,
			),
		);
	}

	public function noPaymentPlanLabel( Application $application ) {
		$none_label = $application->getComponent( 'Payment' )->getConfig( 'plan', 'none_label' );
		$none_label = $application->System_TranslateString( $none_label, 'no_payment_plan_label', 'payment' );
		$none_desc  = $application->getComponent( 'Payment' )->getConfig( 'plan', 'none_desc' );
		$none_desc  = $application->System_TranslateString( $none_desc, 'no_payment_plan_desc', 'payment' );

		return array( $none_label, $none_desc );
	}

	public function noPaymentPlanEnabled( Application $application, $bundleName ) {
		$bundle = $application->Entity_Bundle( $bundleName, '', true );
		if ( $bundle->entitytype_name !== 'post' ) {
			return false;
		}

		return $application->Filter(
			'payment_plans_no_payment_plan_enabled',
			(bool) $application->getComponent( 'Payment' )->getConfig( 'plan', 'allow_none' ),
			array( $bundleName )
		);
	}
}
