<?php

namespace FluentFormPro\Integrations\IContact;

if (!defined('ABSPATH')) {
    exit; // Exit if accessed directly.
}

use Exception;

class IContactApi
{
	
	protected $api_url = 'https://app.icontact.com/icp/a/';
	public $account_id = null;
	protected $client_folder_id = null;
	
	public function __construct( $app_id, $api_username, $api_password, $client_folder_id = null, $account_id = '' ) {
		
		$this->app_id = $app_id;
		$this->api_username = $api_username;
		$this->api_password = $api_password;
		$this->client_folder_id = $client_folder_id;
		$this->account_id = $account_id;
	}
	
	/**
	 * Get base path of API requests.
	 *
	 * @access public
	 * @return void
	 */
	public function get_url_base() {
		
		return $this->set_account_id() .'/c/'. $this->client_folder_id .'/';
		
	}
	
	/**
	 * Get array of headers needed for every API request.
	 *
	 * @access public
	 * @return array
	 */
	public function request_headers() {
		
		return array(
			'Expect'       => '',
			'Accept'       => 'application/json',
			'Content-type' => 'application/json',
			'Api-Version'  => '2.2',
			'Api-AppId'    => $this->app_id,
			'Api-Username' => $this->api_username,
			'Api-Password' => $this->api_password
		);
		
	}

	/**
	 * Make API request.
	 *
	 * @access public
	 * @param string $action
	 * @param array $options (default: array())
	 * @param string $method (default: 'GET')
	 * @return \WP_Error | array | \Exception
	 */
	public function make_request( $action = null, $options = array(), $method = 'GET', $return_key = null )
    {
        $options = apply_filters_deprecated(
            'fluentform_icontact_request_args',
            [
                $options,
                $action,
                $method,
                $return_key
            ],
            FLUENTFORM_FRAMEWORK_UPGRADE,
            'fluentform/icontact_request_args',
            'Use fluentform/icontact_request_args instead of fluentform_icontact_request_args.'
        );

		$options = apply_filters( 'fluentform/icontact_request_args', $options, $action, $method, $return_key );

		// Build request options string.
		$request_options = ( $method == 'GET' && ! empty( $options ) ) ? '?' . http_build_query( $options ) : '';
		
		// Build request URL.
		$request_url = $this->api_url . $action . $request_options;
		
		// Prepare request and execute.
		$args = array(
			'headers' => $this->request_headers(),
			'method'  => $method
		);
		
		if ( $method == 'POST' ) {
			$args['body'] = json_encode( $options );
		}

		$response = wp_remote_request( $request_url, $args );
		
		// If WP_Error, die. Otherwise, return decoded JSON.
		if ( is_wp_error( $response ) ) {
			return $response;
		} else {
			
			$response = json_decode( $response['body'], true );
			
			if (isset( $response['errors'])) {
				if (isset($response['errors'][0]) && is_string($response['errors'][0])) {
					throw new Exception( $response['errors'][0] ); // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
				}
			}

			if (isset($response['warnings'])) {
				if (isset($response['warnings'][0]) && is_string($response['warnings'][0])) {
					throw new Exception( $response['warnings'][0] ); // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
				}
			}
			
			return empty( $return_key ) ? $response : $response[$return_key];
			
		}
		
	}
	
	/**
	 * Fetch the Account ID.
	 *
	 * @access public
	 * @return void
	 */
	public function set_account_id() {

		if ( empty( $this->account_id ) ) {
			$accounts = $this->make_request('/');
			if ( isset( $accounts['errors'] ) )
				throw new Exception( $accounts['errors'][0] ); // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
			
			$account = $accounts['accounts'][0];

			if ( $account['enabled'] == 1 ) {
				$this->account_id = $account['accountId'];
			} else {
				throw new Exception(__('Your account has been disabled.', 'fluentformpro')); // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
			}
		}
		
		return $this->account_id;
		
	}
	
	/**
	 * Add a new contact.
	 *
	 * @access public
	 * @param array $contact
	 * @return array
	 */
	public function add_contact( $contact ) {
		
		$contacts = $this->make_request( $this->get_url_base() . 'contacts', array( $contact ), 'POST', 'contacts' );
		
		return $contacts[0];
		
	}
	
	/**
	 * Add a contact to a list.
	 *
	 * @access public
	 * @param int $contact_id
	 * @param int $list_id
	 * @param string $status (default: 'normal')
	 * @return void
	 */
	public function add_contact_to_list( $contact_id, $list_id, $status = 'normal' ) {
		
		$subscription = array(
			'contactId' => $contact_id,
			'listId'    => $list_id,
			'status'    => $status
		);
		
		$new_subscription = $this->make_request( $this->get_url_base() . 'subscriptions', array( $subscription ), 'POST', 'subscriptions' );
		
		return $new_subscription;
		
	}
	
	/**
	 * Add new custom field to account.
	 *
	 * @access public
	 * @param mixed $custom_field
	 * @return void
	 */
	public function add_custom_field( $custom_field ) {
		
		return $this->make_request( $this->get_url_base() . 'customfields', array( $custom_field ), 'POST', 'customfields' );
	
	}
	
	/**
	 * Get available client folders.
	 *
	 * @access public
	 * @return array $folders
	 */
	public function get_client_folders() {
		
		/* If the account ID isn't set, go set it. */
		if ( empty( $this->account_id ) ) {
			$this->set_account_id();
		}

		$clients = $this->make_request( $this->account_id . '/c/', array( 'limit' => 999 ) );
		
		if ( isset( $clients['errors'] ) ) {
			throw new Exception(__('No client folders were found for this account.', 'fluentformpro')); // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
		}
		
		return $clients['clientfolders'];
		
	}

	/**
	 * Fetch all contacts associated with this account.
	 *
	 * @access public
	 * @return void
	 */
	public function get_contacts() {
		
		return $this->make_request( $this->get_url_base() . 'contacts', array(), 'GET', 'contacts' );
		
	}
	
	/**
	 * Fetch contact by email address.
	 *
	 * @access public
	 * @return void
	 */
	public function get_contact_by_email( $email ) {
		return $this->make_request( $this->get_url_base() . 'contacts', array( 'email' => $email ), 'GET', 'contacts' );
	}

	/**
	 * Fetch custom fields for associated with this account.
	 *
	 * @access public
	 * @return void
	 */
	public function get_custom_fields() {
		return $this->make_request( $this->get_url_base() . 'customfields', array(), 'GET', 'customfields' );
	}

	/**
	 * Fetch all lists associated with this account.
	 *
	 * @access public
	 * @return void
	 */
	public function get_lists() {
		
		return $this->make_request( $this->get_url_base() . 'lists', array( 'limit' => 999 ), 'GET', 'lists' );
		
	}

	/**
	 * Fetch a specific list associated with this account.
	 *
	 * @access public
	 * @param mixed $list_id
	 * @return void
	 */
	public function get_list( $list_id ) {
		
		return $this->make_request( $this->get_url_base() . 'lists/' . $list_id, array(), 'GET', 'list' );
		
	}

	/**
	 * Checks to see if a client folder has been selected.
	 *
	 * @access public
	 * @return bool
	 */
	public function is_client_folder_set() {
		
		return ! empty( $this->client_folder_id );
		
	}

	/**
	 * Update an existing contact.
	 *
	 * @access public
	 * @param int $contact_id
	 * @param array $contact
	 * @return void
	 */
	public function update_contact( $contact_id, $contact ) {
		
		return $this->make_request( $this->get_url_base() . 'contacts/'. $contact_id, $contact, 'POST', 'contact' );
		
	}
}
