<?php 
/**
 * PipeDrive_integration Class
 * WP Options af2_pipedrive_enable, af2_pipedrive_api_key
 * @author WDT 
 * @author Shubham Jain
 * */

class PipeDrive_integration
{
    private $auth_credentials = '';
    private $api_url = '';
    
	/**
	 * Class constructor 
	 * */
	function __construct()
	{
        if( function_exists('get_option') )
        {
            $this->set_credentials(get_option('af2_pipedrive_api_key'), get_option('af2_pipedrive_api_url'));
        }
	}

    public function set_credentials($api_key, $api_url){
        $this->auth_credentials = $api_key;
        $this->api_url = $api_url;
    }

    /**
     * Send curl request to verify API URL and Key
     * @param String $api_key
     * @param Sting $api_url
     * @return Array : Array of User Account with success:true . On Fail it will send array with success:false and details
     * */
    public function verify_api_key($api_key, $api_url){
        // get users if found then verify otherwise fails.
        if($api_key && $api_url){
            $this->set_credentials($api_key, $api_url);
            $users = $this->request('users');
            return json_decode($users->response, true);            
        }else{
            return false;
        }
    }

    /**
     * Send curl request to add Person or contact in pipedrive
     * @param Array $data array( "name" => "James Bond", "email" => array("james@example.com"), "phone" => array("123-456-7890") );
     * @return Object | with response and http code, Exception on any error thrown
     * */
    public function add_contact($data)
    {
        try {
            $response = $this->request('persons', 'POST', $data);
            return $response;
        } catch (\Throwable $th) {
            return $th;
        }
    }

    /**
     * Send curl request to add new person/contact or update that if already exist (this will only work for first email id in given array of email ids)
     * @param Array $data array( "name" => "James Bond", "email" => array("james@example.com"), "phone" => array("123-456-7890") );
     * @return Object | Exception on any error thrown
     * */
    public function add_update_contact($data)
    {
        if( !isset($data['email']) || empty($data['email']) ) return false;

        $email = is_array($data['email']) ? $data['email'][0] : $data['email'];

        // search person with email id
        $search = $this->search_contact($email);

        if($search->response){
            $searchResponse = json_decode($search->response, true);
            if($searchResponse['success'] && count($searchResponse['data']['items']) > 0 ){
                $personData = $searchResponse['data']['items'][0];
                $person_id = $personData['item']['id'];                
                return $this->update_contact($data, $person_id);
            }else{
                return $this->add_contact($data);
            }
        }else{
            return $this->add_contact($data);
        }
    }

    /**
     * Send curl request to udpate person or contact by given id
     * @param Array $data $data array( "name" => "James Bond", "email" => array("james@example.com"), "phone" => array("123-456-7890") );
     * @param Integer $id person id in PipeDrive
     * @return Object | Exception on any error thrown
     * */
    public function update_contact($data, $id)
    {
            
        try {
            $response = $this->request('persons/'.$id, 'PUT', $data);
            return $response;
        } catch (\Throwable $th) {
            return $th;
        }
    }

    /**
     * Send curl request to udpate person or contact by given id
     * @param Array $data $data array( "name" => "James Bond", "email" => array("james@example.com"), "phone" => array("123-456-7890") );
     * @param Integer $id person id in PipeDrive
     * @return Object | Exception on any error thrown
     * */
    public function search_contact($email='')
    {
        if($email){
            $searchArr = array(
                'fields' => 'email',
                'term' => $email,
                'exact_match' => false,
                'start' => 0,
                'limit' => 10
            );
            try {
                $response = $this->request('persons/search', 'GET', '', $searchArr);
                return $response;
            } catch (\Throwable $th) {
                return $th;
            }
        }
        return false;
    }

    /**
     * Send curl request to get all persons or contacts
     * @return Array | Exception on any error thrown
     * 
     * */
    public function get_contacts()
    {
        try {
            $queryArrg = array( 'start'=> 0, 'limit'=>92875845 );
            $response = $this->request('persons', 'GET', '', $queryArrg);
            return $response;
        } catch (\Throwable $th) {
            return $th;
        }
    }

    private function get_request_url($path, $queryArrg = [])
    {
        $urlString = $this->api_url.'/api/v1/'.$path;
        
        $queryParam = array('api_token' => $this->auth_credentials);
        $paramString = http_build_query( array_merge($queryParam, $queryArrg) );
        return $urlString.'?'.$paramString;
    }

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

    public function request($uri='/', $method = 'GET', $data = '', $queryArrg=[])
    {
        $header = array(
            'Content-Type: application/json',
            'Accept: application/json',
            'cache-control: no-cache'
        );

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

        $requestUri = $this->get_request_url($uri, $queryArrg);
        
        if( empty($requestUri) ) throw new Exception('Not a valid request url');
        // echo $requestUri; print_r($data);die;
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $requestUri);
        curl_setopt($curl, CURLOPT_FOLLOWLOCATION, false); // optional
        curl_setopt($curl, CURLOPT_MAXREDIRS, 1);  // optional 
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
        
        // use if normal username password authentication is required.
        // curl_setopt($curl, CURLOPT_USERPWD, $username . ':' . $password); 
        
        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); // optional if debug
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2); // optional if debug
        // 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;      
    }

}
