<?php 
/**
 * MailChimp_Integration Class
 * WP Options af2_mailchimp_enable, af2_mailchimp_api_key
 * @author WDT 
 * @author Shubham Jain
 * @since  Class available since Release 3.0.5.2
 * */

class MailChimp_Integration
{
	private $auth_credentials = '';
	private $auth_type = 'Basic';
	private $baseUri = '';
    private $apiVersion ='3.0';
	
	/**
	 * Class constructor 
	 * @param string $version optional
	 * */
	function __construct( $version = '3.0' )
	{
        if( function_exists('get_option') )
        {
            $this->auth_credentials = get_option('af2_mailchimp_api_key');
		    $this->set_base_uri();
        }		
        if($version) $this->apiVersion = $version;
	}

    public function test_set_credential($api_key)
    {
        $this->auth_credentials = $api_key;
        $this->set_base_uri();
    }

	public function test_setting_form()
    {
		ob_start();
		?>
		<form name="mailchimp_settings" id="mailchimp_settings" method="post">
		<label>
			<input type="checkbox" 
				name="af2_mailchimp_enable" 
				id="af2_mailchimp_enable"
				<?= (get_option('af2_mailchimp_enable', '')) ? 'checked' : '' ?>
				> 
			Enable
		</label>
		<input 
			type="text" 
			name="af2_mailchimp_api_key" 
			placeholder="API KEY" 
			id="af2_mailchimp_api_key" 
			value="<?php echo get_option('af2_mailchimp_api_key', ''); ?>"
			/>
		<input type="hidden" name="action" value="mailchimp_form_submit" value="true">
		<input type="submit" value="VERIFY AND SAVE" name="submit">
		</form>
		<?php
		echo ob_get_clean();
    }

	public function test_setting_form_handler()
    {
		if( isset($_REQUEST['action']) && 'mailchimp_form_submit' == $_REQUEST['action'] ){
			if( !isset($_REQUEST['af2_mailchimp_enable']) ){
				update_option('af2_mailchimp_enable', '');
			}
			$api_key = $_REQUEST['af2_mailchimp_api_key'];
			
			if( empty($api_key) )
			{
				update_option('af2_mailchimp_api_key', '');
				update_option('af2_mailchimp_enable', '');
				return true;
			}

			if( $api_key == get_option('af2_mailchimp_api_key') ){
				if(isset($_REQUEST['af2_mailchimp_enable'])) update_option('af2_mailchimp_enable', 'enable');
				else update_option('af2_mailchimp_enable', '');
				return true;
			}
			
			$verified = $this->verify_api_key($api_key);
			
			if(( $verified instanceof Exception) ){
				echo 'Error:' . $verified->getMessage();
			} else {
				if( 'varified' == $verified){
					update_option('af2_mailchimp_api_key', $api_key);
					if(isset($_REQUEST['af2_mailchimp_enable'])) update_option('af2_mailchimp_enable', 'enable');
					echo 'MailChimp Credentials successfully verified and saved';
				}else{
					echo 'Error:' .$verified;
				}
			}
		}
    }

    /**
	 * Get all available lists from mailchimp
	 * MailChimp API Route /lists
	 * @return array List of all lists and Error Exception on fail
	 * */
    public function get_all_lists()
    {
        $requestUri = '/lists';
        try {
            $response = $this->send_request( $requestUri , 'get' );
            if( $response->code === 200 || $response->code === '200' )
            {
                return json_decode( $response->response, true )['lists'];
            }
            else
            {
                throw new Exception("Error getting list", 1);
            }
        } catch (\Throwable $th) {
            return $th;
        }
    }
    
    /**
	 * Add Contact or Member in to given list
	 * MailChimp API Route /lists/<list_id>/members
	 * @param array | JSON $contact
     * @param string $list_id
	 * @return string
	 * */
    public function add_contact_to_list($contact, $list_id)
    {
        $requestUri = '/lists/'.$list_id.'/members';
        try {
            $response = $this->send_request( $requestUri , 'post', $contact );
            if( $response->code === 200 || $response->code === '200' )
            {
                return 'added';
            }
            else
            {
                return json_decode( $response->response, true )['detail'];
            }
        } catch (\Throwable $th) {
            return $th;
        }
    }

    /**
	 * Add or Update Contact/Member in to given list
	 * MailChimp API Route /lists/<list_id>/members/<email_hash>
	 * @param mixed $contact (array | json) 
     * @param string $list_id
	 * @return string
	 * */
    public function add_update_contact_to_list($contact, $list_id)
    {
        $email = is_array($contact) ? $contact['email_address'] : json_decode($contact,true)['email_address'];
        $email_hash = md5($email);
        $requestUri = '/lists/'.$list_id.'/members/'.$email_hash;
        try {
            $response = $this->send_request( $requestUri , 'put', $contact );
            if( $response->code === 200 || $response->code === '200' )
            {
                return 'added';
            }
            else
            {
                return json_decode( $response->response, true )['detail'];
            }
        } catch (\Throwable $th) {
            return $th;
        }
    }

    /**
	 * Verify API Key and Domain Prefix or Subdomain
	 * MailChimp API Route /ping
	 * @param string $api_key
	 * @return string
	 * */
    public function verify_api_key($api_key)
    {
        $this->auth_credentials = $api_key;
        $this->set_base_uri();
        
        try {
            $response = $this->send_request('/ping', 'get');
            if( $response->code === 200 || $response->code === '200' )
            {
                return 'varified';
            }
            else
            {
                return json_decode( $response->response, true )['detail'];
            }
        } catch (\Throwable $th) {
            return $th;
        }
    }

	/**
	 * set baseUri based on passed param
	 * @return string
	 * */
	private function set_base_uri()
	{
		$domain = explode("-", $this->auth_credentials);
		$this->baseUri = 'https://'.$domain[1].'.api.mailchimp.com/'.$this->apiVersion;
	}

	/**
	 * Create Authorization header with credentials
	 * @return string
	 * */
	private function get_auth_header_string()
	{
        $credential_string = base64_encode( 'user:' . $this->auth_credentials );
		return 'Authorization: '.$this->auth_type.' '. $credential_string;
	}

	/**
	 * Send curl request to the given url
	 * @param $uri string optional - use if you want to break the url in to base url and action path 
	 * @param $method string default GET 
	 * @param $data array|string (json string)
	 * @return object | Error Exception on success full hit response object with response, code and meta
	 * */

	public function send_request($uri='/', $method = 'GET', $data = '') 
	{
	    $header = array(
	        'Content-Type: application/json',
	        'Accept: application/json'
	    );

	    if( $this->auth_credentials) array_push( $header, $this->get_auth_header_string());

	    $method = strtoupper($method);
	    $data = is_array($data) ? json_encode($data) : $data;

	    $requestUri = '';
	    if( $uri )
        {
	    	$requestUri = $this->baseUri . $uri;
	    }
        else
        {
	    	throw new Exception('Not a valid request url');
	    }

	    if( empty($requestUri) ) throw new Exception('Not a valid request url');
	    
	    $curl = curl_init();
	    curl_setopt($curl, CURLOPT_URL, $requestUri);
	    curl_setopt($curl, CURLOPT_FOLLOWLOCATION, false);
	    curl_setopt($curl, CURLOPT_MAXREDIRS, 1);
	    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
	    curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
	    
	    if($method == 'POST'){
	        curl_setopt($curl, CURLOPT_POST, true);
	        curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
	    }
	    else if ($method == 'PUT'){
	        curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'PUT');
	        curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
	    }
	    else if($method != 'GET'){
	        curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
	    }
	    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
	    curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);
	    // curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 30);
	    curl_setopt($curl, CURLOPT_TIMEOUT, 30);
	    $result = new StdClass();

	    $result->response = curl_exec($curl);
	    $result->code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
	    $result->meta = curl_getinfo($curl);
	    
	    $curl_error = ($result->code > 0 ? null : curl_error($curl) . ' (' . curl_errno($curl) . ')');
	    curl_close($curl);
	    
	    if ($curl_error) {
	        throw new Exception('An error occurred while connecting to endpoint: ' . $curl_error);
	    }
	    return $result;      
	}
}