<?php

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

const NELE_API_ROOT_URL = 'https://api.nextlevel.delivery/v1/';


function nele_custom_http_request_timeout( $time ): int {
	return 60;
}
add_filter( 'http_request_timeout', 'nele_custom_http_request_timeout');



function nele_api_request($url, $method, $payload, $creds, $headers=array(), $no_die = false, $content_type = 'application/json', $decode_response = true): ApiResponse
{
	$common_header = array(
		'app-id' => $creds->app_id,
		'app-secret' => $creds->app_secret,
		'Content-Type' => $content_type
	);
	$finalHeaders = array_merge($headers, $common_header);
	$args = array(
		'method'      => $method,
        'timeout'     => 60,
        'redirection' => 5,
        'httpversion' => '1.0',
        'blocking'    => true,
        'headers'     => $finalHeaders,
        'cookies'     => array(),
		'sslverify'   => false
	);
    if (! empty($payload)) {
        $payload = ($method === 'GET') ? $payload : json_encode($payload);
        $args['body'] = $payload;
    }
    $url = NELE_API_ROOT_URL . $url;
    write_log("URL:" . $url . ", payload:");
    write_log($payload);
	write_log($args);
	try {
		add_filter( 'http_request_timeout', 'nele_custom_http_request_timeout', PHP_INT_MAX - 1 );
		if ($method === 'GET') {
			$response = wp_remote_get($url, $args);
		} elseif ($method === 'POST') {
			$response = wp_remote_post($url, $args);
		} else {
			exit("Unsupported method specified: ".$method);
		}
	} finally {
		remove_filter( 'http_request_timeout', 'nele_custom_http_request_timeout', PHP_INT_MAX - 1 );
	}
	if (! $response) {
		$msg = "Error while accessing ".$url." (no response)";
		nele_add_db_error($msg);
        return new ApiResponse($msg, $no_die, true);
	} else if ( is_wp_error( $response ) ) {
		$msg = "Error while accessing ". $url . ", " . $response->get_error_message();
		nele_add_db_error($msg);
        return new ApiResponse($msg, $no_die, true);
	}

    if ($content_type === 'text/plain') {
		write_log("plain content type");
        if ((isset($response['code']) && $response['code'] !== 200) || (isset($response['response']['code']) && $response['response']['code'] !== 200)) {
	        write_log("plain and is ok");
			$msg = $response['body'];
			write_log($msg);
			nele_add_db_error($msg);
            return new ApiResponse($msg, $no_die, true);
        }
        return new ApiResponse($response['body'] ?? $response);
    }
    $decoded_body = wp_remote_retrieve_body( $response );
	$body = json_decode( $decoded_body );
//	write_log(json_encode($body, JSON_PRETTY_PRINT));

	if (isset($body->error)) {
        write_log("Error while accessing ".$url." (API returned error)");
		$msg = $body->error->message;
		nele_add_db_error($msg);
        return new ApiResponse($msg, $no_die, true);
	}
    if (! $decode_response) {
        return new ApiResponse($decoded_body);
    }
	return new ApiResponse($body);
}

function nele_api_init_install($creds, array $countries = array())
{
	global $wp_version;
    $payload = array(
        'platform' => "wordpress",
        'platform_version' => $wp_version,
        'plugin_version' => NELE_PLUGIN_VERSION,
        'domain' => wp_parse_url(home_url())['host'],
        'countries' => $countries,
    );
    nele_api_request( 'install', 'POST', $payload, $creds, array(), true );
}

function nele_api_exchange_rate($creds, $currency): float {
    $response = nele_api_request('rates/' . strtolower($currency), 'GET', array(), $creds);
    return $response->is_error || ! isset($response->msg->rate) ? 1 : $response->msg->rate;
}

/**
 * Return list of countries.
 *
 * @param $creds
 * @return array
 */
function nele_api_countries($creds): array
{
	$response = nele_api_request('countries', 'GET', array(), $creds);
	return $response->is_error ? array() : $response->msg;
}

/**
 * Return list of offices for the given country.
 *
 * @param $creds
 * @param string $country_id
 * @return array
 */
function nele_api_offices($creds, string $country_id): array
{
    $response = nele_api_request('offices/all?country_id='.$country_id, 'GET', array(), $creds);
    return $response->is_error ? array() : $response->msg;
}

/**
 * Return list of places withing the given country
 *
 * @param $creds
 * @param string $country_id
 * @return array
 */
function nele_api_places($creds, string $country_id): array
{
    $response = nele_api_request('cities/all?country_id='.$country_id, 'GET', array(), $creds);
    return $response->is_error ? array() : $response->msg;
}

/**
 * Return list of streets available.
 *
 * @param $creds
 * @param string $country_code
 * @return array
 */
function nele_api_streets($creds, string $country_code): array
{
    if(empty($country_code)){
        return array();
    }
    $response = nele_api_request('streets?country='.$country_code, 'GET', array(), $creds);
    return $response->is_error ? array() : $response->msg;
}

function nele_api_calculate_price($creds, $receiver_country, $receiver_place, $receiver_post_code, $weight, $courier, $receiver_office_id = '', $services = array()): ApiResponse {
    $payload = array('sender' => array('id' => $creds->sender_id, 'office_id' => 1, 'courier' => $courier),
        'receiver' => array('country' => $receiver_country, 'place' => $receiver_place),
        'weight' => round($weight, 3),
        'services' => $services);
    if (! empty($receiver_office_id)) {
        $payload['receiver']['office_id'] = $receiver_office_id;
    }
    if (! empty($receiver_post_code)) {
        $payload['receiver']['post_code'] = $receiver_post_code;
    }
    return nele_api_request('shipments/calculate', 'POST', $payload, $creds, array(), true);
}

/**
* Create new shipment
*/
function nele_api_create_shipment($creds, $courier, $receiver, $phone, $parcels, $payer, $currency, $included_shipping_price,
                                  $address_details, $order_id, $description, $contents, $declared_value = false, $option = 'OPEN',
                                  $return_shipment_payer = 'SENDER', $fragile = false, $email = null, $is_machine = false): ApiResponse {
    $payload = array(
		'sender' => array('id' => $creds->sender_id, 'office_id' => 1, 'courier' => $courier),
        'receiver' => array('name' => $receiver, 'phone' => $phone),
        'content' => array('parcels_count' => $parcels->count, 'contents' => $contents, 'weight' => $parcels->weight, 'package' => 'BOX'),
	    'payment' => array('payer' => $payer),
	    'services' => array('cod' => array('amount' => $parcels->price, 'currency' => $currency, 'processing_type' => 'CASH', 'included_shipping_price' => $included_shipping_price)),
        'ref' => $order_id,
        'ref2' => $description);

    if (! empty($email)) {
        $payload['receiver']['email'] = $email;
    }
    if (! empty($address_details->office_id)) {
        $payload['receiver']['office_id'] = $address_details->office_id;
    } else {
        $payload['receiver']['country'] = $address_details->country;
        $payload['receiver']['post_code'] = $address_details->post_code;
        $payload['receiver']['place'] = $address_details->place;
        if (! empty($address_details->street)) {
            $payload['receiver']['street'] = $address_details->street;
        }
        if (! empty($address_details->street_no)) {
            $payload['receiver']['street_no'] = $address_details->street_no;
        }
        if (! empty($address_details->complex)) {
            $payload['receiver']['complex'] = $address_details->complex;
        }
        if (! empty($address_details->block_no)) {
            $payload['receiver']['block_no'] = $address_details->block_no;
        }
        if (! empty($address_details->entrance_no)) {
            $payload['receiver']['entrance_no'] = $address_details->entrance_no;
        }
        if (! empty($address_details->floor_no)) {
            $payload['receiver']['floor_no'] = $address_details->floor_no;
        }
        if (! empty($address_details->apartment_no)) {
            $payload['receiver']['apartment_no'] = $address_details->apartment_no;
        }
    }
    if (! empty($parcels)) {
        $payload['content']['parcels'] = array();
        foreach ($parcels->items as $item) {
            $payload['content']['parcels'][] = array('number' => $item->id, 'weight' => $item->weight,
                'length' => $item->length, 'width' => $item->width, 'height' => $item->height);
        }
    }
    if ($is_machine === false) {
        $payload['services']['obpd'] = array('option' => $option, 'return_shipment_payer' => strtoupper($return_shipment_payer));
    }
    if ($declared_value === true) {
        $payload['services']['dv'] = array('amount' => $parcels->price, 'currency' => $currency);
        $payload['services']['cv'] = array('amount' => $parcels->price, 'currency' => $currency);
    }
    if ($fragile === true) {
        $payload['services']['fragile'] = true;
    }
    return nele_api_request('shipments', 'POST', $payload, $creds, array(), true);
}

/**
 * Get shipment info
 *
 * @param $creds
 * @param array $ids
 * @return array
 */
function nele_api_shipment_info($creds, array $ids): array {
    if(empty($ids)){
        return array();
    }
    $payload = array(
        "ids" => $ids
    );
    $response = nele_api_request('shipments/info', 'GET', $payload, $creds);
    return $response->is_error ? array() : $response->msg;
}

/**
 * Shipment tracking
 *
 * @param $creds
 * @param array $ids
 * @return array
 */
function nele_api_shipment_track($creds, array $ids): array {
    if(empty($ids)){
        return array();
    }
    $payload = array(
        "ids" => $ids
    );
    $response = nele_api_request('shipments/track', 'POST', $payload, $creds);
    return $response->is_error ? array() : $response->msg;
}

/**
 * Get shipment PDF label
 *
 * @param $creds
 * @param array $ids
 * @return ApiResponse
 */
function nele_api_shipment_pdf_bulk($creds, array $ids): ApiResponse {
    $payload = array(
        'ids'=> $ids
    );
    return nele_api_request('shipments/print', 'POST', $payload, $creds, array(), true, 'application/json', false);
}

/**
 * Get shipment PDF label
 *
 * @param $creds
 * @param string $id
 * @return ApiResponse
 */
function nele_api_shipment_pdf($creds, string $id): ApiResponse {
    return nele_api_request("shipments/$id/print", 'POST', array(), $creds, array(), true, 'text/plain');
}

/**
* Cancel shipment and destroy label
* 
* @param $creds
* @param string $id
*/
function nele_api_shipment_cancel($creds, string $id) {
    if (empty($id)) {
        return;
    }
    nele_api_request("shipments/$id/cancel", 'POST', array(), $creds, array(), true, 'text/plain');
}

/**
 * Confirm shipment will be given to courier
 *
 * @param $creds
 * @param array $ids
 * @return ApiResponse
 */
function nele_api_shipment_confirm($creds, array $ids): ApiResponse {
    $payload = array(
        "ids" => $ids
    );
    return nele_api_request('shipments/confirm', 'POST', $payload, $creds);
}
