<?php

namespace Vn;

require_once ('vn/hedera/init.php');
require_once ('vn/db/db.php');
require_once ('vn/tpv/soap-method.php');

use Vn\Lib\Log;

class Tpv
{
	static $conn;
	
	/**
	 * Initializes the class.
	 **/
	static function init ()
	{
		global $conf;

		openlog ('hedera-web', LOG_ODELAY, LOG_LOCAL0);

		self::$conn = new Db\Conn ();
		self::$conn->open (
			 $conf['db']['host']
			,$conf['db']['user']
			,base64_decode ($conf['db']['pass'])
			,$conf['db']['schema']
		);
	}

	/**
	 * Deinitializes the class.
	 **/
	static function deinit ()
	{
		self::$conn->close ();
		closelog ();
	}

	/**
	 * Gets transaction confirmations from the IMAP mailbox.
	 **/
	static function getFromMailbox ()
	{
		self::init ();

		$imap = NULL;

		if (self::$conn->isOpen ())
		{
			$imapConf = self::$conn->getRow (
				'SELECT host, user, pass, clean_period, success_folder, error_folder '
					.'FROM tpv_imap_config'
			);

			if ($imapConf)
			{
				$mailbox = sprintf ('{%s/imap/ssl/novalidate-cert}INBOX',
					$imapConf['host']);
	
				$imap = imap_open ($mailbox
					,$imapConf['user']
					,base64_decode ($imapConf['pass'])
				);
			}
		}

		if ($imap)
		{
			// Fetchs and confirms new transaction mails

			$inbox = imap_search ($imap, 'ALL');
	
			if ($inbox)
			foreach ($inbox as $msg)
			{
				// Decodes the mail body

				$params = [];
				$body = imap_fetchbody ($imap, $msg, '1');
				$strings = explode (';', $body);
		
				foreach ($strings as $string)
				{
					$x = explode (':', $string);
					$params[trim ($x[0])] = trim ($x[1]);
				}
		
				// Confirms the transaction

				$success = self::confirm ($params);
		
				// Moves the processed mail to another folder
	
				if ($success)
					$folder = $imapConf['success_folder'];
				else
					$folder = $imapConf['error_folder'];				
		
				$folder = sprintf ('INBOX.%s', $folder);

				if (!imap_mail_move ($imap, $msg, $folder))
					error_log ('TPV: IMAP: Can\'t move message to %s: %s'
						,$folder
						,imap_last_error ()
					);
			}
	
			if ($inbox && ($count = count ($inbox)) > 0)
				error_log ('TPV: %d mails processed.', $count);

			imap_expunge ($imap);
	
			// Cleans the old mails
	
			if (rand (1, 20) == 1)
			{
				$folders = array (
					 $imapConf['success_folder']
					,$imapConf['error_folder']
				);

				$deleted = 0;
				$date = new \DateTime (NULL);
				$date->sub (new \DateInterval ($imapConf['clean_period']));
				$filter = sprintf ('BEFORE "%s"', $date->format('D, j M Y'));

				foreach ($folders as $folder)
				if (imap_reopen ($imap, $mailbox.'.'.$folder))
				if ($messages = imap_search ($imap, $filter))
				{
					foreach ($messages as $message)
						imap_delete ($imap, $message);

					imap_expunge ($imap);
					$deleted += count ($messages);
				}
		
				error_log ('TPV: Cleaner: %d mails deleted.', $deleted);
			}

			imap_close ($imap);
		}
		else
			error_log ('TPV: IMAP: %s', imap_last_error ());

		self::deinit ();
	}

	/**
	 * Gets transaction confirmation from HTTP POST.
	 **/
	static function getFromPost ()
	{
		self::init ();

		if (self::$conn->isOpen ())
			self::confirm ($_POST);
			
		self::deinit ();
	}

	/**
	 * Gets transaction confirmation from SOAP service.
	 **/
	static function getFromSoap ()
	{
		ini_set ('soap.wsdl_cache_enabled', FALSE);

		$server = new \SoapServer (__DIR__ .'/soap.wsdl');
		$server->addFunction ('procesaNotificacionSIS');
		$server->handle ();
	}

	/**
	 * Tryes to confirm a transaction with the given params.
	 **/
	static function confirm ($params)
	{
		if (isset ($params['Ds_Amount'])
		&& isset ($params['Ds_Order'])
		&& isset ($params['Ds_MerchantCode'])
		&& isset ($params['Ds_Currency'])
		&& isset ($params['Ds_Response'])
		&& isset ($params['Ds_Signature']))
		{
			if (isset ($params['Ds_ErrorCode']))
				$error = $params['Ds_ErrorCode'];
			else
				$error = NULL;

			try {
				return self::$conn->query (
					'CALL transaction_confirm_with_check (#, #, #, #, #, #, #)',
					[
						 $params['Ds_Amount']
						,$params['Ds_Order']
						,$params['Ds_MerchantCode']
						,$params['Ds_Currency']
						,$params['Ds_Response']
						,$params['Ds_Signature']
						,$error
					]
				);
			}
			catch (\Exception $e)
			{
				error_log ("TPV: DB: %s", $e->getMessage ()); 
			}
		}
		
		return FALSE;
	}

	/**
	 * Tests the confirmation process. The corresponding record
	 * must exist in the `tpv_transaction` table.
	 **/
	static function test ($order)
	{
		self::init ();

		if (self::$conn->isOpen () && isset ($order))
			self::$conn->query ('CALL transaction_confirm_by_id (#)', [$order]);

		self::deinit ();
	}
}

?>