<?php

/**
 * ZohoProjects Integration
 *
 */

namespace BitCode\BitFormPro\Integration\ZohoProjects;

use BitCode\BitForm\Core\Util\IpTool;
use BitCode\BitForm\Core\Util\HttpHelper;
use BitCode\BitForm\Core\Integration\IntegrationHandler;
use BitCode\BitFormPro\Integration\ZohoProjects\RecordApiHelper;

/**
 * Provide functionality for ZohoCrm integration
 */
class ZohoProjectsHandler
{
	private $_formID;
	private $_integrationID;

	public function __construct($integrationID, $formID)
	{
		$this->_formID = $formID;
		$this->_integrationID = $integrationID;
	}

	/**
	 * Helps to register ajax function's with wp
	 *
	 * @return null
	 */
	public static function registerAjax()
	{
		add_action('wp_ajax_bitforms_zprojects_generate_token', array(__CLASS__, 'generateTokens'));
		add_action('wp_ajax_bitforms_zprojects_refresh_portals', array(__CLASS__, 'refreshPortalsAjaxHelper'));
		add_action('wp_ajax_bitforms_zprojects_refresh_projects', array(__CLASS__, 'refreshProjectsAjaxHelper'));
		add_action('wp_ajax_bitforms_zprojects_refresh_milestones', array(__CLASS__, 'refreshMilestonesAjaxHelper'));
		add_action('wp_ajax_bitforms_zprojects_refresh_tasklists', array(__CLASS__, 'refreshTasklistsAjaxHelper'));
		add_action('wp_ajax_bitforms_zprojects_refresh_tasks', array(__CLASS__, 'refreshTasksAjaxHelper'));
		add_action('wp_ajax_bitforms_zprojects_refresh_fields', array(__CLASS__, 'refreshFieldsAjaxHelper'));
		add_action('wp_ajax_bitforms_zprojects_refresh_users', array(__CLASS__, 'refreshUsersAjaxHelper'));
		add_action('wp_ajax_bitforms_zprojects_refresh_task_layouts', array(__CLASS__, 'refreshTaskLaysAjaxHelper'));
		add_action('wp_ajax_bitforms_zprojects_refresh_groups', array(__CLASS__, 'refreshGroupsAjaxHelper'));
		add_action('wp_ajax_bitforms_zprojects_refresh_tags', array(__CLASS__, 'refreshTagsAjaxHelper'));
	}

	/**
	 * Process ajax request for generate_token
	 *
	 * @return JSON zoho crm api response and status
	 */
	public static function generateTokens()
	{
		if (isset($_REQUEST['_ajax_nonce']) && wp_verify_nonce($_REQUEST['_ajax_nonce'], 'bitforms_save')) {
			$inputJSON = file_get_contents('php://input');
			$requestsParams = json_decode($inputJSON);
			if (
				empty($requestsParams->{'accounts-server'})
				|| empty($requestsParams->dataCenter)
				|| empty($requestsParams->clientId)
				|| empty($requestsParams->clientSecret)
				|| empty($requestsParams->redirectURI)
				|| empty($requestsParams->code)
			) {
				wp_send_json_error(
					__(
						'Requested parameter is empty',
						'bitformpro'
					),
					400
				);
			}

			$apiEndpoint = \urldecode($requestsParams->{'accounts-server'}) . '/oauth/v2/token';
			$requestParams = array(
				"grant_type" => "authorization_code",
				"client_id" => $requestsParams->clientId,
				"client_secret" => $requestsParams->clientSecret,
				"redirect_uri" => \urldecode($requestsParams->redirectURI),
				"code" => $requestsParams->code
			);
			$apiResponse = HttpHelper::post($apiEndpoint, $requestParams);

			if (is_wp_error($apiResponse) || !empty($apiResponse->error)) {
				wp_send_json_error(
					empty($apiResponse->error) ? 'Unknown' : $apiResponse->error,
					400
				);
			}
			$apiResponse->generates_on = \time();
			wp_send_json_success($apiResponse, 200);
		} else {
			wp_send_json_error(
				__(
					'Token expired',
					'bitformpro'
				),
				401
			);
		}
	}
	public static function refreshPortalsAjaxHelper()
	{
		$authorizationHeader = null;
		if (isset($_REQUEST['_ajax_nonce']) && wp_verify_nonce($_REQUEST['_ajax_nonce'], 'bitforms_save')) {
			$inputJSON = file_get_contents('php://input');
			$queryParams = json_decode($inputJSON);
			if (
				empty($queryParams->tokenDetails)
				|| empty($queryParams->dataCenter)
				|| empty($queryParams->clientId)
				|| empty($queryParams->clientSecret)
			) {
				wp_send_json_error(
					__(
						'Requested parameter is empty',
						'bitformpro'
					),
					400
				);
			}
			$response = [];
			if ((intval($queryParams->tokenDetails->generates_on) + (55 * 60)) < time()) {
				$response['tokenDetails'] = ZohoProjectsHandler::_refreshAccessToken($queryParams);
			}

			$portalsMetaApiEndpoint = "https://projectsapi.zoho.{$queryParams->dataCenter}/restapi/portals/";

			$authorizationHeader["Authorization"] = "Zoho-oauthtoken {$queryParams->tokenDetails->access_token}";
			$portalsMetaResponse = HttpHelper::get($portalsMetaApiEndpoint, null, $authorizationHeader);

			if (!is_wp_error($portalsMetaResponse)) {
				$allPortals = [];
				$portals = $portalsMetaResponse->portals;

				if (count($portals) > 0) {
					foreach ($portals as $portal) {
						$allPortals[$portal->name] = (object) array(
							'portalId' => $portal->id,
							'portalName' => $portal->name
						);
					}
				}
				uksort($allPortals, 'strnatcasecmp');
				$response['portals'] = $allPortals;
			} else {
				wp_send_json_error(
					empty($portalsMetaResponse->data) ? 'Unknown' : $portalsMetaResponse->error,
					400
				);
			}
			if (!empty($response['tokenDetails']) && !empty($queryParams->id)) {
				ZohoProjectsHandler::_saveRefreshedToken($queryParams->formID, $queryParams->id, $response['tokenDetails'], $response['lists']);
			}
			wp_send_json_success($response, 200);
		} else {
			wp_send_json_error(
				__(
					'Token expired',
					'bitformpro'
				),
				401
			);
		}
	}

	public static function refreshProjectsAjaxHelper()
	{
		$authorizationHeader = null;
		if (isset($_REQUEST['_ajax_nonce']) && wp_verify_nonce($_REQUEST['_ajax_nonce'], 'bitforms_save')) {
			$inputJSON = file_get_contents('php://input');
			$queryParams = json_decode($inputJSON);
			if (
				empty($queryParams->tokenDetails)
				|| empty($queryParams->dataCenter)
				|| empty($queryParams->clientId)
				|| empty($queryParams->clientSecret)
				|| empty($queryParams->portalId)
			) {
				wp_send_json_error(
					__(
						'Requested parameter is empty',
						'bitformpro'
					),
					400
				);
			}
			$response = [];
			if ((intval($queryParams->tokenDetails->generates_on) + (55 * 60)) < time()) {
				$response['tokenDetails'] = ZohoProjectsHandler::_refreshAccessToken($queryParams);
			}

			$projectsMetaApiEndpoint = "https://projectsapi.zoho.{$queryParams->dataCenter}/restapi/portal/{$queryParams->portalId}/projects/?range=1000&status=active";

			$authorizationHeader["Authorization"] = "Zoho-oauthtoken {$queryParams->tokenDetails->access_token}";
			$projectsMetaResponse = HttpHelper::get($projectsMetaApiEndpoint, null, $authorizationHeader);

			// wp_send_json_success($projectsMetaResponse, 200);

			if (!is_wp_error($projectsMetaResponse)) {
				$allProjects = [];
				$projects = $projectsMetaResponse->projects;

				if (count($projects) > 0) {
					foreach ($projects as $project) {
						$allProjects[$project->name] = (object) array(
							'projectId' => $project->id_string,
							'projectName' => $project->name
						);
					}
				}
				uksort($allProjects, 'strnatcasecmp');
				$response['projects'] = $allProjects;
			} else {
				wp_send_json_error(
					empty($projectsMetaResponse->data) ? 'Unknown' : $projectsMetaResponse->error,
					400
				);
			}
			if (!empty($response['tokenDetails']) && !empty($queryParams->id)) {
				ZohoProjectsHandler::_saveRefreshedToken($queryParams->formID, $queryParams->id, $response['tokenDetails'], $response['lists']);
			}
			wp_send_json_success($response, 200);
		} else {
			wp_send_json_error(
				__(
					'Token expired',
					'bitformpro'
				),
				401
			);
		}
	}

	public static function refreshMilestonesAjaxHelper()
	{
		$authorizationHeader = null;
		if (isset($_REQUEST['_ajax_nonce']) && wp_verify_nonce($_REQUEST['_ajax_nonce'], 'bitforms_save')) {
			$inputJSON = file_get_contents('php://input');
			$queryParams = json_decode($inputJSON);
			if (
				empty($queryParams->tokenDetails)
				|| empty($queryParams->dataCenter)
				|| empty($queryParams->clientId)
				|| empty($queryParams->clientSecret)
				|| empty($queryParams->portalId)
				|| empty($queryParams->projectId)
			) {
				wp_send_json_error(
					__(
						'Requested parameter is empty',
						'bitformpro'
					),
					400
				);
			}
			$response = [];
			if ((intval($queryParams->tokenDetails->generates_on) + (55 * 60)) < time()) {
				$response['tokenDetails'] = ZohoProjectsHandler::_refreshAccessToken($queryParams);
			}

			$milestonesMetaApiEndpoint = "https://projectsapi.zoho.{$queryParams->dataCenter}/restapi/portal/{$queryParams->portalId}/projects/{$queryParams->projectId}/milestones/?range=1000";

			$authorizationHeader["Authorization"] = "Zoho-oauthtoken {$queryParams->tokenDetails->access_token}";
			$milestonesMetaResponse = HttpHelper::get($milestonesMetaApiEndpoint, null, $authorizationHeader);

			if (!is_wp_error($milestonesMetaResponse)) {
				$allMilestones = [];
				$milestones = $milestonesMetaResponse->milestones;

				if (count($milestones) > 0) {
					foreach ($milestones as $milestone) {
						$allMilestones[$milestone->name] = (object) array(
							'milestoneId' => $milestone->id_string,
							'milestoneName' => $milestone->name
						);
					}
				}
				uksort($allMilestones, 'strnatcasecmp');
				$response['milestones'] = $allMilestones;
			} else {
				wp_send_json_error(
					empty($milestonesMetaResponse->data) ? 'Unknown' : $milestonesMetaResponse->error,
					400
				);
			}
			if (!empty($response['tokenDetails']) && !empty($queryParams->id)) {
				ZohoProjectsHandler::_saveRefreshedToken($queryParams->formID, $queryParams->id, $response['tokenDetails'], $response['lists']);
			}
			wp_send_json_success($response, 200);
		} else {
			wp_send_json_error(
				__(
					'Token expired',
					'bitformpro'
				),
				401
			);
		}
	}

	public static function refreshTasklistsAjaxHelper()
	{
		$authorizationHeader = null;
		if (isset($_REQUEST['_ajax_nonce']) && wp_verify_nonce($_REQUEST['_ajax_nonce'], 'bitforms_save')) {
			$inputJSON = file_get_contents('php://input');
			$queryParams = json_decode($inputJSON);
			if (
				empty($queryParams->tokenDetails)
				|| empty($queryParams->dataCenter)
				|| empty($queryParams->clientId)
				|| empty($queryParams->clientSecret)
				|| empty($queryParams->portalId)
				|| empty($queryParams->projectId)
				|| empty($queryParams->tasklistFlag)
			) {
				wp_send_json_error(
					__(
						'Requested parameter is empty',
						'bitformpro'
					),
					400
				);
			}
			$response = [];
			if ((intval($queryParams->tokenDetails->generates_on) + (55 * 60)) < time()) {
				$response['tokenDetails'] = ZohoProjectsHandler::_refreshAccessToken($queryParams);
			}

			$tasklistsMetaApiEndpoint = "https://projectsapi.zoho.{$queryParams->dataCenter}/restapi/portal/{$queryParams->portalId}/projects/{$queryParams->projectId}/tasklists/?range=1000&flag={$queryParams->tasklistFlag}";

			if ($queryParams->milestoneId)
				$tasklistsMetaApiEndpoint .= "&milestone_id={$queryParams->milestoneId}";

			$authorizationHeader["Authorization"] = "Zoho-oauthtoken {$queryParams->tokenDetails->access_token}";
			$tasklistsMetaResponse = HttpHelper::get($tasklistsMetaApiEndpoint, null, $authorizationHeader);

			if (!is_wp_error($tasklistsMetaResponse)) {
				$allTasklists = [];
				$tasklists = $tasklistsMetaResponse->tasklists;

				if (count($tasklists) > 0) {
					foreach ($tasklists as $tasklist) {
						$allTasklists[$tasklist->name] = (object) array(
							'tasklistId' => $tasklist->id_string,
							'tasklistName' => $tasklist->name
						);
					}
				}
				uksort($allTasklists, 'strnatcasecmp');
				$response['tasklists'] = $allTasklists;
			} else {
				wp_send_json_error(
					empty($tasklistsMetaResponse->data) ? 'Unknown' : $tasklistsMetaResponse->error,
					400
				);
			}
			if (!empty($response['tokenDetails']) && !empty($queryParams->id)) {
				ZohoProjectsHandler::_saveRefreshedToken($queryParams->formID, $queryParams->id, $response['tokenDetails'], $response['lists']);
			}
			wp_send_json_success($response, 200);
		} else {
			wp_send_json_error(
				__(
					'Token expired',
					'bitformpro'
				),
				401
			);
		}
	}

	public static function refreshTasksAjaxHelper()
	{
		$authorizationHeader = null;
		if (isset($_REQUEST['_ajax_nonce']) && wp_verify_nonce($_REQUEST['_ajax_nonce'], 'bitforms_save')) {
			$inputJSON = file_get_contents('php://input');
			$queryParams = json_decode($inputJSON);
			if (
				empty($queryParams->tokenDetails)
				|| empty($queryParams->dataCenter)
				|| empty($queryParams->clientId)
				|| empty($queryParams->clientSecret)
				|| empty($queryParams->portalId)
				|| empty($queryParams->projectId)
			) {
				wp_send_json_error(
					__(
						'Requested parameter is empty',
						'bitformpro'
					),
					400
				);
			}
			$response = [];
			if ((intval($queryParams->tokenDetails->generates_on) + (55 * 60)) < time()) {
				$response['tokenDetails'] = ZohoProjectsHandler::_refreshAccessToken($queryParams);
			}

			$tasksMetaApiEndpoint = "https://projectsapi.zoho.{$queryParams->dataCenter}/restapi/portal/{$queryParams->portalId}/projects/{$queryParams->projectId}/tasks/?range=1000";

			if ($queryParams->milestoneId)
				$tasksMetaApiEndpoint .= "&milestone_id={$queryParams->milestoneId}";
			if ($queryParams->tasklistId)
				$tasksMetaApiEndpoint .= "&tasklist_id={$queryParams->tasklistId}";

			$authorizationHeader["Authorization"] = "Zoho-oauthtoken {$queryParams->tokenDetails->access_token}";
			$tasksMetaResponse = HttpHelper::get($tasksMetaApiEndpoint, null, $authorizationHeader);

			if (!is_wp_error($tasksMetaResponse)) {
				$allTasks = [];
				$tasks = $tasksMetaResponse->tasks;

				if (count($tasks) > 0) {
					foreach ($tasks as $task) {
						$allTasks[$task->name] = (object) array(
							'taskId' => $task->id_string,
							'taskName' => $task->name
						);
					}
				}
				uksort($allTasks, 'strnatcasecmp');
				$response['tasks'] = $allTasks;
			} else {
				wp_send_json_error(
					empty($tasksMetaResponse->data) ? 'Unknown' : $tasksMetaResponse->error,
					400
				);
			}
			if (!empty($response['tokenDetails']) && !empty($queryParams->id)) {
				ZohoProjectsHandler::_saveRefreshedToken($queryParams->formID, $queryParams->id, $response['tokenDetails'], $response['lists']);
			}
			wp_send_json_success($response, 200);
		} else {
			wp_send_json_error(
				__(
					'Token expired',
					'bitformpro'
				),
				401
			);
		}
	}

	public static function refreshFieldsAjaxHelper()
	{
		if (isset($_REQUEST['_ajax_nonce']) && wp_verify_nonce($_REQUEST['_ajax_nonce'], 'bitforms_save')) {
			$inputJSON = file_get_contents('php://input');
			$queryParams = json_decode($inputJSON);
			if (
				empty($queryParams->tokenDetails)
				|| empty($queryParams->dataCenter)
				|| empty($queryParams->clientId)
				|| empty($queryParams->clientSecret)
				|| empty($queryParams->portalId)
				|| empty($queryParams->event)
			) {
				wp_send_json_error(
					__(
						'Requested parameter is empty',
						'bitformpro'
					),
					400
				);
			}
			$response = [];
			if ((intval($queryParams->tokenDetails->generates_on) + (55 * 60)) < time()) {
				$response['tokenDetails'] = ZohoProjectsHandler::_refreshAccessToken($queryParams);
			}

			if ($queryParams->event === 'project') {
				$response = ZohoProjectsHandler::getProjectFields($queryParams->dataCenter, $queryParams->portalId, $queryParams->tokenDetails->access_token);
			} else if ($queryParams->event === 'milestone') {
				$response = ZohoProjectsHandler::getMilestoneFields();
			} else if ($queryParams->event === 'tasklist') {
				$response = ZohoProjectsHandler::getTasklistFields();
			} else if ($queryParams->event === 'task' || $queryParams->event === 'subtask') {
				$response = ZohoProjectsHandler::getTaskFields($queryParams->dataCenter, $queryParams->portalId, $queryParams->tokenDetails->access_token, $queryParams->projectId);
			} else if ($queryParams->event === 'issue') {
				$response = ZohoProjectsHandler::getIssueFields($queryParams->dataCenter, $queryParams->portalId, $queryParams->tokenDetails->access_token, $queryParams->projectId);
			}

			if (!empty($response['tokenDetails']) && $response['tokenDetails'] && !empty($queryParams->id)) {
				$response["queryModule"] = $queryParams->module;
				ZohoProjectsHandler::_saveRefreshedToken($queryParams->formID, $queryParams->id, $response['tokenDetails'], $response);
			}
			wp_send_json_success($response, 200);
		} else {
			wp_send_json_error(
				__(
					'Token expired',
					'bitformpro'
				),
				401
			);
		}
	}

	protected static function getProjectFields($dataCenter, $portalId, $access_token)
	{
		$allFields = [
			'Project Title' => [
				'apiName' => 'name',
				'displayLabel' => 'Project Title',
				'required' => true
			],
			'Project Overview' => [
				'apiName' => 'description',
				'displayLabel' => 'Project Overview'
			],
			'Start Date' => [
				'apiName' => 'start_date',
				'displayLabel' => 'Start Date'
			],
			'End Date' => [
				'apiName' => 'end_date',
				'displayLabel' => 'End Date'
			],
			'Strict Project' => [
				'apiName' => 'strict_project',
				'displayLabel' => 'Strict Project'
			],
			'Project Budget' => [
				'apiName' => 'budget_type',
				'displayLabel' => 'Project Budget'
			],
			'Budget Amount' => [
				'apiName' => 'budget_value',
				'displayLabel' => 'Budget Amount'
			],
			'Billing Method' => [
				'apiName' => 'billing_method',
				'displayLabel' => 'Billing Method'
			],
			'Currency' => [
				'apiName' => 'currency',
				'displayLabel' => 'Currency'
			],
			'Threshold Limit' => [
				'apiName' => 'threshold',
				'displayLabel' => 'Threshold Limit'
			],
			'Rate Per Hour' => [
				'apiName' => 'project_rate',
				'displayLabel' => 'Rate Per Hour'
			],
			'Fixed Cost' => [
				'apiName' => 'fixed_cost',
				'displayLabel' => 'Fixed Cost'
			],
			'Bill Status' => [
				'apiName' => 'bill_status',
				'displayLabel' => 'Bill Status'
			]
		];

		$response['required'][] = 'name';

		$customFieldsMetaApiEndpoint = "https://projectsapi.zoho.{$dataCenter}/restapi/portal/{$portalId}/projects/customfields/";
		$authorizationHeader["Authorization"] = "Zoho-oauthtoken {$access_token}";
		$customFieldsMetaResponse = HttpHelper::get($customFieldsMetaApiEndpoint, null, $authorizationHeader);

		if (!is_wp_error($customFieldsMetaResponse)) {
			$fields = $customFieldsMetaResponse->project_custom_fields;

			if (count($fields) > 0) {
				foreach ($fields as $field) {
					$allFields[$field->field_name] = (object) array(
						'apiName' => $field->field_id,
						'displayLabel' => $field->field_name
					);

					if ($field->is_mandatory) $response['required'][] = $field->field_id;
				}
			}
		}

		$response['fields'] = $allFields;
		uksort($response['fields'], 'strnatcasecmp');
		usort($response['required'], 'strnatcasecmp');

		return $response;
	}

	protected static function getMilestoneFields()
	{
		$allFields = [
			'Milestone Title' => [
				'apiName' => 'name',
				'displayLabel' => 'Milestone Title',
				'required' => true
			],
			'Start Date' => [
				'apiName' => 'start_date',
				'displayLabel' => 'Start Date',
				'required' => true
			],
			'End Date' => [
				'apiName' => 'end_date',
				'displayLabel' => 'End Date',
				'required' => true
			]
		];

		$response['required'] = ['name', 'start_date', 'end_date'];

		$response['fields'] = $allFields;
		uksort($response['fields'], 'strnatcasecmp');
		usort($response['required'], 'strnatcasecmp');

		return $response;
	}

	protected static function getTasklistFields()
	{
		$allFields = [
			'Tasklist Title' => [
				'apiName' => 'name',
				'displayLabel' => 'Tasklist Title',
				'required' => true
			]
		];

		$response['required'] = ['name'];

		$response['fields'] = $allFields;
		uksort($response['fields'], 'strnatcasecmp');
		usort($response['required'], 'strnatcasecmp');

		return $response;
	}

	protected static function getTaskFields($dataCenter, $portalId, $access_token, $projectId)
	{
		$allFields = [
			'Task Title' => [
				'apiName' => 'name',
				'displayLabel' => 'Task Title',
				'required' => true
			],
			'Task Description' => [
				'apiName' => 'description',
				'displayLabel' => 'Task Description'
			],
			'Start Date' => [
				'apiName' => 'start_date',
				'displayLabel' => 'Start Date'
			],
			'End Date' => [
				'apiName' => 'end_date',
				'displayLabel' => 'End Date'
			],
			'Duration' => [
				'apiName' => 'duration',
				'displayLabel' => 'Duration'
			],
			'Duration Type' => [
				'apiName' => 'duration_type',
				'displayLabel' => 'Duration Type'
			],
			'Start Time' => [
				'apiName' => 'start_time',
				'displayLabel' => 'Start Time'
			],
			'End Time' => [
				'apiName' => 'end_time',
				'displayLabel' => 'End Time'
			],
			'Rate Per Hour' => [
				'apiName' => 'rate_per_hour',
				'displayLabel' => 'Rate Per Hour'
			],
			'Priority' => [
				'apiName' => 'priority',
				'displayLabel' => 'Priority'
			]
		];

		$response['required'][] = 'name';

		// for associate with project
		$authorizationHeader = null;
		if ($projectId) {
			$customFieldsMetaApiEndpoint = "https://projectsapi.zoho.{$dataCenter}/restapi/portal/{$portalId}/projects/{$projectId}/tasklayouts";
			$authorizationHeader["Authorization"] = "Zoho-oauthtoken {$access_token}";
			$customFieldsMetaResponse = HttpHelper::get($customFieldsMetaApiEndpoint, null, $authorizationHeader);

			if (!is_wp_error($customFieldsMetaResponse)) {
				$sections = $customFieldsMetaResponse->section_details;

				if (count($sections) > 0) {
					foreach ($sections as $section) {
						$fields = $section->customfield_details;
						foreach ($fields as $field) {
							if (!$field->is_default) {
								$allFields[$field->display_name] = (object) array(
									'apiName' => 'cf_' . $field->column_name,
									'displayLabel' => $field->display_name
								);
								if ($field->is_mandatory) $response['required'][] = 'cf_' . $field->column_name;
							}
						}
					}
				}
			}
		}

		$response['fields'] = $allFields;
		uksort($response['fields'], 'strnatcasecmp');
		usort($response['required'], 'strnatcasecmp');

		return $response;
	}

	protected static function getIssueFields($dataCenter, $portalId, $access_token, $projectId)
	{
		$allFields = [
			'Issue Title' => [
				'apiName' => 'title',
				'displayLabel' => 'Issue Title',
				'required' => true
			],
			'Description' => [
				'apiName' => 'description',
				'displayLabel' => 'Description'
			],
			'Due Date' => [
				'apiName' => 'due_date',
				'displayLabel' => 'Due Date'
			],
			'Rate Per Hour' => [
				'apiName' => 'rate_per_hour',
				'displayLabel' => 'Rate Per Hour'
			]
		];

		$response['required'] = ['title'];

		// for associate with project
		$authorizationHeader = null;
		if ($projectId) {
			// Custom Fields
			$customFieldsMetaApiEndpoint = "https://projectsapi.zoho.{$dataCenter}/restapi/portal/{$portalId}/projects/{$projectId}/bugs/customfields/";
			$authorizationHeader["Authorization"] = "Zoho-oauthtoken {$access_token}";
			$customFieldsMetaResponse = HttpHelper::get($customFieldsMetaApiEndpoint, null, $authorizationHeader);

			if (!is_wp_error($customFieldsMetaResponse)) {
				$fields = $customFieldsMetaResponse->customfields;

				if (count($fields) > 0) {
					foreach ($fields as $field) {
						$allFields[$field->label_name] = (object) array(
							'apiName' => $field->column_name,
							'displayLabel' => $field->label_name
						);

						if ($field->is_mandatory === 'true') $response['required'][] = $field->column_name;
					}
				}
			}

			// Default Fields
			$defaultFieldsMetaApiEndpoint = "https://projectsapi.zoho.{$dataCenter}/restapi/portal/{$portalId}/projects/{$projectId}/bugs/defaultfields/";
			$authorizationHeader["Authorization"] = "Zoho-oauthtoken {$access_token}";
			$defaultFieldsMetaResponse = HttpHelper::get($defaultFieldsMetaApiEndpoint, null, $authorizationHeader);

			if (!is_wp_error($defaultFieldsMetaResponse)) {
				$response['defaultfields'] = $defaultFieldsMetaResponse->defaultfields;
			}
		}

		$response['fields'] = $allFields;
		uksort($response['fields'], 'strnatcasecmp');
		usort($response['required'], 'strnatcasecmp');

		return $response;
	}

	public static function refreshUsersAjaxHelper()
	{
		$authorizationHeader = null;
		if (isset($_REQUEST['_ajax_nonce']) && wp_verify_nonce($_REQUEST['_ajax_nonce'], 'bitforms_save')) {
			$inputJSON = file_get_contents('php://input');
			$queryParams = json_decode($inputJSON);
			if (
				empty($queryParams->tokenDetails)
				|| empty($queryParams->dataCenter)
				|| empty($queryParams->clientId)
				|| empty($queryParams->clientSecret)
				|| empty($queryParams->portalId)
			) {
				wp_send_json_error(
					__(
						'Requested parameter is empty',
						'bitformpro'
					),
					400
				);
			}
			$response = [];
			if ((intval($queryParams->tokenDetails->generates_on) + (55 * 60)) < time()) {
				$response['tokenDetails'] = ZohoProjectsHandler::_refreshAccessToken($queryParams);
			}

			$usersMetaApiEndpoint = "";

			if ($queryParams->projectId) {
				$usersMetaApiEndpoint = "https://projectsapi.zoho.{$queryParams->dataCenter}/restapi/portal/{$queryParams->portalId}/projects/{$queryParams->projectId}/users/";
			} else {
				$usersMetaApiEndpoint = "https://projectsapi.zoho.{$queryParams->dataCenter}/restapi/portal/{$queryParams->portalId}/users/";
			}

			$authorizationHeader["Authorization"] = "Zoho-oauthtoken {$queryParams->tokenDetails->access_token}";
			$usersMetaResponse = HttpHelper::get($usersMetaApiEndpoint, null, $authorizationHeader);

			// wp_send_json_success($usersMetaResponse, 200);

			if (!is_wp_error($usersMetaResponse)) {
				$users = $usersMetaResponse->users;

				if (count($users) > 0) {
					foreach ($users as $user) {
						$response['users'][] = (object) array(
							'userId' => $user->id,
							'userName' => $user->name,
							'userEmail' => $user->email,
						);
					}
				}
			} else {
				wp_send_json_error(
					empty($usersMetaResponse->data) ? 'Unknown' : $usersMetaResponse->error,
					400
				);
			}
			if (!empty($response['tokenDetails']) && !empty($queryParams->id)) {
				ZohoProjectsHandler::_saveRefreshedToken($queryParams->formID, $queryParams->id, $response['tokenDetails'], $response['lists']);
			}
			wp_send_json_success($response, 200);
		} else {
			wp_send_json_error(
				__(
					'Token expired',
					'bitformpro'
				),
				401
			);
		}
	}

	public static function refreshTaskLaysAjaxHelper()
	{
		$authorizationHeader = null;
		if (isset($_REQUEST['_ajax_nonce']) && wp_verify_nonce($_REQUEST['_ajax_nonce'], 'bitforms_save')) {
			$inputJSON = file_get_contents('php://input');
			$queryParams = json_decode($inputJSON);
			if (
				empty($queryParams->tokenDetails)
				|| empty($queryParams->dataCenter)
				|| empty($queryParams->clientId)
				|| empty($queryParams->clientSecret)
				|| empty($queryParams->portalId)
			) {
				wp_send_json_error(
					__(
						'Requested parameter is empty',
						'bitformpro'
					),
					400
				);
			}
			$response = [];
			if ((intval($queryParams->tokenDetails->generates_on) + (55 * 60)) < time()) {
				$response['tokenDetails'] = ZohoProjectsHandler::_refreshAccessToken($queryParams);
			}

			$taskLaysMetaApiEndpoint = "https://projectsapi.zoho.{$queryParams->dataCenter}/restapi/portal/{$queryParams->portalId}/tasklayouts";

			$authorizationHeader["Authorization"] = "Zoho-oauthtoken {$queryParams->tokenDetails->access_token}";
			$taskLaysMetaResponse = HttpHelper::get($taskLaysMetaApiEndpoint, null, $authorizationHeader);

			// wp_send_json_success($taskLaysMetaResponse, 200);

			if (!is_wp_error($taskLaysMetaResponse)) {
				$taskLays = $taskLaysMetaResponse->layouts;

				if (count($taskLays) > 0) {
					foreach ($taskLays as $taskLay) {
						$response['taskLays'][] = (object) array(
							'taskLayId' => $taskLay->layout_id,
							'taskLayName' => $taskLay->layout_name
						);
					}
				}
			} else {
				wp_send_json_error(
					empty($taskLaysMetaResponse->data) ? 'Unknown' : $taskLaysMetaResponse->error,
					400
				);
			}
			if (!empty($response['tokenDetails']) && !empty($queryParams->id)) {
				ZohoProjectsHandler::_saveRefreshedToken($queryParams->formID, $queryParams->id, $response['tokenDetails'], $response['lists']);
			}
			wp_send_json_success($response, 200);
		} else {
			wp_send_json_error(
				__(
					'Token expired',
					'bitformpro'
				),
				401
			);
		}
	}

	public static function refreshGroupsAjaxHelper()
	{
		$authorizationHeader = null;
		if (isset($_REQUEST['_ajax_nonce']) && wp_verify_nonce($_REQUEST['_ajax_nonce'], 'bitforms_save')) {
			$inputJSON = file_get_contents('php://input');
			$queryParams = json_decode($inputJSON);
			if (
				empty($queryParams->tokenDetails)
				|| empty($queryParams->dataCenter)
				|| empty($queryParams->clientId)
				|| empty($queryParams->clientSecret)
				|| empty($queryParams->portalId)
			) {
				wp_send_json_error(
					__(
						'Requested parameter is empty',
						'bitformpro'
					),
					400
				);
			}
			$response = [];
			if ((intval($queryParams->tokenDetails->generates_on) + (55 * 60)) < time()) {
				$response['tokenDetails'] = ZohoProjectsHandler::_refreshAccessToken($queryParams);
			}

			$groupsMetaApiEndpoint = "https://projectsapi.zoho.{$queryParams->dataCenter}/restapi/portal/{$queryParams->portalId}/projects/groups";

			$authorizationHeader["Authorization"] = "Zoho-oauthtoken {$queryParams->tokenDetails->access_token}";
			$groupsMetaResponse = HttpHelper::get($groupsMetaApiEndpoint, null, $authorizationHeader);

			// wp_send_json_success($groupsMetaResponse, 200);

			if (!is_wp_error($groupsMetaResponse)) {
				$groups = $groupsMetaResponse->groups;

				if (count($groups) > 0) {
					foreach ($groups as $group) {
						$response['groups'][] = (object) array(
							'groupId' => $group->id,
							'groupName' => $group->name
						);
					}
				}
			} else {
				wp_send_json_error(
					empty($groupsMetaResponse->data) ? 'Unknown' : $groupsMetaResponse->error,
					400
				);
			}
			if (!empty($response['tokenDetails']) && !empty($queryParams->id)) {
				ZohoProjectsHandler::_saveRefreshedToken($queryParams->formID, $queryParams->id, $response['tokenDetails'], $response['lists']);
			}
			wp_send_json_success($response, 200);
		} else {
			wp_send_json_error(
				__(
					'Token expired',
					'bitformpro'
				),
				401
			);
		}
	}

	public static function refreshTagsAjaxHelper()
	{
		$authorizationHeader = null;
		if (isset($_REQUEST['_ajax_nonce']) && wp_verify_nonce($_REQUEST['_ajax_nonce'], 'bitforms_save')) {
			$inputJSON = file_get_contents('php://input');
			$queryParams = json_decode($inputJSON);
			if (
				empty($queryParams->tokenDetails)
				|| empty($queryParams->dataCenter)
				|| empty($queryParams->clientId)
				|| empty($queryParams->clientSecret)
				|| empty($queryParams->portalId)
			) {
				wp_send_json_error(
					__(
						'Requested parameter is empty',
						'bitformpro'
					),
					400
				);
			}

			$response = [];
			if ((intval($queryParams->tokenDetails->generates_on) + (55 * 60)) < time()) {
				$response['tokenDetails'] = ZohoProjectsHandler::_refreshAccessToken($queryParams);
			}

			$tagsMetaApiEndpoint = "https://projectsapi.zoho.{$queryParams->dataCenter}/api/v3/portal/{$queryParams->portalId}/tags";

			$authorizationHeader["Authorization"] = "Zoho-oauthtoken {$queryParams->tokenDetails->access_token}";
			$tagsMetaResponse = HttpHelper::get($tagsMetaApiEndpoint, null, $authorizationHeader);

			// wp_send_json_success($tagsMetaResponse, 200);

			if (!is_wp_error($tagsMetaResponse)) {
				$tags = $tagsMetaResponse->tags;

				if (count($tags) > 0) {
					$allTags = [];
					foreach ($tags as $tag) {
						$allTags[$tag->name] = (object) array(
							'tagId' => $tag->id,
							'tagName' => $tag->name
						);
					}
					uksort($allTags, 'strnatcasecmp');
					$response['tags'] = $allTags;
				}
			} else {
				wp_send_json_error(
					empty($tagsMetaResponse->data) ? 'Unknown' : $tagsMetaResponse->error,
					400
				);
			}
			if (!empty($response['tokenDetails']) && !empty($queryParams->id)) {
				ZohoProjectsHandler::_saveRefreshedToken($queryParams->formID, $queryParams->id, $response['tokenDetails'], $response['lists']);
			}
			wp_send_json_success($response, 200);
		} else {
			wp_send_json_error(
				__(
					'Token expired',
					'bitformpro'
				),
				401
			);
		}
	}

	protected static function _refreshAccessToken($apiData)
	{
		if (
			empty($apiData->dataCenter)
			|| empty($apiData->clientId)
			|| empty($apiData->clientSecret)
			|| empty($apiData->tokenDetails)
		) {
			return false;
		}
		$tokenDetails = $apiData->tokenDetails;

		$dataCenter = $apiData->dataCenter;
		$apiEndpoint = "https://accounts.zoho.{$dataCenter}/oauth/v2/token";
		$requestParams = array(
			"grant_type" => "refresh_token",
			"client_id" => $apiData->clientId,
			"client_secret" => $apiData->clientSecret,
			"refresh_token" => $tokenDetails->refresh_token,
		);

		$apiResponse = HttpHelper::post($apiEndpoint, $requestParams);
		if (is_wp_error($apiResponse) || !empty($apiResponse->error)) {
			return false;
		}
		$tokenDetails->generates_on = \time();
		$tokenDetails->access_token = $apiResponse->access_token;
		return $tokenDetails;
	}

	/**
	 * Save updated access_token to avoid unnecessary token generation
	 *
	 * @param Integer $formID        ID of Integration related form
	 * @param Integer $integrationID ID of Zoho crm Integration
	 * @param Obeject $tokenDetails  refreshed token info
	 *
	 * @return null
	 */
	protected static function _saveRefreshedToken($formID, $integrationID, $tokenDetails, $others = null)
	{
		if (empty($formID) || empty($integrationID)) {
			return;
		}

		$integrationHandler = new IntegrationHandler($formID, IpTool::getUserDetail());
		$zprojectsDetails = $integrationHandler->getAIntegration($integrationID);

		if (is_wp_error($zprojectsDetails)) {
			return;
		}
		$newDetails = json_decode($zprojectsDetails[0]->integration_details);

		$newDetails->tokenDetails = $tokenDetails;
		if (!empty($others['portals'])) {
			$newDetails->default->portals = $others['portals'];
		}


		$integrationHandler->updateIntegration($integrationID, $zprojectsDetails[0]->integration_name, 'Zoho Projects', \json_encode($newDetails), 'form');
	}

	public function execute(IntegrationHandler $integrationHandler, $integrationData, $fieldValues, $entryID, $logID)
	{
		$integrationDetails = is_string($integrationData->integration_details) ? json_decode($integrationData->integration_details) : $integrationData->integration_details;

		$tokenDetails = $integrationDetails->tokenDetails;
		$portalId = $integrationDetails->portalId;
		$dataCenter = $integrationDetails->dataCenter;
		$fieldMap = $integrationDetails->field_map;
		if (
			empty($tokenDetails)
			|| empty($portalId)
			|| empty($fieldMap)
		) {
			return new WP_Error('REQ_FIELD_EMPTY', __('list are required for zoho projects api', 'bitformpro'));
		}

		$requiredParams = null;
		if ((intval($tokenDetails->generates_on) + (55 * 60)) < time()) {
			$requiredParams['clientId'] = $integrationDetails->clientId;
			$requiredParams['clientSecret'] = $integrationDetails->clientSecret;
			$requiredParams['dataCenter'] = $integrationDetails->dataCenter;
			$requiredParams['tokenDetails'] = $tokenDetails;
			$newTokenDetails = ZohoProjectsHandler::_refreshAccessToken((object)$requiredParams);
			if ($newTokenDetails) {
				ZohoProjectsHandler::_saveRefreshedToken($this->_formID, $this->_integrationID, $newTokenDetails);
				$tokenDetails = $newTokenDetails;
			}
		}

		$recordApiHelper = new RecordApiHelper($tokenDetails, $this->_integrationID, $logID);

		$zprojectsApiResponse = $recordApiHelper->executeRecordApi(
			$this->_formID,
			$entryID,
			$integrationDetails,
			$dataCenter,
			$fieldMap,
			$fieldValues
		);

		if (is_wp_error($zprojectsApiResponse)) {
			return $zprojectsApiResponse;
		}
		return $zprojectsApiResponse;
	}
}
