<?php
/***************** CONFIGURATION START *****************/

const APIKEY = 'xxx'; // agent panel> settings> system> API

const API_URL = 'https://xxx.ladesk.com/api/v3'; //

// e.g. ./data.csv
const FILE_PATH = './import.csv';

// Col1;Col2;Col3;
const DELIMITER = ';';

// *************** C O L U M N S *****************
// csv column name => api column name
// columns which are not mentioned will be ignored
// ***********************************************

// HACK_1: 'csv_column' => 'name'
//   it will divide name into firstname and lastname
//   e.g. 'aaa bbb ccc' will be firstname => 'aaa' lastname => 'bbb ccc'

// HACK_2: 'csv_column' => 'company_name'
//   it will try to add contact into company if company already exists
//   if company doesn't exist, it will create that company

// HACK_3: list phones as phoneN where N is a number it will be processed into the needed format
// e.g. 'Mobile No.' => 'phone1', 'Landline' => 'phone2'

// HACK_4: list custom fields as customN where N is a number it will be processed into the needed format
// e.g. 'Marital status' => 'custom1', 'Loan' => 'custom2'
// in case you are using custom fields you also have to use COLUMNS_CUSTOM_FIELDS
// you have to define custom field's 'code' for each 'customN' value

const COLUMNS = array(
    'Company' => 'company_name',
    'First Name' => 'firstname',
    'Last Name' => 'lastname',
    'Email' => 'emails',
    'Mobile No.' => 'phone1',
    'Landline' => 'phone2',
    'City' => 'city',
    'Marital status' => 'custom1',
    'Loan' => 'custom2'
);

const COLUMNS_CUSTOM_FIELDS = array(
    'custom1' => 'marital',
    'custom2' => 'loan'
);

/***************** CONFIGURATION END *******************/

$curl = curl_init();

$data = read_and_parse_data();

import($data);

curl_close($curl);

/*******************************************************/
function read_and_parse_data() {
	if (!mb_check_encoding(file_get_contents(FILE_PATH), 'UTF-8')) {
		die('CSV file is not UTF-8 encoded. Please make sure to encode the file in UTF-8 to have special characters correctly saved in LiveAgent.');
	}
    $file = fopen(FILE_PATH, 'r');
    $csv_data = array();
    $api_data = array();
    
    while (($row = fgetcsv($file, 1000, DELIMITER)) !== false) {
        $csv_data[] = $row;
    }
    
    if ($csv_data == array()) {
        die('Input data not found/loaded.');
    }
    
    fclose($file);
    
    $csv_columns = $csv_data[0];
    array_shift($csv_data);
    
    // replace csv column names by api column names
        foreach ($csv_data as $row) {
        $row = filter_columns(array_combine_special($csv_columns, $row));
        $row = array_combine_special(array_merge($row, COLUMNS), $row);
        //print_r($row);die();
        $api_data[] = handle_special_columns($row);
    }

    return $api_data;
}

function import($data) {
    foreach ($data as $row) {
        // some additional information which is not in csv file
        $row['date_created'] = date('Y-m-d H:i:s', time());
        $row['type'] = 'V';
        
        // create contact
        send_request('/contacts', 'POST', $row);
    }
}

/**
 *
 * @param $api_call e.g. '/contacts' ('/' is required)
 * @param $http_method GET, POST, PUT, DELETE
 * @param $data should be array, e.g. array('firstname' => '...', ...)
 */
function send_request($api_call, $http_method, $data = array()) {
    global $curl;
    
    $responseHeaders = [];
    curl_setopt_array($curl, array(
        CURLOPT_URL => API_URL . $api_call,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_ENCODING => '',
        CURLOPT_MAXREDIRS => 10,
        CURLOPT_TIMEOUT => 30,
        CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
        CURLOPT_CUSTOMREQUEST => $http_method,
        CURLOPT_HTTPHEADER => array(
            'apikey: ' . APIKEY,
            'cache-control: no-cache',
            'content-type: application/json; charset=utf-8' 
        ),
        CURLOPT_HEADERFUNCTION => function($curl, $header) use (&$responseHeaders) {
            $len = strlen($header);
            $header = explode(':', $header, 2);
            if (count($header) < 2)
              return $len;

            $responseHeaders[strtolower(trim($header[0]))][] = trim($header[1]);
            
            return $len;
        } 
    ));
    
    $dataEncoded = json_encode($data, JSON_UNESCAPED_UNICODE);
    
    if ($dataEncoded != array()) {
        curl_setopt($curl, CURLOPT_POSTFIELDS, $dataEncoded);
    }
    
    $response = curl_exec($curl);
    $info = curl_getinfo($curl);
    
    if ($info['http_code'] == 429) {
        $sleepTime = 5;
        if (isset($responseHeaders['retry-after'])) {
            $sleepTime = $responseHeaders['retry-after'];
        }
        sleep($sleepTime);
        return send_request($api_call, $http_method, $data = array());
    }
    
    if ($info['http_code'] != 200) {
        echo "Error in: $dataEncoded \n<br>";
        echo $response . "\n<br>";
        echo "---\n<br>";
    }
    
    return $response;
}

/**
 * will returns filtered $row without columns which is not
 * mentioned in COLUMNS array
 */
function filter_columns(array $row) {
    return array_filter($row, function ($key) {
        return in_array($key, array_keys(COLUMNS));
    }, ARRAY_FILTER_USE_KEY);
}

/**
 * make arrays from columns which should be array, but is string
 * and remove empty columns
 */
function handle_special_columns(array $row) {
    $columns = array('phones', 'emails');

    // custom fields
    $row['custom_fields'] = array();
    $i = 1;
    while (isset($row['custom'.$i])) {
        $row['custom_fields'][] = (object)[
            'code' => COLUMNS_CUSTOM_FIELDS['custom'.$i],
            'value' => $row['custom'.$i]
        ];
        unset($row['custom'.$i]);
        $i++;
    }

    $row['phones'] = '';
    $i = 1;
    while (isset($row['phone'.$i])) {
        if (isset($row['phone'.$i]) && $row['phone'.$i] != '') {
            $row['phones'] .= $row['phone'.$i].',';
            unset($row['phone'.$i]);
        }
        $i++;
    }
    $row['phones'] = rtrim($row['phones'], ',');
    
    if (isset($row['name'])) {
        $name = explode(' ', $row['name'], 2);
        $row['firstname'] = $name[0];
        $row['lastname'] = @$name[1] ?: '';
    }
    
    if (isset($row['company_name'])) {
        //$row['company_id'] = get_company_id($row['company_name']);
        unset($row['company_name']);
    }

    foreach ($columns as $column) {
        if (isset($row[$column])) {
            $row[$column] = explode(',', str_replace(', ', ',', $row[$column]));
        }
    }
    
    foreach ($row as $key => $value) {
        if ($value == '' || $value == array('')) {
            unset($row[$key]);
        }
    }
    
    foreach (array('emails', 'phones') as $key) {
        if (isset($row[$key]) && !isset($row['description'])) {
            $row['description'] = $row[$key][0];
            break;
        }
    }
    
    return $row;
}

function get_company_id($company_name) {
    if ($company_name == '') {
        return '';
    }
    
    $filters = '{"name":"' . urlencode($company_name) . '"}';
    $response = @json_decode(send_request('/companies?_filters=' . $filters, 'GET'));
    
    if ($response == array()) {
        // company doesn't exist, create it
        return @json_decode(send_request("/companies", 'POST', array(
                'name' => $company_name,
                'date_created' => date('Y-m-d H:i:s', time()),
                'type' => 'V' 
        )))->id;
    }
    
    return $response[0]->id;
}

// array_combine problem fix:
function array_combine_special($a, $b, $pad = TRUE) {
    $acount = count($a);
    $bcount = count($b);
    // more elements in $a than $b but we don't want to pad either
    if (!$pad) {
        $size = ($acount > $bcount) ? $bcount : $acount;
        $a = array_slice($a, 0, $size);
        $b = array_slice($b, 0, $size);
    } else {
        // more headers than row fields
        if ($acount > $bcount) {
            $more = $acount - $bcount;
            // how many fields are we missing at the end of the second array?
            // Add empty strings to ensure arrays $a and $b have same number of elements
            $more = $acount - $bcount;
            for($i = 0; $i < $more; $i++) {
                $b[] = "";
            }
        // more fields than headers
        } else if ($acount < $bcount) {
            $more = $bcount - $acount;
            // fewer elements in the first array, add extra keys
            for($i = 0; $i < $more; $i++) {
                $key = 'extra_field_0' . $i;
                $a[] = $key;
            }

        }
    }

    return array_combine($a, $b);
}