<?php
/**
 * @package        RSForm! Pro
 * @copyright  (c) 2007 - 2020 RSJoomla!
 * @link           https://www.rsjoomla.com
 * @license        GNU General Public License http://www.gnu.org/licenses/gpl-3.0.en.html
 */

defined('_JEXEC') or die;

use Joomla\CMS\Language\Text;
use Joomla\CMS\Http\HttpFactory;
use Joomla\CMS\Factory;
use Joomla\Utilities\IpHelper;

/**
 * Class RSFormPro_Mailchimp
 */
class RSFormPro_Mailchimp
{
	/**
	 * The URL from where we will access data.
	 */
	const ENDPOINT = '%s://%s.api.mailchimp.com/3.0/%s';
	/**
	 * This holds the server where the data is located.
	 *
	 * @var $server
	 */
	protected $server;
	/**
	 * The mailchimp API Key
	 *
	 * @var $key
	 */
	protected $key;

	/**
	 * The count option used in retrieving lists (the Mailchimp default is 10)
	 *
	 * @var $key
	 */
	protected $count;

	/**
	 * RSFormPro_Mailchimp constructor.
	 */
	public function __construct()
	{
		/**
		 * Sets the mailchimp api key
		 */
		$key = RSFormProHelper::getConfig('mailchimp.key');

		if ($key && strpos($key, '-') !== false)
		{
			// This seems to be a valid key
			$this->key = $key;
			list($api, $this->server) = explode('-', $key);

			// Get the count for lists
			$this->count = (!RSFormProHelper::getConfig('mailchimp.list_count') ? 10 : (int) RSFormProHelper::getConfig('mailchimp.list_count'));
			// this setting must be at least 1
			if (!$this->count) {
				$this->count = 1;
			}
		}
	}

	/**
	 * Returns the instance of the mailchimp object
	 *
	 * @return RSFormPro_Mailchimp
	 */
	public static function getInstance()
	{
		static $inst;
		if (!$inst)
		{
			$inst = new RSFormPro_Mailchimp;
		}

		return $inst;
	}

	/**
	 * Create a request to the mailchimp API
	 *
	 * @param $args
	 *
	 * @return mixed
	 * @throws Exception
	 */
	private function request($args, $decode_json = true)
	{
		if (!$this->key || !$this->server)
		{
			throw new Exception (Text::_('RSFP_MAILCHIMP_NO_KEY_ADDED'));
		}
		
		$headers = array(
			'Authorization' => 'apikey ' . $this->key
		);

		if (!empty($args['data']['language']))
		{
			$headers['Accept-Language'] = $args['data']['language'];
		}

		$http = HttpFactory::getHttp();

		$params = implode('/', $args['params']);
		
		if (isset($args['q_params']) && !empty($args['q_params'])) {
			$q_params = implode('&', $args['q_params']);
			// Append to the $params
			$params .= '?' . $q_params; 
		}

		$scheme = 'https';
		
		$url = sprintf(self::ENDPOINT, $scheme, $this->server, $params);
		
		$response = null;

		$timeout = RSFormProHelper::getConfig('mailchimp.timeout');

		switch ($args['method'])
		{
			case 'get':
				$response = $http->get($url, $headers, $timeout);
				break;

			case 'post':
				$response = $http->post($url, json_encode($args['data']), $headers, $timeout);
				break;

			case 'patch':
				$response = $http->patch($url, json_encode($args['data']), $headers, $timeout);
				break;

			case 'put':
				$headers['X-HTTP-Method-Override'] = 'PUT';
				$response                          = $http->post($url, json_encode($args['data']), $headers, $timeout);
				break;

			case 'delete':
				$headers['X-HTTP-Method-Override'] = 'DELETE';
				$response                          = $http->post($url, json_encode($args['data']), $headers, $timeout);
				break;
		}

		if ($decode_json)
		{
			$data = json_decode($response->body);

			if ($data === null)
			{
				throw new Exception(Text::_('RSFP_MAILCHIMP_COULD_NOT_DECODE_JSON_DATA'));
			}

			if ($response->code >= 400)
			{
				if (isset($data->detail))
				{
					throw new Exception($data->detail);
				}
				else
				{
					throw new Exception(Text::sprintf('RSFP_MAILCHIMP_RECEIVED_HTTP_ERROR_NUM', $response->code));
				}
			}

			return $data;
		}
		else
		{
			return $response->body;
		}
	}

	/**
	 * Get the lists
	 *
	 * @return array
	 */
	public function get_lists()
	{
		$args = array(
			'method'   => 'get',
			'params'   => array('lists'),
			'q_params' => array('count='.$this->count)
		);
		try
		{
			$return = array();
			$lists  = $this->request($args);

			if (!empty($lists->lists))
			{
				foreach ($lists->lists as $list)
				{
					$return[] = array(
						'name'  => $list->name,
						'id'    => $list->id,
						'stats' => $list->stats->member_count
					);
				}
			}

			return $return;

		}
		catch (Exception $e)
		{
			Factory::getApplication()->enqueueMessage('(Mailchimp) ' . $e->getMessage(), 'warning');
			return array();
		}
	}

	/**
	 * Adds a user to a certain list
	 *
	 * @param $list_id
	 * @param $update
	 * @param $data
	 * @param $replace
	 * @param $delete
	 *
	 * @return array|string
	 */
	public function manage_user($list_id, $update = false, $replace = false, $delete = false, $data = array(), $status_data = null)
	{
		$interests = array();

		foreach ($data['interests'] as $interest)
		{
			foreach ($interest['groups'] as $subgroup)
			{
				$interests[$subgroup] = true;
			}
		}
		
		if ($replace)
		{
			$all_interests = $this->create_interests_array($list_id);
			$data['interests'] = array_replace($all_interests, $interests);
		} else {
			$data['interests'] = $interests;
		}

		$data['ip_signup'] = IpHelper::getIp();
		$data['timestamp_signup'] = Factory::getDate()->format('c');
		
		// Cast as object apparently
		$data['interests'] = (object) $data['interests'];

		$args = array(
			'method' => 'post',
			'params' => array('lists', $list_id, 'members'),
			'data'   => $data,
		);

		try
		{
			if ((bool) $update)
			{
				$args['method']   = 'put';
				$args['params'][] = md5(strtolower($data['email_address']));
			}

			if ((bool) $delete && $data['status'] == 'unsubscribed')
			{
				$args['method']   = 'delete';
			}

			// Do not update existing users, but user is already on our list, show a nicer message
			if (!$update && $status_data)
			{
				Factory::getApplication()->enqueueMessage(Text::_('RSFP_MAILCHIMP_SORRY_YOUR_EMAIL_ADDRESS_APPEARS_TO_BE_ON_OUR_LIST_ALREADY'), 'warning');
				return false;
			}

			return $this->request($args);
		}
		catch (Exception $e)
		{
			Factory::getApplication()->enqueueMessage('(Mailchimp) ' . $e->getMessage(), 'warning');
		}
	}

	public function update_user($list_id, $email_address, $data)
	{
		$args = array(
			'method' => 'patch',
			'params' => array('lists', $list_id, 'members', md5(strtolower($email_address))),
			'data'   => $data,
		);

		try
		{
			return $this->request($args);
		}
		catch (Exception $e)
		{
			Factory::getApplication()->enqueueMessage('(Mailchimp) ' . $e->getMessage(), 'warning');
		}
	}

	public function update_user_tags($list_id, $email_address, $tags, $is_syncing)
	{
		$args = array(
			'method' => 'post',
			'params' => array('lists', $list_id, 'members', md5(strtolower($email_address)), 'tags'),
			'data'   => array('tags'=> $tags, 'is_syncing' => $is_syncing),
		);

		try
		{
			 $this->request($args, false);
		}
		catch (Exception $e)
		{
			Factory::getApplication()->enqueueMessage('(Mailchimp) ' . $e->getMessage(), 'warning');
		}
	}
	
	public function get_user_status($list_id, $email_address) {
		$args = array(
			'method' => 'get',
			'params' => array('lists', $list_id, 'members', md5(strtolower($email_address)))
		);

		try
		{
			return $this->request($args);
		}
		catch (Exception $e)
		{
			return false;
		}
	}

	public function get_user_tags($list_id, $email_address)
	{
		$args = array(
			'method' => 'get',
			'params' => array('lists', $list_id, 'members', md5(strtolower($email_address)), 'tags'),
		);

		try
		{
			if ($result = $this->request($args))
			{
				if (!empty($result->tags))
				{
					return $result->tags;
				}
			}
		}
		catch (Exception $e)
		{
			Factory::getApplication()->enqueueMessage('(Mailchimp) ' . $e->getMessage(), 'warning');
		}
	}

	/**
	 * Creates an array with all the interests assigned to the list id.
	 *
	 * @param $list_id
	 *
	 * @return array
	 */
	public function create_interests_array($list_id)
	{
		$all_interests = array();
		
		try
		{			
			if ($categories = $this->get_interest_categories($list_id))
			{
				foreach ($categories as $category)
				{
					if ($results = $this->get_interests($list_id, $category->id))
					{
						foreach ($results as $interest)
						{
							$all_interests[$interest->id] = false;
						}
					}
				}
			}
		}
		catch (Exception $e)
		{
			Factory::getApplication()->enqueueMessage('(Mailchimp) ' . $e->getMessage(), 'warning');
		}
		
		return $all_interests;
	}
	
	public function get_interests($list_id, $category_id)
	{
		$params = array(
			'method' => 'get',
			'params' => array('lists', $list_id, 'interest-categories', $category_id, 'interests'),
			'q_params' => array('count='.$this->count)
		);
		
		try
		{
			if ($result = $this->request($params))
			{
				if (!empty($result->interests))
				{
					return $result->interests;
				}
			}
		}
		catch (Exception $e)
		{
			Factory::getApplication()->enqueueMessage('(Mailchimp) ' . $e->getMessage(), 'warning');
		}
		
		return false;
	}
	
	public function get_interest_categories($list_id)
	{
		$params = array(
			'method' => 'get',
			'params' => array('lists', $list_id, 'interest-categories'),
			'q_params' => array('count='.$this->count)
		);
		
		try
		{			
			if ($response = $this->request($params))
			{
				return $response->categories;
			}
		}
		catch (Exception $e)
		{
			Factory::getApplication()->enqueueMessage('(Mailchimp) ' . $e->getMessage(), 'warning');
		}
		
		return false;
	}
	
	public function get_merge_fields($list_id)
	{
		$params = array(
			'method' => 'get',
			'params' => array('lists', $list_id, 'merge-fields'),
			'q_params' => array('count='.$this->count)
		);

		try
		{
			if ($result = $this->request($params))
			{
				if (!empty($result->merge_fields))
				{
					return $result->merge_fields;
				}
			}
		}
		catch (Exception $e)
		{
			Factory::getApplication()->enqueueMessage('(Mailchimp) ' . $e->getMessage(), 'warning');
		}
		
		return false;
	}

	public function get_tags($list_id)
	{
		$params = array(
			'method' => 'get',
			'params' => array('lists', $list_id, 'segments'),
			'q_params' => array('count='.$this->count)
		);

		try
		{
			if ($result = $this->request($params))
			{
				if (!empty($result->segments))
				{
					return $result->segments;
				}
			}
		}
		catch (Exception $e)
		{
			Factory::getApplication()->enqueueMessage('(Mailchimp) ' . $e->getMessage(), 'warning');
		}

		return false;
	}
}