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

use SabaiApps\Directories\Application;
use SabaiApps\Directories\Exception;
use SabaiApps\Directories\Component\Entity\Type\IEntity;
use SabaiApps\Directories\Component\Entity\Model\Bundle;
use SabaiApps\Directories\Component\Payment\IOrder;
use SabaiApps\Directories\Component\Payment\ISubscription;
use SabaiApps\Directories\Component\Payment\IPlan;

class PlanHelper {

	/**
	 * @param Application                                $application
	 * @param IEntity|Bundle|string|IOrder|ISubscription $object
	 * @param int|string|null                            $planId
	 * @param string|null                                $component
	 * @return IPlan|null
	 */
	public function help( Application $application, $object, $planId = null, $component = null ) {
		if ( $object instanceof IOrder ) {
			return $object->paymentOrderPlan();
		}

		if ( $object instanceof ISubscription ) {
			return $object->paymentSubscriptionPlan();
		}

		if ( ! $object instanceof Bundle ) {
			if ( ! $bundle = $application->Entity_Bundle( $object ) ) {
				throw new Exception\RuntimeException( 'Invalid bundle: ' . ( $object instanceof IEntity ? $object->getBundleName() : $object ) );
			}
		} else {
			$bundle = $object;
		}

		if ( empty( $bundle->info['payment_enable'] ) ) {
			return;
		}

		$plan = null;
		if ( $object instanceof IEntity ) {
			$application->Entity_Field_load( $object );
			if ( $plan_id = $object->getSingleFieldValue( 'payment_plan', 'plan_id' ) ) {
				if ( ! $component = $object->getSingleFieldValue( 'payment_plan', 'component' ) ) {
					$component = 'woocommerce'; // for compat with <v1.4.0
				}
				if ( $component !== $application->getComponent( 'Payment' )->getPaymentComponent( false, true ) ) {
					if ( ( $payment_component = $application->Payment_Components_impl( $component, true ) )
						&& $payment_component->paymentIsEnabled()
						&& ( $_plan = $payment_component->paymentGetPlanById( $object->getBundleName(), $plan_id ) )
					) {
						$plan = $_plan;
					}
				} elseif ( $_plan = $this->_getPlan( $application, $object->getBundleName(), $plan_id ) ) {
						$plan = $_plan;
				}
			}
		} else {
			if ( empty( $planId ) ) {
				throw new Exception\InvalidArgumentException( 'Plan ID or slug is required.' );
			}
			$method = is_numeric( $planId ) ? '_getPlan' : '_getPlanByName';
			if ( $_plan = $this->$method( $application, $bundle->name, $planId, $component ) ) {
				$plan = $_plan;
			}
		}

		return $plan;
	}

	protected function _getPlan( Application $application, $bundleName, $planId, $component = null ) {
		$plans = $application->Payment_Plans( $bundleName, null, false, false, $component );
		return isset( $plans[ $planId ] ) ? $plans[ $planId ] : false;
	}

	protected function _getPlanByName( Application $application, $bundleName, $planName, $component = null ) {
		$plans = $application->Payment_Plans( $bundleName, null, false, false, $component );
		foreach ( array_keys( $plans ) as $plan_id ) {
			if ( $plans[ $plan_id ]->paymentPlanName() === $planName ) {
				return $plans[ $plan_id ];
			}
		}
		return false;
	}

	public function features( Application $application, IPlan $plan, $sort = true ) {
		$features = (array) $plan->paymentPlanFeatures();
		if ( $plan->paymentPlanType() !== 'addon'
			&& ( $level = $plan->paymentPlanEntityLevel() )
			&& ( $payment_component = $application->Payment_Components_impl( $plan->paymentPlanComponent(), true ) )
			&& ( $content_bundle_name = $payment_component->paymentGetPlanContentBundleName( $plan ) )
		) {
			foreach ( $this->_getLevelFeatures( $application, $content_bundle_name, $level, $sort ) as $feature_name => $feature ) {
				$features[ $feature_name ] = $feature;
			}
		}

		return $features;
	}

	public function defaultFeatures( Application $application, $bundle, $getFromLevel = true, $sort = true ) {
		if ( $getFromLevel
			&& $application->Entity_BundleTypeInfo( $bundle, 'levelable' )
		) {
			return $this->_getLevelFeatures( $application, $bundle, 'default', $sort );
		}
		return empty( $bundle->info['payment_default_features']['features']['enabled'] ) ? array() : $bundle->info['payment_default_features']['features']['enabled'];
	}

	protected function _getLevelFeatures( Application $application, $bundle, $level, $sort = false ) {
		$features = $application->Entity_Levels_features( $bundle, $level );
		// Convert entity level features to payment features
		foreach ( array(
			'entity_fields'         => 'payment_fields',
			'entity_taxonomy_terms' => 'payment_taxonomy_terms',
		) as $feature_name => $replace ) {
			if ( isset( $features[ $feature_name ] ) ) {
				$features[ $replace ] = $features[ $feature_name ];
				unset( $features[ $feature_name ] );
			}
		}
		// Sort features by weight?
		if ( $sort ) {
			$_features = array();
			foreach ( array_keys( $application->Payment_Features() ) as $feature_name ) {
				if ( isset( $features[ $feature_name ] ) ) {
					$_features[ $feature_name ] = $features[ $feature_name ];
					unset( $features[ $feature_name ] );
				}
			}
			$features += $_features;
		}

		return $features;
	}

	public function isFree( Application $application, IPlan $plan ) {
		$price = $plan->paymentPlanPrice();
		return is_numeric( $price ) && (int) $price === 0;
	}

	public function formattedPrice( Application $application, IPlan $plan ) {
		return $application->getComponent( 'Payment' )->getPaymentComponent()->paymentFormatPlanPrice( $plan );
	}

	public function isCheckoutRequired( Application $application, IPlan $plan, $userId ) {
		if ( ! $this->isFree( $application, $plan ) ) {
			return true;
		}

		return empty( $userId ) && ! $application->getComponent( 'Payment' )->getPaymentComponent()->paymentIsGuestCheckoutEnabled();
	}
}
