<?php
/**
 * @version            1.0
 * @package            Joom Donation
 * @subpackage         Payment Plugins
 * @author             Dang Thuc Dam
 * @copyright          Copyright (C) 2010 - 2018 Ossolution Team
 * @license            GNU/GPL, see LICENSE.php
 */
defined('_JEXEC') or die();

class os_stripe extends OSFPayment
{
	/**
	 * Constructors function
	 *
	 * @param \Joomla\Registry\Registry $params
	 * @param array                     $config
	 */
	public function __construct($params, $config = array('type' => 1))
	{
        require_once __DIR__ . '/stripe/init.php';

        $document  = JFactory::getDocument();
        $publicKey = $params->get('stripe_public_key');

        if ($params->get('use_stripe_card_element', 0))
        {
            $verison = DonationHelper::getInstalledVersion();

            if (version_compare($verison, '5.4.5', 'le'))
            {
                JFactory::getApplication()->enqueueMessage(JText::_('JD_STRIPE_CARD_ELEMENET_REQUIREMENT'), 'warning');
            }

            $document->addScript('https://js.stripe.com/v3/');
            $document->addScriptDeclaration(
                "   var stripe = Stripe('$publicKey');\n
					var elements = stripe.elements();\n
				"
            );

            $config['type'] = 0;
        }
        else
        {
            $document->addScript('https://js.stripe.com/v2/');
            $document->addScriptDeclaration(
                "   var stripePublicKey = '$publicKey';\n
					Stripe.setPublishableKey('$publicKey');\n
				"
            );
        }

        $this->stripeErrors = [
            'invalid_number'       => JText::_('JD_STRIPE_ERROR_INVALID_NUMBER'),
            'invalid_expiry_month' => JText::_('JD_STRIPE_ERROR_INVALID_EXPIRY_MONTH'),
            'invalid_expiry_year'  => JText::_('JD_STRIPE_ERROR_INVALID_EXPIRY_YEAR'),
            'invalid_cvc'          => JText::_('JD_STRIPE_ERROR_INVALID_EXPIRY_CVC'),
            'incorrect_number'     => JText::_('JD_STRIPE_ERROR_INVALID_NUMBER'),
            'expired_card'         => JText::_('JD_STRIPE_ERROR_EXPIRED_CARD'),
            'incorrect_cvc'        => JText::_('JD_STRIPE_ERROR_INCORRECT_CVC'),
            'incorrect_zip'        => JText::_('JD_STRIPE_ERROR_INCORRECT_ZIP'),
            'card_declined'        => JText::_('JD_STRIPE_ERROR_CARD_DECLINED'),
            'processing_error'     => JText::_('JD_STRIPE_ERROR_PROCESS_ERROR'),
        ];

        $document->addScriptDeclaration('var jdStripeErrors = ' . json_encode($this->stripeErrors) . ";\n");

        parent::__construct($params, $config);
	}

	/**
	 * Check to see whether this payment gateway support recurring payment
	 *
	 */
	public function getEnableRecurring()
	{
		return 1;
	}


	/**
	 * Process Payment
	 *
	 * @param $row
	 * @param $data
	 *
	 * @return bool
	 * @throws Exception
	 */
	public function processPayment($row, $data)
	{
		$db		= JFactory::getDbo();
		$app    = JFactory::getApplication();
		$Itemid = $app->input->getInt('Itemid', 0);
		\Stripe\Stripe::setApiKey($this->params->get('stripe_api_key'));
		
		if (!empty($data['stripeToken']))
		{
			$card = $data['stripeToken'];
		}
		else
		{
			$card = array(
				'number'    => $data['x_card_num'],
				'exp_month' => $data['exp_month'],
				'exp_year'  => $data['exp_year'],
				'cvc'       => $data['x_card_code'],
				'name'      => $data['card_holder_name']
			);
		}

		$metaData			= array();
		$metaData['Email']  = $row->email;
		$metaData['Name']	= $row->first_name. ' '. $row->last_name;

		$request = array(
			'amount'      => 100 * round($data['gateway_amount'], 2),
			'currency'    => $data['currency'],
			'description' => $data['item_name'],
			'card'        => $card,
			'metadata'	  => $metaData
		);
		try
		{
			$charge = \Stripe\Charge::create($request);
			$this->onPaymentSuccess($row, $charge->id);
			$app->redirect(JRoute::_('index.php?option=com_jdonation&view=complete&Itemid=' . $Itemid, false, false));
		}
		catch (Exception $e)
		{
			$session = JFactory::getSession();
			$session->set('omnipay_payment_error_reason', $e->getMessage());
			$app->redirect(JRoute::_('index.php?option=com_jdonation&view=failure&id=' . $row->id . '&Itemid=' . $Itemid, false, false));
		}
	}

	/**
	 * Process recurring subscription
	 *
	 * @param $row
	 * @param $data
	 *
	 * @return bool
	 * @throws Exception
	 */
	public function processRecurringPayment($row, $data)
	{
		$app    = JFactory::getApplication();
		$Itemid = $app->input->getInt('Itemid', 0);
		\Stripe\Stripe::setApiKey($this->params->get('stripe_api_key'));

		$db    = JFactory::getDbo();
		$query = $db->getQuery(true);
		$amount = round($data['gateway_amount'], 2);
	
		// Create the stripe plan if it doesn't exist
		$frequency    = $row->r_frequency;
		$length       = $row->r_times;
		switch ($row->r_frequency)
		{
			case 'd':
				$length    = 1;
				$unit      = 'day';
				$planTitle = JText::sprintf('JD_DAILY_DONATION', $amount);
				break;
			case 'w' :
				$length    = 1;
				$unit      = 'week';
				$planTitle = JText::sprintf('JD_WEEKLY_DONATION', $amount);
				break;
			case 'b' :
				$length    = 2;
				$unit      = 'week';
				$planTitle = JText::sprintf('JD_BI_WEEKLY_DONATION', $amount);
				break;
			case 'm' :
				$length    = 1;
				$unit      = 'month';
				$planTitle = JText::sprintf('JD_MONTHLY_DONATION', $amount);
				break;
			case 'q' :
				$length    = 3;
				$unit      = 'month';
				$planTitle = JText::sprintf('JD_QUARTERLY_DONATION', $amount);
				break;
			case 's' :
				$length    = 6;
				$unit      = 'month';
				$planTitle = JText::sprintf('JD_SEMI_ANNUALLY_DONATION', $amount);
				break;
			case 'a' :
				$length    = 1;
				$unit      = 'year';
				$planTitle = JText::sprintf('JD_ANNUALLY_DONATION', $amount);
				break;
			default:
				$length    = 1;
				$unit      = 'month';
				$planTitle = JText::sprintf('JD_MONTHLY_DONATION', $amount);
				break;
		}
		$stripePlanId = 'donation_' . $length.'_'.$unit.'_'.$amount.'_'.$row->id;

		$metaData			= array();
		$metaData['Email']  = $row->email;
		$metaData['Name']	= $row->first_name. ' '. $row->last_name;

		// Create a new stripe plan for account created before Feb 2018
		/*
		$request = array(
			'name'           => $planTitle,
			'id'             => $stripePlanId,
			'amount'         => 100 * $amount,
			'currency'       => $data['currency'],
			'interval'       => $unit,
			'interval_count' => $length
		);
		*/
		//For account created from Feb 2018
		
		$request = array(
			'product'		 => array(
				'name'           => $planTitle
			),
			'id'             => $stripePlanId,
			'amount'         => 100 * $amount,
			'currency'       => $data['currency'],
			'interval'       => $unit,
			'interval_count' => $length
		);
	

		try
		{
			\Stripe\Plan::create($request);
		}
		catch (Exception $e)
		{
			// Assure that the plan exists already
		}

		if (!empty($data['stripeToken']))
		{
			$card = $data['stripeToken'];
		}
		else
		{
			$card = array(
				'number'    => $data['x_card_num'],
				'exp_month' => $data['exp_month'],
				'exp_year'  => $data['exp_year'],
				'cvc'       => $data['x_card_code'],
				'name'      => $data['card_holder_name']
			);
		}

		// OK, plan is created, next we will need to subscribe customers to the plan
		try
		{
			$customer		= \Stripe\Customer::create(array(
				"description" => rtrim($row->first_name . ' ' . $row->last_name),
				"source"      => $card,
				"email"       => $row->email,
				"metadata"	  => $metaData
			));
		}
		catch (Exception $e)
		{
			$session = JFactory::getSession();
			$session->set('omnipay_payment_error_reason', $e->getMessage());
			$app->redirect(JRoute::_('index.php?option=com_jdonation&view=failure&id=' . $row->id . '&Itemid=' . $Itemid, false, false));
		}

		// Next, create subscription
		$request = array(
			'customer' => $customer->id,
			'metadata'	  => $metaData,
			'items'    => array(
				array(
					'plan' => $stripePlanId,
				)
			)
		);

		try
		{
			$subscription			= \Stripe\Subscription::create($request);
			$config					= DonationHelper::getConfig() ;
			$row->transaction_id	= $customer->id;
			$row->subscr_id			= $customer->subscriptions['data'][0]->id;
			$row->payment_date		= gmdate('Y-m-d H:i:s');
			$row->published			= 1;
			$row->payment_made		= $row->payment_made + 1;
			$row->store();

			$this->onPaymentSuccess($row, $customer->id);
			$app->redirect(JRoute::_('index.php?option=com_jdonation&view=complete&Itemid=' . $Itemid, false, false));
		}
		catch (Exception $e)
		{
			$session = JFactory::getSession();
			$session->set('omnipay_payment_error_reason', $e->getMessage());
			$app->redirect(JRoute::_('index.php?option=com_jdonation&view=failure&id=' . $row->id . '&Itemid=' . $Itemid, false, false));
		}
	}

	/**
	 *
	 * @param $row
	 *
	 * @return bool
	 * @throws Exception
	 */
	public function cancelSubscription($row)
	{
		\Stripe\Stripe::setApiKey($this->params->get('stripe_api_key'));
		try
		{
			$customer = \Stripe\Customer::retrieve($row->transaction_id);
			$customer->subscriptions->retrieve($row->transaction_id)->cancel();

			return true;
		}
		catch (Exception $e)
		{
			JFactory::getApplication()->enqueueMessage($e->getMessage(), 'error');

			return false;
		}
	}

	public function verifyRecurringPayment()
	{
		\Stripe\Stripe::setApiKey($this->params->get('stripe_api_key'));
		$body       = @file_get_contents('php://input');
		$event_json = json_decode($body);
		$event_id   = $event_json->id;
		try
		{
			$event = \Stripe\Event::retrieve($event_id);
		}
		catch (Exception $e)
		{
			$event = null;
		}

		if ($event && $event->type == 'charge.succeeded' && !empty($event->data->object->customer))
		{
			$customerId = $event->data->object->customer;
			//Check to see if there is customer object
			$db    = JFactory::getDbo();
			
			$query = $db->getQuery(true);
			$query->select('id')
				->from('#__jd_donors')
				->where('transaction_id = ' . $db->quote($customerId))
				->order('id');
			$db->setQuery($query, 0, 1);
			$donorId				= (int) $db->loadResult();
			
			if($donorId > 0){
				$this->logGatewayData($body . (string) $query . ' ' . $donorId);
				$row					= JTable::getInstance('jdonation', 'Table');
				$row->load($donorId);
				$row->payment_made		= $row->payment_made + 1;
				$row->store();

				//Create a new one time donation record and send emails when a recurring payment happens
				
				if ($row->payment_made > 1)
				{
					$row                = clone $row;
					$row->id            = 0;
					$row->donation_type = 'I';
					$row->created_date  = gmdate('Y-m-d H:i:s');
					$this->onPaymentSuccess($row, $customerId);
				}
			}
		}
	}
}