<?php
/**
* @package RSform!Pro
* @copyright (C) 2015 www.rsjoomla.com
* @license GPL, http://www.gnu.org/copyleft/gpl.html
*/

// no direct access
defined('_JEXEC') or die;

use Joomla\CMS\Language\Text;
use Joomla\CMS\Factory;
use Joomla\CMS\Uri\Uri;

class RSFPZohoCrm {

	protected $token;
	protected $host;
	public $debug;

	protected $config = array(
		'grant_token' => '',
		'client_id' => '',
		'client_secret' => '',
		'redirect_uri' => '',
		'apiBaseUrl' => '',
		'accounts_url' => '',
		'currentUserEmail' => '',
		'sandbox' => false
	);

	public $client_instance;

	public function __construct($args = array()) {

		if (!empty($args)) {

			$errors = array();
			foreach($args as $config => $value) {
				// clean the value a bit
				if (!is_bool($value)) {
					$value = trim($value);
				}

				// some mandatory checks
				switch($config) {
					case 'client_id':
					case 'client_secret':
					case 'currentUserEmail':
						if (empty($value)) {
							$errors[] = Text::sprintf('RSFP_ZOHOCRM_ERROR_CONFIG_VALUE', $config);
						}
					break;
				}

				if (isset($this->config[$config])) {
					$this->config[$config] = $value;
				}
			}

			if (!empty($errors)) {
				$error = implode('<br/>', $errors);
				throw new Exception(Text::_('RSFP_ZOHOCRM_ERROR_CONFIG').'<br/>'.$error);
			}
		}

		// some default values
		if (empty($this->config['apiBaseUrl'])) {
			$this->config['apiBaseUrl'] = 'zoho.com';
		}

		// actual values for the apiBaseUrl and accounts_url

		switch ($this->config['apiBaseUrl'])
		{
			default:
				$this->config['apiBaseUrl'] 	= 'https://www.zohoapis.com';
				$this->config['accounts_url'] 	= 'https://accounts.zoho.com';
				break;

			case 'zoho.in':
				$this->config['apiBaseUrl'] 	= 'https://www.zohoapis.in';
				$this->config['accounts_url'] 	= 'https://accounts.zoho.in';
				break;

			case 'zoho.eu':
				$this->config['apiBaseUrl'] 	= 'https://www.zohoapis.eu';
				$this->config['accounts_url'] 	= 'https://accounts.zoho.eu';
			break;

			case 'zoho.com.au':
				$this->config['apiBaseUrl'] 	= 'https://www.zohoapis.com.au';
				$this->config['accounts_url'] 	= 'https://accounts.zoho.com.au';
			break;

			case 'zoho.com.cn':
				$this->config['apiBaseUrl'] 	= 'https://www.zohoapis.com.cn';
				$this->config['accounts_url'] 	= 'https://accounts.zoho.com.cn';
				break;

			case 'zoho.sa':
				$this->config['apiBaseUrl'] 	= 'https://www.zohoapis.sa';
				$this->config['accounts_url'] 	= 'https://accounts.zoho.sa';
				break;

			case 'zoho.uk':
				$this->config['apiBaseUrl'] 	= 'https://www.zohoapis.uk';
				$this->config['accounts_url'] 	= 'https://accounts.zoho.uk';
				break;

			case 'zoho.jp':
				$this->config['apiBaseUrl'] 	= 'https://www.zohoapis.jp';
				$this->config['accounts_url'] 	= 'https://accounts.zoho.jp';
				break;

			case 'zohocloud.ca':
				$this->config['apiBaseUrl'] 	= 'https://www.zohoapis.ca';
				$this->config['accounts_url'] 	= 'https://accounts.zohocloud.ca';
				break;
		}

		// need to build the redirect uri that will be displayed in the configuration area and copied in the accounts.zoho.com/developerconsole
		$this->config['redirect_uri'] = urlencode(Uri::root().'administrator/index.php?option=com_rsform&task=plugin&plugin_task=zoho_auth');

		// load the file for the Zohocrm rest client
		require_once JPATH_ADMINISTRATOR . '/components/com_rsform/helpers/zohocrm/crm/library/setup/restclient/ZCRMRestClient.php';

	}

	public function get_current_access_token($userEmail = null, $clientid = null) {
		if (is_null($userEmail)) {
			$userEmail = $this->config['currentUserEmail'];
		}

		if (is_null($clientid)) {
			$clientid = $this->config['client_id'];
		}

		$db 	= Factory::getDbo();
		$query 	= $db->getQuery(true);

		$query->select($db->qn('accesstoken'))
			->select($db->qn('expirytime'))
			->select($db->qn('refreshtoken'))
			->select($db->qn('clientid'))
			->from($db->qn('#__rsform_zohocrm_oauthtokens'))
			->where($db->qn('useridentifier').'='.$db->q($userEmail))
			->where($db->qn('clientid').'='.$db->q($clientid));

		$db->setQuery($query);

		return $db->loadObject();
	}

	public function check_if_auth_token_exist() {
		$access_token = $this->get_current_access_token();
		if (is_null($access_token) || empty($access_token->accesstoken)) {
			throw new Exception(Text::_('RSFP_ZOHOCRM_ERROR_NO_ACCESS_TOKEN_GENERATED'));
		}

		// if there is no refresh token and the current access token is expired need to alert so that a new one be generated
		if (empty($access_token->refreshtoken)) {
			$expiry = (float) $access_token->expirytime;

			// The current time must be based on the microtime because the SDK stores it this way
			$now = round(microtime(true)*1000);

			if ($expiry < $now) {
				throw new Exception(Text::_('RSFP_ZOHOCRM_ERROR_NO_ACCESS_TOKEN'));
			}
		}
	}

	public function get_redirect_uri() {
		return $this->config['redirect_uri'];
	}

	public function get_and_store_access_token() {
		ZCRMRestClient::initialize($this->config);
		$oAuthClient = ZohoOAuth::getClientInstance();

		// Avoiding requesting an access token without a refresh token we need to get it from the refresh token
		if ($current_token = $this->get_current_access_token()) {
			if (!empty($current_token->refreshtoken)) {
				$oAuthTokens = $oAuthClient->generateAccessTokenFromRefreshToken($current_token->refreshtoken, $this->config['currentUserEmail']);
				return $oAuthTokens;
			}
		}

		$oAuthTokens = $oAuthClient->generateAccessToken($this->config['grant_token']);

		return $oAuthTokens;
	}

	
	public function getFields() {
		$fields = array();

		$instance  = ZCRMRestClient::getInstance();
		$instance::initialize($this->config);

		$layouts = $instance->getModule('Leads')->getData()->getAllLayouts();
		$layouts = $layouts->getData();

		if (empty($layouts))
		{
			throw new Exception(Text::_('RSFP_ZOHOCRM_ERROR_NO_LEADS_LAYOUTS'));
		}

		foreach ($layouts as $layout) {
			if (!$layout->isVisible()) {
				continue;
			}
			$sections = $layout->getSections();

			if (empty($sections)) {
				throw new Exception(Text::_('RSFP_ZOHOCRM_ERROR_NO_LEADS_SECTIONS'));
			}
			$layout_id = $layout->getId();

			// initiate the fields for this specific layout
			$fields[$layout_id] = array(
				'layout_name' => $layout->getName(),
				'sections' => array()
			);
			
			// attachment field to map
			$attachment_field = (object) array(
				'dv' => 'file_attachment',
				'customfield' => '',
				'maxlength' => '',
				'isreadonly' => false,
				'label' => 'File Attachment',
				'type' => 'file_attachment',
				'req' => false,
			);
			
			// attachment link to map
			$attachment_link_field = (object) array(
				'dv' => 'link_attachment',
				'customfield' => '',
				'maxlength' => '',
				'isreadonly' => false,
				'label' => 'Link Attachment',
				'type' => 'link_attachment',
				'req' => false,
			);
			
			// attachment section
			$fields[$layout_id]['sections']['Attachments'] = array($attachment_field, $attachment_link_field);

			foreach ($sections as $section) {
				$section_name = $section->getName();
				$section_fields = $section->getFields();

				// if there are no fields then no need for adding the empty section
				if (empty($section_fields)) {
					continue;
				}

				$fields[$layout_id]['sections'][$section_name] = array();

				foreach ($section_fields as $field) {
					$field_type = $field->getDataType();

					$compat_field = array(
						'dv' => $field->getApiName(),
						'customfield' => $field->isCustomField(),
						'maxlength' => $field->getLength(),
						'isreadonly' => $field->isReadOnly(),
						'label' => $field->getFieldLabel(),
						'type' => $field_type,
						'req' => $field->isMandatory(),
					);

					if ($values = $field->getPickListFieldValues()) {
						$compat_field['val'] = array();

						foreach($values as $val) {
							$compat_field['val'][$val->getDisplayValue()] = $val->getActualValue();
						}
					}

					$fields[$layout_id]['sections'][$section_name][] = (object) $compat_field;
				}
			}
		}

		return $fields;
	}
	
	public function addLead($data) {
		$instance  = ZCRMRestClient::getInstance();
		$instance::initialize($this->config);

		if (!empty($data['data'])) {
			$attachments_fields = array(
				'record_image' => !empty($data['record_image']) ? $data['record_image'] : false, 
				'file_attachment' => !empty($data['file_attachment']) ? $data['file_attachment'] : false, 
				'link_attachment' => !empty($data['link_attachment']) ? $data['link_attachment'] : false
			);
			
			// remove the image/attachment and link attachment
			$to_unset = array_keys($attachments_fields);
			foreach ($to_unset as $unset_field)
			{
				if (isset($data[$unset_field]))
				{
					unset($data[$unset_field]);
				}
			}
			

			$record = ZCRMRecord::getInstance("Leads", null);

			foreach ($data['data'] as $recordData) {
				foreach ($recordData as $field => $value) {
					$record->setFieldValue($field, $value);
				}
			}

			// add the layout if present
			if (isset($data['layout_id'])) {
				$record->setLayout(ZCRMLayout::getInstance($data['layout_id']));
			}
			
			$duplicate_check = isset($data['duplicate_check']) && $data['duplicate_check'];
			
			// module
			$leads_module = ZCRMModule::getInstance("Leads");
			if ($duplicate_check) {
				$api_response = $leads_module->upsertRecords(array($record), $data['trigger'], $data['lar_id']);
			} else {
				$api_response = $leads_module->createRecords(array($record), $data['trigger'], $data['lar_id']);
			}

			// The response
			$entity_response = $api_response->getEntityResponses();
			// Should be just one
			$entity_response = $entity_response[0];
						
			$status = $entity_response->getStatus();
			
			// try to upload the lead photo
			if ($status == 'success')
			{
				$lead_record = $entity_response->getData();
				
				foreach ($attachments_fields as $att_field_name => $att_field_value)
				{
					if ($att_field_value !== false)
					{
						switch($att_field_name)
						{
							case 'record_image':
								$lead_record->uploadPhoto($att_field_value);
							break;
							
							case 'file_attachment':
								$files = RSFormProHelper::explode($att_field_value);
								if ($files) {
									foreach ($files as $file)
									{
										$lead_record->uploadAttachment($file);
									}
								}
							break;
							
							case 'link_attachment':
								foreach($att_field_value as $link)
								{
									$lead_record->uploadLinkAsAttachment($link);
								}
							break;
						}
					}
				}
			}

			if ($this->debug) {
				$message_append = array();
				if ($details = $entity_response->getDetails()) {
					if ($status == 'error') {
						foreach($details as $type => $value) {
							$type = ($type == 'expected_data_type' ? str_replace('_', ' ', $type) : '');
							$type = ucfirst($type);

							$value = str_replace('_', ' ', $value);
							$message_append[] = (!empty($type) ? $type.': ': '').$value;
						}

						if (!empty($message_append)) {
							$message_append = implode(', ', $message_append);
						}
					}
				}
				Factory::getApplication()->enqueueMessage(
					Text::sprintf('RSFP_ZOHOCRM_DEBUG_RESPONSE', $status, $entity_response->getCode(), $entity_response->getMessage().(!empty($message_append) ? '<br/>'.$message_append : '')),
					($status != 'success' ? 'warning' : 'success')
				);
			}

		}
	}

}