<?php
/**
 * @package freeSmsForWoocommerce
 * @version 1.0.0
 */
/*
Plugin Name:			Free SMS for WooCommerce
Plugin URI:				https://smsforwoocommerce.gitlab.io
Description:			Send WooCommerce SMS notifications from your Android phone
Author: 					Bartosz Juriewicz
Requires PHP:			5.6
Version:					1.0.0
License:					GPL v2 or later
License URI:			https://www.gnu.org/licenses/gpl-2.0.html
*/

/*****************************
* More detailed description: *
******************************
*
* This plugin (with help of dedicated open-source Android app) allows to send SMS notifications
* from user's phone, when WooCommerce order status changes. It uses the external service to communicate with
* mobile devices with Google GCM messaging. You can replace this service with your own one.
* Check out the plugin's website for more detail.
*/

if ( is_readable( __DIR__ . '/vendor/autoload.php' ) ) {
	require __DIR__ . '/vendor/autoload.php';
}

$SMSFWC_AVAILABLE_HOOKS = [ 
	'woocommerce_order_status_completed' => 'Order status changed to Completed',
	'woocommerce_order_status_pending' => 'Order status changed to Pending',
	'woocommerce_order_status_failed' => 'Order status changed to Failed',
	'woocommerce_order_status_on-hold' => 'Order status changed to On-Hold',
	'woocommerce_order_status_processing' => 'Order status changed to Processing',
	'woocommerce_order_status_refunded' => 'Order status changed to Refunded',
	'woocommerce_order_status_cancelled' => 'Order status changed to Cancelled'
];
$SMSFWC_INIT_SETTINGS = '{ "registeredHooks": [], "token": "" }';
$SMSFWC_AVAILABLE_VARIABLES = [
	'status', 'currency', 'date_created_date', 'date_modified_date', 'total', 'billing_first_name',
    'billing_last_name', 'billing_company', 'billing_address_1', 'billing_address_2', 'billing_city', 'billing_state', 
    'billing_postcode', 'billing_country', 'billing_email',  'billing_phone',
    'shipping_first_name', 'shipping_last_name', 'shipping_company', 'shipping_address_1', 'shipping_address_2', 
    'shipping_city', 'shipping_state', 'shipping_postcode', 'shipping_country', 'payment_method_title', 'order_key'
];

$SMSFWC_TEST_VARIABLES = ['status' => 'completed', 'currency' => 'USD', 'date_created_date' => '2020-10-24', 'date_modified_date' => '2020-10-24', 'total' => '2', 'billing_first_name' => 'John', 'billing_last_name' => 'Doe', 'billing_company' => 'ACME', 'billing_address_1' => 'Wall Street', 'billing_address_2' => 24/14, 'billing_city' => 'New York', 'billing_state' => 'New York',  'billing_postcode' => '43-345', 'billing_country' => 'USA', 'billing_email' => 'jdoe@gmail.com',  'billing_phone' => '543234543', 'shipping_first_name' => 'Jane', 'shipping_last_name' => 'Doe', 'shipping_company' => 'ACME', 'shipping_address_1', 'shipping_address_2', 'shipping_city' => 'New York', 'shipping_state' => 'NY', 'shipping_postcode' => '123-54', 'shipping_country' => 'USA', 'payment_method_title' => 'CASH'];

/*
* if you want to use your own service, replace this URL with your own. 
* Check the https://smsforwoocommerce.gitlab.io FAQ for more info
*/
$SMSFWC_SEND_MESSAGE_URL = 'https://us-central1-sms-sender-e5fb3.cloudfunctions.net/sendMessage';

/*
* ACTIVATION HOOK
*/
register_activation_hook( __FILE__, 'smsfwc_plugin_activated' );
function smsfwc_plugin_activated() {
	$settingsJson = get_option('smsfwc_settings', '{ "registeredHooks": [], "token": "" }');
	$settings = json_decode($settingsJson);
	if(empty($settings->token)) {
		$settings->token = md5(uniqid(rand(), true));
		update_option('smsfwc_settings', wp_json_encode($settings));
	}
}

/*
* UNINSTALL HOOK
*/
register_uninstall_hook(__FILE__, 'smsfwc_plugin_uninstalled');
function smsfwc_plugin_uninstalled() {
	delete_option('smsfwc_settings');
}

/*
* enqueue scripts
*/
add_action('admin_enqueue_scripts','smsfwc_scripts');
function smsfwc_scripts($hook) {
	global $SMSFWC_AVAILABLE_HOOKS, $SMSFWC_INIT_SETTINGS;
	//run only on plugin config page
	$settingsJson = get_option('smsfwc_settings', $SMSFWC_INIT_SETTINGS);
	$settings = json_decode($settingsJson);

	if($GLOBALS['pageHook'] === $hook) {
		wp_enqueue_script( 'qrcodes', plugins_url( '/js/qrcodes.js', __FILE__ ));
		wp_enqueue_script( 'app', plugins_url( '/js/app.js', __FILE__ ));
		wp_localize_script( 'app', 'bundle', array( 
			'token' => $settings->token,
			'pluginUrl' => plugins_url( '', __FILE__ )
		));
	}
}



/*
* admin menu entry
*/
add_action('admin_menu', 'smsfwc_addPluginAdminMenu', 9);
function smsfwc_addPluginAdminMenu() {
	$page_title = 'Free SMS for WooCommerce';
	$menu_title = 'Free SMS for WooCommerce';
	$capability = 'manage_options';
	$menu_slug  = 'free-sms';
	$function   = 'smsfwc_adminPage';
	$icon_url   = 'dashicons-buddicons-pm';
	$position   = 7;
	$GLOBALS['pageHook'] = add_menu_page( $page_title, $menu_title, $capability, $menu_slug, $function, $icon_url, $position );
}

/*
* ADMIN PANEL PAGE
*/
function smsfwc_adminPage() {
	global $SMSFWC_AVAILABLE_HOOKS, $SMSFWC_INIT_SETTINGS, $SMSFWC_AVAILABLE_VARIABLES;
	if (!current_user_can('manage_options')) {
		wp_die('Unauthorized user');
	}
	
	$settingsJson = get_option('smsfwc_settings', $SMSFWC_INIT_SETTINGS);
	$settings = json_decode($settingsJson);
	$editedHook = null;
	
	//handle POST form submits
	if (isset($_POST['addHook'])) {
		smsfwc_handleAddHookFormSubmit($settings);
	}
	if (isset($_POST['remove'])) {
		smsfwc_handleHookRemove($settings);
	}
	if (isset($_POST['edit'])) {
		smsfwc_handleHookEdit($settings, $editedHook);
	}
	if (isset($_POST['test'])) {
		smsfwc_handleTestMessageSubmit($settings);
	}


	include 'page.php';

}

/*
* EDIT message template
*/
function smsfwc_handleHookEdit($settings, &$editedHook) {
	check_admin_referer('submit_edit_nonce');
	$index = intval($_POST['index']);
	$editedHook = $settings->registeredHooks[$index];
	$editedHook->index = $index;
}

/*
* REMOVE message template
*/
function smsfwc_handleHookRemove(&$settings) {
	check_admin_referer('submit_remove_nonce');
	$index = intval($_POST['index']);
	array_splice($settings->registeredHooks, $index, 1);
	update_option('smsfwc_settings', wp_json_encode($settings));
}

/*
* UPSERT new message template
*/
function smsfwc_handleAddHookFormSubmit(&$settings) {
	global $SMSFWC_AVAILABLE_HOOKS;
	check_admin_referer('submit_wc_hook_nonce');

	$phoneUtil = \libphonenumber\PhoneNumberUtil::getInstance();
	$regions = $phoneUtil->getSupportedRegions();

	//validate
	$hookName = sanitize_text_field($_POST['hookName']);	
	if (!array_key_exists($hookName, $SMSFWC_AVAILABLE_HOOKS)) return;
	$regionCode = sanitize_text_field($_POST['regionCode']);
	if (empty($regionCode) || !in_array($regionCode, $regions)) return;
	$message = !empty($_POST['message']) ? sanitize_text_field($_POST['message']) : 'empty message';
	$newHook = (object) ['hookName' => $hookName, 'message' => $message, 'regionCode' => $regionCode];

	//update
	if (isset($_POST['index'])) {
		$index = intval($_POST['index']);
		array_splice($settings->registeredHooks, $index, 1, array($newHook));
	} else {
		//insert
		$settings->registeredHooks[] = $newHook;
	}
	update_option('smsfwc_settings', wp_json_encode($settings));
}

/*
* sent test message
*/
function smsfwc_handleTestMessageSubmit(&$settings) {
	global $SMSFWC_AVAILABLE_HOOKS, $SMSFWC_TEST_VARIABLES;
	check_admin_referer('submit_test_nonce');
	$phoneNumber = sanitize_text_field($_POST['testPhone']);
	$action = sanitize_text_field($_POST['testHookNameSelect']);

	$result = null;
	$messagesSent = 0;
	foreach($settings->registeredHooks as $h) {
		if ($h->hookName == $action) {
			$phone = smsfwc_tryParsePhone($phoneNumber, $h->regionCode);
			if (empty($phone)) {
				continue;
			}
			$parsedMessage = smsfwc_parseMessage($h->message, $SMSFWC_TEST_VARIABLES);
			$result = smsfwc_sendPOSTRequest($parsedMessage, $phone, $settings->token);
			if ($result == 'not_registered') {
				wp_redirect('?page=free-sms&test_not_registered=1');
				exit;
			}
			$messagesSent++;
		}
	}
	if ($messagesSent > 0) {
		wp_redirect('?page=free-sms&test_success=1');
	} else {
		wp_redirect('?page=free-sms&test_no_match=1');
	}
	exit;
}

/*
* REGISTER WC HOOKS
*/
add_action( 'woocommerce_order_status_changed', 'smsfwc_statusChanged', 10, 1 );
function smsfwc_statusChanged($orderId) {
	global $SMSFWC_INIT_SETTINGS;
	$settingsJson = get_option('smsfwc_settings', $SMSFWC_INIT_SETTINGS);
	$settings = json_decode($settingsJson);
	if (empty($settings->token) || empty($settings->registeredHooks)) {
		return;
	}

	$order = wc_get_order($orderId);
	$currentHook = 'woocommerce_order_status_' . $order->get_status();

	foreach($settings->registeredHooks as $h) {
		if ($h->hookName == $currentHook) {
			$phone = smsfwc_tryParsePhone($order->get_billing_phone(), $h->regionCode);
			if (empty($phone)) {
				continue;
			}
			$parsedMessage = smsfwc_parseMessage($h->message, smsfwc_prepareOrderVariables($order));
			smsfwc_sendPOSTRequest($parsedMessage, $phone, $settings->token);
			break;
		}
	}

}


/*
* HELPER FUNCTIONS
*/

//squash and format dates
function smsfwc_prepareOrderVariables($order) {
	$order_data = $order->get_data();
	$squashed = smsfwc_squash($order_data);
	foreach($squashed as $key => $value) {
		if (strpos($key, 'date') !== false && !empty($value)) {
			$squashed[$key] = date("d-m-y", strtotime($value));
		}
	}
	return $squashed;	
}

/*
* replace message variables with values
*/
function smsfwc_parseMessage($message, $preparedOrder) {
	global $SMSFWC_AVAILABLE_VARIABLES;
	foreach($SMSFWC_AVAILABLE_VARIABLES as $v) {
		$message = str_replace(':'.$v, $preparedOrder[$v], $message);
	}
	return $message;
}

/*
* if $number is valid for $regionCode, return it in E164.
*/
function smsfwc_tryParsePhone($phone, $regionCode) {
	$phoneUtil = \libphonenumber\PhoneNumberUtil::getInstance();
	try {
			$parsedNumber = $phoneUtil->parse($phone, $regionCode);
			$isValid = $phoneUtil->isValidNumberForRegion($parsedNumber, $regionCode);
			return $isValid ? $phoneUtil->format($parsedNumber, \libphonenumber\PhoneNumberFormat::E164) : NULL;
	} catch (\libphonenumber\NumberParseException $e) {
			return NULL;
	}
}

/*
* Send request to the server that will send Firebase GCM message to mobile device.
* Replace SMSFWC_SEND_MESSAGE_URL with your own server URL if you want to handle this on your own.
* Check https://smsforwoocommerce.gitlab.io/ for more info
*/
function smsfwc_sendPOSTRequest($message, $phone, $token) {
	global $SMSFWC_SEND_MESSAGE_URL;

	$body = array(
    'message' => $message,
		'phone' => $phone,
		'qrToken' => $token
	);

	$args = array(
    'body'        => $body,
    'timeout'     => '5',
    'redirection' => '5',
    'httpversion' => '1.0',
    'blocking'    => true,
    'headers'     => array(),
    'cookies'     => array(),
	);

	$response = wp_remote_post($SMSFWC_SEND_MESSAGE_URL, $args);

	return $response;
}

/*
* Flatten json, replacing dots with $sep separator
*/
function smsfwc_squash($array, $prefix = '') {
    $flat = array();
    $sep = "_";    
    if (!is_array($array)) $array = (array)$array;
    foreach($array as $key => $value) {
        $_key = ltrim($prefix.$sep.$key, $sep);        
        if (is_array($value) || is_object($value)) {
            // Iterate this one too
            $flat = array_merge($flat, smsfwc_squash($value, $_key));
        }
        else {
            $flat[$_key] = $value;
        }
    }
    return $flat;
}
