<?php
/**
 * Send back deeplink-locations to Ovis-API
 * 
 */

/**
 * API location
 */
define('OVIS_DEEPLINK_REST_API_V1', 'https://api.ovis.nl/');

class ovis_deeplink {
	
	protected $wpdb;
	
	protected $_iMaxPageLevels = 10;				/** maximum number of page-levels to prevent memory overflow */
	
	protected $_iCurrentPageLevel = 0;
	
	protected $_oAvailableCategories = false;
	
	protected $_oAPICategories = false;
	
	private $_sAPIAuthenticationKey = false;
	
	
	protected $_aAPIUsers = false;

	/**
	 * init
	 * 
	 * @param handler $wpdb
	 * @return	void
	 */
	public function __construct($wpdb){
		
		$this->wpdb = $wpdb;
		
		$this->_oAvailableCategories = new \stdClass();
		$this->_oAvailableCategories->ovis = [ 'caravan', 'kampeerauto', 'stacaravan', 'vouwwagen', 'aanhangwagen' ];
		$this->_oAvailableCategories->boten = [ 'boot', 'motor', 'boottrailer' ];
		
		$this->_oAPICategories = new \stdClass();
		$this->_oAPICategories->ovis = [ 'caravan', 'camper', 'mobilehome', 'tenttrailer', 'trailer' ];
		$this->_oAPICategories->boat = [ 'boat', 'engine', 'boattrailer' ];
		
		$sSQL = "

		SELECT 

		OVIS_authentication

		FROM {$this->wpdb->prefix}ovis

		WHERE

		1=1

		AND ovis_id = 1
		
		LIMIT 1

		";		

		$aResults = $this->wpdb->get_results($sSQL);
		
		
		if(!empty($aResults[0]->OVIS_authentication)){
		
			$this->_sAPIAuthenticationKey = $aResults[0]->OVIS_authentication;
		
		}
	}

	/**
	 * debug logging
	 * 
	 * @param	$sMessage		string
	 */
	private function log($sMessage){

		if (is_scalar($sMessage)){
		
			print date('Y-m-d H:i:s') . ' - ' . $sMessage . PHP_EOL;
		
		} else {
		
			print date('Y-m-d H:i:s') . ' - ' . print_r($sMessage, true) . PHP_EOL;
			
		}

	}
	
	/**
	 * filter & select primary shortcodes per module
	 * 
	 * @param		array $aResults
	 * @return	array/bool
	 * 
	 */
	private function filter_shortcodes($aResults){
		
		if ($aResults === false || count($aResults) == 0){
			
			return false;
			
		}
		
		/**
		 * select primary shortcode
		 */
		
		$aModules = array_column(json_decode(json_encode($aResults), true), 'module');
		
		$aCategories = array_column(json_decode(json_encode($aResults), true), 'category');
		
		$aCategories = array_map('count', $aCategories);
		
		array_multisort($aModules, SORT_ASC, $aCategories, SORT_DESC, $aResults);
		
		
		$aFiltered = [];
		
		foreach($aResults as $oRecord){
			
			if (!isset($aFiltered[$oRecord->module])){
				
				$aFiltered[$oRecord->module] = $oRecord;
				
			}
			
		}
		
		if (count($aFiltered) == 0){
			
			return false;
			
		}
		
		return $aFiltered;
		
	}
	
	/**
	 * load all pages with ovis-plugin shortcodes to determine what the site-structure is.
	 * 
	 * @param		int			$iParentId
	 * @param		string	$sSlug
	 * @return	array/bool
	 * 
	 */
	private function load_shortcodes($iParentId = 0, $sSlug = ''){
	    
		/*
		
		$oMetaData = get_post_meta($oRecord->ID);
			
		print_R('<pre>');
		print_R($oMetaData);
		print_R('</pre>');

		exit;
		
		*/
		
		if ($iParentId == 0){
			
			$this->_iCurrentPageLevel = 0;
			
		}
		
		if ($this->_iCurrentPageLevel > $this->_iMaxPageLevels){
			
			return false;
			
		}
		
		$sSQL = "
		SELECT 
		ID,
		post_title,
		CAST(post_name AS CHAR(255)) AS slug,
		/* post_content, */
		TRIM(
				SUBSTRING(
						post_content,
						LOCATE('[ovis-voorraad', post_content),
						LOCATE('<!-- /wp:shortcode -->', post_content) - LOCATE('[ovis-voorraad', post_content)
				)
		) AS shortcode,

		TRIM(
				SUBSTRING(
						post_content,
						LOCATE('[ovis-voorraad', post_content),
						LOCATE('<!-- /wp:paragraph -->', post_content) - LOCATE('[ovis-voorraad', post_content)
				)
		) AS shortcode_paragraph
		FROM {$this->wpdb->prefix}posts
		WHERE
		1=1
		AND post_content LIKE '%[ovis-voorraad%'
		AND post_content NOT LIKE '%verhuur=\'ja\'%'
		AND post_parent = " . $iParentId . "
		AND post_status = 'publish'
		";
		
		$aResults = $this->wpdb->get_results($sSQL);
		
		if ($aResults === false || count($aResults) == 0){
		
			return false;
			
		}
		
		foreach($aResults as $iKey=>$oRecord){
			
			/**
			 * slug
			 */
			if (!empty($sSlug)){
			
				$oRecord->slug = $sSlug . '/' . $oRecord->slug;
				
			}
			
			$oRecord->shortcode = $this->to_object(trim(strip_tags($oRecord->shortcode)));
			
			$oRecord->shortcode_paragraph = $this->to_object(trim(strip_tags($oRecord->shortcode_paragraph)));
			
			/**
			 * pick standard shortcode or paragraph
			 */
			if (is_object($oRecord->shortcode) && !empty($oRecord->shortcode->tag)){
			
				unset($oRecord->shortcode_paragraph);
				
			}
			
			if (isset($oRecord->shortcode_paragraph) && is_object($oRecord->shortcode_paragraph) && !empty($oRecord->shortcode_paragraph->tag)){
			
				$oRecord->shortcode = $oRecord->shortcode_paragraph;
				
				unset($oRecord->shortcode_paragraph);
				
			}
			
			/**
			 * module / category cleanup
			 */
			$oRecord->module = 'ovis';
			
			$oRecord->category = $this->_oAvailableCategories->{$oRecord->module};
			
			if (isset($oRecord->shortcode->attributes) && is_array($oRecord->shortcode->attributes)){

				if (isset($oRecord->shortcode->attributes['module'])){
			
					$oRecord->module = $oRecord->shortcode->attributes['module'];
			
				}
			
				if (isset($oRecord->shortcode->attributes['categorie'])){
				
					$oRecord->category = explode(',', $oRecord->shortcode->attributes['categorie']);

				}
				
			}
			
			if ($oRecord->module == 'boten' && empty($oRecord->category)){
			
				$oRecord->category = $this->_oAvailableCategories->{$oRecord->module};
				
			}

			$oRecord->category = array_map('strtolower', $oRecord->category);

			$oRecord->category = array_map('trim', $oRecord->category);
			
			unset($oRecord->shortcode);
			
			/**
			 * next level
			 */
			
			$this->_iCurrentPageLevel++;
			
			// multilevel support
			//$oRecord->level = $this->load_shortcodes($oRecord->ID, $oRecord->slug);
			
			/**
			 * add to list
			 */
			
			$aResults[$iKey] = $oRecord;
			
		}

		return $aResults;
		
	}
	
	/**
	 * load all data of specified user
	 * 
	 * @return bool/array
	 * 
	 */
	private function load_remote_data(){

		$iItemsPerPage = 25; $aData = [];

		$oParams = new \stdClass();
		$oParams->useCache = false;
		$oParams->status = 'active';
		$oParams->category = $this->_oAPICategories->ovis;
		$oParams->simple = false;
		$oParams->page = 1;
		$oParams->itemsPerPage = $iItemsPerPage;
		$this->log('loading data');			

		$oClient = new restapi_client(OVIS_DEEPLINK_REST_API_V1, 'Authentication', $this->_sAPIAuthenticationKey);

		$oClient->post('/search/', $oParams);

		while (true){

			$oResult = $oClient->client_response_result();

			if (!is_object($oResult)){

				return false;

			}

			if (empty($oResult->result)){

				$this->log($oResult->errors);
				
				break 1;

			}
			
			/**
			 * users
			 */
			if ($this->_aAPIUsers === false && isset($oResult->data->clientUsers)){
			
				$this->_aAPIUsers = $oResult->data->clientUsers;
				
			}

			$iMaxPages = ceil($oResult->data->totalItems / $iItemsPerPage);

			$this->log('loading data - page: ' . $oParams->page . ' - total pages: ' . $iMaxPages);			
			
			if ($oParams->page > $iMaxPages){

				break 1;

			}

			foreach($oResult->data->data as $oRecord){
			
				if (!isset($oRecord->presentation) || !isset($oRecord->presentation->specifications)){
					
					continue 1;
					
				}
				
				$oItem = new \stdClass();
				$oItem->presentationId = $oRecord->presentation->id;
				$oItem->userId = $oRecord->presentation->userId;
				$oItem->realm = $oRecord->presentation->realm;
				$oItem->category = $oRecord->presentation->specifications->category;
				$oItem->new = boolval($oRecord->presentation->specifications->new);
				$oItem->brand = $oRecord->presentation->specifications->brand;
				$oItem->brandDisplay = $oRecord->presentation->specifications->brandDisplay;
				$oItem->model = $oRecord->presentation->specifications->model;
				$oItem->modelDisplay = $oRecord->presentation->specifications->modelDisplay;
				$oItem->version = $oRecord->presentation->specifications->version;
				$oItem->modelVersion = $oRecord->presentation->specifications->modelVersion;
				$oItem->title = $oRecord->presentation->specifications->title;
				
				$aData[$oRecord->presentation->userId][$oRecord->presentation->id] = $oItem;

			}

			$oParams->page++;
			
			if ($oParams->page > $iMaxPages){
				
				break 1;
				
			}

			$oClient->post('/search/', $oParams);

		}		

		return $aData;
		
	}
	
	/**
	 * build payload
	 * 
	 * @param int		$iUserId
	 * @param array $aUserData
	 * @param array $aShortCodes
	 * @return	bool/object
	 * 
	 */
	private function build_payload($iUserId, $aUserData, $aShortCodes){
		
		$oPayload = new \stdClass();
		$oPayload->userId = intval($iUserId);
		$oPayload->deeplinks = [];
		
		$sDomain = get_option('home');
		
		if (empty($sDomain)){
			
			$this->log('wordpress error: domain not set!');
			
			return false;
			
		}
		
		foreach ($aUserData as $oRecord){
			
			if (!isset($aShortCodes[$oRecord->realm])){
				
				/** no shortcode available for this module */
				
				continue 1;
				
			}

			$sUrl = rtrim($sDomain, '/') . '/' . $aShortCodes[$oRecord->realm]->slug . '/details/' . $oRecord->category . '/' . $oRecord->presentationId . '-' . sanitize_title($oRecord->title) . '.html';
			
			if (filter_var($sUrl, FILTER_VALIDATE_URL, FILTER_FLAG_PATH_REQUIRED) == false){
			
				$this->log('invalid url: ' . $sUrl);
				
				continue 1;
				
			}
			
			$oLink = new \stdClass();
			$oLink->presentationId = $oRecord->presentationId;
			$oLink->url = $sUrl;
			
			$oPayload->deeplinks[] = $oLink;
			
		}

		if (count($oPayload->deeplinks) == 0){
			
			$this->log('no deeplinks available');
			
			return false;
			
		}
		
		return $oPayload;
		
	}
	
	/**
	 * start processing
	 * 
	 * @return	bool
	 * 
	 */
	public function parse(){
		
		if(empty($this->_sAPIAuthenticationKey)){
			
			$this->log('no apikey available');
		

			return false;
		}

		$aShortCodes = $this->load_shortcodes();
		
		if ($aShortCodes === false){

			$this->log('no shortcodes available');
			
			return false;
			
		}
		
		$aShortCodes = $this->filter_shortcodes($aShortCodes);
		
		if ($aShortCodes === false){

			$this->log('no filtered shortcodes available');
			
			return false;
			
		}
		
		$this->log('loading remote data');

		$aData = $this->load_remote_data();
		
		if ($aData === false || count($aData) == 0){
		
			$this->log('no data available');
			
			return false;
			
		}
		
		foreach($aData as $iUserId=>$aUserData){
			
			$oPayload = $this->build_payload($iUserId, $aUserData, $aShortCodes);
			
			if ($oPayload === false){
				
				continue 1;
				
			}
			
			$this->to_api($oPayload);
			
		}
		
	}
	
	/**
	 * send to ovis api
	 * 
	 * @param		object	$oPayload
	 * @return	bool
	 * 
	 */
	private function to_api($oPayload){
		
		$oClient = new restapi_client(OVIS_DEEPLINK_REST_API_V1, 'Authentication', $this->_sAPIAuthenticationKey);
		
		$oClient->post('/search/deeplink/', $oPayload);
		
		$oResult = $oClient->client_response_result();
		
		if (empty($oResult->result)){
			
			if (isset($oResult->message)){
			
				$this->log($oResult->message);
				
			}
			
			if (isset($oResult->errors)){
			
				$this->log(implode(', ', $oResult->errors));
				
			}
			
			return false;
			
		}

		$this->log('deeplinks succesfully posted');
		
		return true;
		
	}
		
	/**
	 * convert short-code to object
	 * 
	 * @param		string	$sData
	 * @return	bool/object
	 * 
	 */
	private function to_object($sData){
		
		$aMatches = []; $aTagMatch = [];
		
		preg_match('/\[(\S+)/', $sData, $aTagMatch);
		
		$sTagName = $aTagMatch[1] ?? null;
		
		if (!is_null($sTagName)){
		
			$sTagName = str_replace(']', '', $sTagName);
			
		}

		preg_match_all("/(\w+)='([^']*)'/", $sData, $aMatches, PREG_SET_ORDER);

		$aAttributes = [];
		
		foreach ($aMatches as $match){
			
			$aAttributes[$match[1]] = $match[2];
			
		}

		$aResult = [ 'tag' => $sTagName, 'attributes' => $aAttributes ];

		if (empty($sTagName)){
			
			return false;
			
		}
		
		return (object) $aResult;			
		
	}
	
}