<?php
/**
 * Class Portal_ConvoBotWidget
 * @deprecated 
 */
class Portal_ConvoBotWidget extends Extension_CommunityPortal {
	const PARAM_BOT_NAME = 'bot_name';
	const PARAM_CORS_ALLOW_ORIGIN = 'cors_allow_origin';
	const PARAM_INTERACTION_BEHAVIOR_ID = 'interaction_behavior_id';
	const PARAM_PAGE_CSS = 'page_css';
	const PARAM_PAGE_HIDE_ICON = 'page_hide_icon';
	const PARAM_PAGE_TITLE = 'page_title';
	
	private $_config = null;
	
	private function getConfig() {
		if(is_null($this->_config)) {
			$portal_code = ChPortalHelper::getCode();
			$this->_config = DAO_CommunityToolProperty::getAllByTool($portal_code);
		}
		
		return $this->_config;
	}
	
	/**
	 * @param DevblocksHttpRequest $request
	 * @return DevblocksHttpResponse
	 */
	public function handleRequest(DevblocksHttpRequest $request) {
		$config = $this->getConfig();
		
		DevblocksPlatform::services()->http()
			->setHeader('Content-Security-Policy', '')
		;
		
		if(isset($config[self::PARAM_CORS_ALLOW_ORIGIN])) {
			$origin = $config[self::PARAM_CORS_ALLOW_ORIGIN] ?: '*';
			
			DevblocksPlatform::services()->http()
				->setHeader('Access-Control-Allow-Origin', $origin)
				->setHeader('Access-Control-Allow-Credentials', 'true')
			;
		}
	}
	
	public function writeResponse(DevblocksHttpResponse $response) {
		$path = $response->path;
		$stack = array_shift($path);
		
		$portal_code = ChPortalHelper::getCode();
		$config = $this->getConfig();
		
		switch($stack) {
			case 'interaction':
				$action = array_shift($path);
				
				switch($action) {
					case 'start':
						$id = DevblocksPlatform::importGPC($_REQUEST['id'] ?? null, 'string', '');
						$browser = DevblocksPlatform::importGPC($_REQUEST['browser'] ?? null, 'array', []);
						$interaction_params = DevblocksPlatform::importGPC($_REQUEST['params'] ?? null, 'array', []);

						$interaction_behavior_id = $config[self::PARAM_INTERACTION_BEHAVIOR_ID] ?? null;
						$bot_name = ($config[self::PARAM_BOT_NAME] ?? null) ?: 'Cerb';
						
						// [TODO] We have their whole session here
						// [TODO] Be able to remember things about their session
						$umsession = ChPortalHelper::getSession();
						
						if(
							!$interaction_behavior_id
							|| false == ($interaction_behavior = DAO_TriggerEvent::get($interaction_behavior_id))
							|| $interaction_behavior->event_point != Event_NewInteractionChatPortal::ID
						)
							return false;
						
						// Start the session using the behavior
						
						$actions = [];
						
						$client_ip = DevblocksPlatform::getClientIp();
						$client_platform = '';
						$client_browser = '';
						$client_browser_version = '';
						$client_url = @$browser['url'] ?: '';
						$client_time = @$browser['time'] ?: '';
						
						if(null != ($client_user_agent_parts = DevblocksPlatform::getClientUserAgent())) {
							$client_platform = @$client_user_agent_parts['platform'] ?: '';
							$client_browser = @$client_user_agent_parts['browser'] ?: '';
							$client_browser_version = @$client_user_agent_parts['version'] ?: '';
						}
						
						$event_model = new Model_DevblocksEvent(
							Event_NewInteractionChatPortal::ID,
							array(
								'portal_code' => $portal_code,
								'interaction' => $id,
								'interaction_params' => $interaction_params,
								'cookie' => $umsession->session_id,
								'client_browser' => $client_browser,
								'client_browser_version' => $client_browser_version,
								'client_ip' => $client_ip,
								'client_platform' => $client_platform,
								'client_time' => $client_time,
								'client_url' => $client_url,
								'actions' => &$actions,
							)
						);
						
						if(false == ($event = $interaction_behavior->getEvent()))
							return;
							
						$event->setEvent($event_model, $interaction_behavior);
						
						$values = $event->getValues();
						
						$dict = DevblocksDictionaryDelegate::instance($values);
						
						$result = $interaction_behavior->runDecisionTree($dict, false, $event);
						
						//$dict->scrubKeys('__trigger');
						//$dict->scrubKeys('_cached_contexts');
						//$dict->scrubKeys('_null');
						
						$behavior_id = null;
						$dict = null;
						
						foreach($actions as $action) {
							switch($action['_action']) {
								case 'behavior.switch':
									if(isset($action['behavior_id'])) {
										$behavior_id = $action['behavior_id'] ?? null;
										$variables = $action['behavior_variables'] ?? null;
										
										if(is_array($variables))
										foreach($variables as $k => $v) {
											$dict[$k] = $v;
										}
									}
									break;
							}
						}
						
						if(
							!$behavior_id 
							|| false == ($behavior = DAO_TriggerEvent::get($behavior_id))
							|| $behavior->event_point != Event_NewMessageChatPortal::ID
							)
							return;
							
						$bot = $behavior->getBot();
						
						$session_data = [
							//'actor' => ['context' => CerberusContexts::CONTEXT_WORKER, 'id' => $active_worker->id],
							'bot_name' => $bot_name, // [TODO] Configurable
							'bot_image' => null, // [TODO] Configurable
							'behavior_id' => $behavior->id,
							'behaviors' => [
								$behavior->id => [
									'dict' => $dict,
								]
							],
							'cookie' => $umsession->session_id,
							'portal_code' => $portal_code,
							'interaction' => $id,
							'interaction_params' => $interaction_params,
							'client_browser' => $client_browser,
							'client_browser_version' => $client_browser_version,
							'client_ip' => $client_ip,
							'client_platform' => $client_platform,
							'client_time' => $client_time,
							'client_url' => $client_url,
						];
						
						$session_id = DAO_BotSession::create([
							DAO_BotSession::SESSION_DATA => json_encode($session_data),
							DAO_BotSession::UPDATED_AT => time(),
						]);
						
						$tpl = DevblocksPlatform::services()->template();
						
						$tpl->assign('bot_name', $bot_name);
						$tpl->assign('session_id', $session_id);
						
						$tpl->display('devblocks:cerb.bots.portal.widget::widget/window.tpl');
						break;
						
					case 'message':
						$session_id = DevblocksPlatform::importGPC($_POST['session_id'] ?? null, 'string', '');
						$message = DevblocksPlatform::importGPC($_POST['message'] ?? null, 'string', '');
						
						$tpl = DevblocksPlatform::services()->template();
						
						// Load the session
						if(!($interaction = DAO_BotSession::get($session_id)))
							return false;
						
						// [TODO] Verify session ownership
						// [TODO] What happens if we're chatting to a dead session? Open a new one?
				
						// Load our default behavior for this interaction
						if(false == (@$behavior_id = $interaction->session_data['behavior_id']))
							return false;
						
						if(false == (@$bot_name = $interaction->session_data['bot_name']))
							$bot_name = 'Cerb';
						
						$actions = [];
						
						if(!($behavior = DAO_TriggerEvent::get($behavior_id)))
							return;
						
						$event_params = [
							'message' => $message,
							'actions' => &$actions,
								
							'bot_name' => $bot_name,
							'bot_image' => $interaction->session_data['bot_image'] ?? null,
							'behavior_id' => $behavior_id,
							'behavior_has_parent' => $interaction->session_data['behavior_has_parent'] ?? null,
							'cookie' => $interaction->session_data['cookie'] ?? null,
							'portal_code' => $interaction->session_data['portal_code'] ?? null,
							'interaction' => $interaction->session_data['interaction'] ?? null,
							'interaction_params' => $interaction->session_data['interaction_params'] ?? null,
							'client_browser' => $interaction->session_data['client_browser'] ?? null,
							'client_browser_version' => $interaction->session_data['client_browser_version'] ?? null,
							'client_ip' => $interaction->session_data['client_ip'] ?? null,
							'client_platform' => $interaction->session_data['client_platform'] ?? null,
							'client_time' => $interaction->session_data['client_time'] ?? null,
							'client_url' => $interaction->session_data['client_url'] ?? null,
						];
						
						$event_model = new Model_DevblocksEvent(
							Event_NewMessageChatPortal::ID,
							$event_params
						);
						
						if(false == ($event = Extension_DevblocksEvent::get($event_model->id, true)))
							return;
						
						if(!($event instanceof Event_NewMessageChatPortal))
							return;
							
						$event->setEvent($event_model, $behavior);
						
						$values = $event->getValues();
						
						// Are we resuming a scope?
						$resume_dict = @$interaction->session_data['behaviors'][$behavior->id]['dict'];
						if($resume_dict) {
							$values = array_replace($values, $resume_dict);
						}
						
						$dict = new DevblocksDictionaryDelegate($values);
							
						$resume_path = $interaction->session_data['behaviors'][$behavior->id]['path'] ?? null;
						
						if($resume_path) {
							$behavior->prepareResumeDecisionTree($message, $interaction, $actions, $dict, $resume_path);
							
							if(false == ($result = $behavior->resumeDecisionTree($dict, false, $event, $resume_path)))
								return;
							
						} else {
							if(false == ($result = $behavior->runDecisionTree($dict, false, $event)))
								return;
						}
						
						$values = $dict->getDictionary(null, false);
						$values = array_diff_key($values, $event->getValues());
						
						// Hibernate
						if($result['exit_state'] == 'SUSPEND') {
							// Keep everything as it is
							DevblocksPlatform::noop();
							
						} else {
							// Start the tree over
							$result['path'] = [];
							
							// Return to the caller if we have one
							$callers = $interaction->session_data['callers'] ?? [];
							$caller = array_pop($callers);
							$interaction->session_data['behavior_has_parent'] = !empty($callers) ? 1 : 0;
							$caller_result_key = $caller['result'] ?? '_behavior';
							
							if(is_array($caller)) {
								$caller_behavior_id = $caller['behavior_id'];
								
								if($caller_behavior_id && isset($interaction->session_data['behaviors'][$caller_behavior_id])) {
									$interaction->session_data['behavior_id'] = $caller_behavior_id;
									$interaction->session_data['behaviors'][$caller_behavior_id]['dict'][$caller_result_key] = $values;
								}
								
								$tpl->display('devblocks:cerb.bots.portal.widget::widget/convo/prompt_wait.tpl');
							}
							
							// [TODO] If we don't have a caller, the chat should end.
						}
						
						$interaction->session_data['behaviors'][$behavior->id]['dict'] = $values;
						$interaction->session_data['behaviors'][$behavior->id]['path'] = $result['path'];
						
						if(false == ($bot = $behavior->getBot()))
							return;
						
						$tpl->assign('bot', $bot);
						$tpl->assign('bot_name', $bot_name);
						
						foreach($actions as $params) {
							// Are we handling the next response message in a special way?
							if(isset($params['_prompt']) && is_array($params['_prompt'])) {
								$interaction->session_data['_prompt'] = $params['_prompt'];
							}
							
							switch(@$params['_action']) {
								case 'behavior.switch':
									$variables = $params['behavior_variables'] ?? null;
									$var_key = ($params['var'] ?? null) ?: '_behavior';
									
									if(!isset($interaction->session_data['callers']))
										$interaction->session_data['callers'] = [];
									
									$interaction->session_data['callers'][] = [
										'behavior_id' => $behavior->id,
										'return' => $var_key,
									];
									
									if(false == ($behavior_id = @$params['behavior_id']))
										break;
										
									if(false == ($new_behavior = DAO_TriggerEvent::get($behavior_id)))
										break;
									
									if($new_behavior->event_point != Event_NewMessageChatPortal::ID)
										break;
									
									if(!Context_TriggerEvent::isReadableByActor($new_behavior, $bot))
										break;
									
									$bot = $new_behavior->getBot();
									$tpl->assign('bot', $bot);
									
									$new_dict = [];
									
									if(is_array($variables))
									foreach($variables as $k => $v) {
										$new_dict[$k] = $v;
									}
									
									$interaction->session_data['behavior_id'] = $new_behavior->id;
									$interaction->session_data['behavior_has_parent'] = 1;
									$interaction->session_data['behaviors'][$new_behavior->id]['dict'] = $new_dict;
									$interaction->session_data['behaviors'][$new_behavior->id]['path'] = [];
									
									// [TODO] Can this be implied better?
									$tpl->assign('delay_ms', 0);
									$tpl->display('devblocks:cerb.bots.portal.widget::widget/convo/prompt_wait.tpl');
									break;
									
								case 'emote':
									if(false == ($emote = @$params['emote']))
										break;
									
									$tpl->assign('emote', $emote);
									$tpl->assign('delay_ms', 500);
									$tpl->display('devblocks:cerb.bots.portal.widget::widget/convo/emote.tpl');
									break;
								
								case 'prompt.buttons':
									$options = $params['options'] ?? null;
									$color_from = $params['color_from'] ?? null;
									$color_to = $params['color_to'] ?? null;
									$color_mid = $params['color_mid'] ?? null;
									$style = $params['style'] ?? null;
									
									if(!is_array($options))
										break;
									
									$tpl->assign('options', $options);
									$tpl->assign('color_from', $color_from);
									$tpl->assign('color_to', $color_to);
									$tpl->assign('color_mid', $color_mid);
									$tpl->assign('style', $style);
									$tpl->assign('delay_ms', 250);
									
									$tpl->display('devblocks:cerb.bots.portal.widget::widget/convo/prompt_buttons.tpl');
									break;
									
								case 'prompt.images':
									$images = $params['images'] ?? null;
									$labels = $params['labels'] ?? null;
									
									if(!is_array($images) || !is_array($images))
										break;
									
									$tpl->assign('images', $images);
									$tpl->assign('labels', $labels);
									$tpl->assign('delay_ms', 0);
									$tpl->display('devblocks:cerb.bots.portal.widget::widget/convo/prompt_images.tpl');
									break;
								
								case 'prompt.rating.number':
									$options = $params['options'] ?? null;
									
									if(!is_array($options))
										break;
									
									$tpl->assign('options', $options);
									$tpl->assign('delay_ms', 0);
									
									$tpl->display('devblocks:cerb.bots.portal.widget::widget/convo/prompt_rating_number.tpl');
									break;
									
								case 'prompt.text':
									$placeholder = $params['placeholder'] ?? null;
									$default = $params['default'] ?? null;
									$mode = $params['mode'] ?? null;
									
									if(empty($placeholder))
										$placeholder = 'say something';
									
									$tpl->assign('delay_ms', 0);
									$tpl->assign('placeholder', $placeholder);
									$tpl->assign('default', $default);
									$tpl->assign('mode', $mode);
									$tpl->display('devblocks:cerb.bots.portal.widget::widget/convo/prompt_text.tpl');
									break;
									
								case 'prompt.wait':
									$tpl->assign('delay_ms', 0);
									$tpl->display('devblocks:cerb.bots.portal.widget::widget/convo/prompt_wait.tpl');
									break;
									
								case 'message.send':
									if(false == ($msg = @$params['message']))
										break;
									
									$delay_ms = DevblocksPlatform::intClamp(@$params['delay_ms'], 0, 10000);
									
									$tpl->assign('message', $msg);
									$tpl->assign('format', @$params['format']);
									$tpl->assign('delay_ms', $delay_ms);
									$tpl->display('devblocks:cerb.bots.portal.widget::widget/convo/message.tpl');
									break;
									
								case 'script.send':
									if(false == ($script = @$params['script']))
										break;
										
									$tpl->assign('script', $script);
									$tpl->assign('delay_ms', 0);
									$tpl->display('devblocks:cerb.bots.portal.widget::widget/convo/script.tpl');
									break;
									
								case 'window.close':
									$tpl->assign('delay_ms', 0);
									$tpl->display('devblocks:cerb.bots.portal.widget::widget/convo/window_close.tpl');
									break;
							}
						}
						
						// Save session scope
						DAO_BotSession::update($interaction->session_id, [
							DAO_BotSession::SESSION_DATA => json_encode($interaction->session_data),
							DAO_BotSession::UPDATED_AT => time(),
						]);
						break; // end message
				}
				break;
			
			case 'assets':
				$file = array_shift($path);
				
				switch($file) {
					case 'embed.js':
						DevblocksPlatform::services()->http()
							->setHeader('Cache-Control', sprintf('max-age=%d', 7200))
							->setHeader('Content-Type', 'text/javascript')
						;
						$tpl = DevblocksPlatform::services()->template();
						$tpl->display('devblocks:cerb.bots.portal.widget::widget/embed.js');
						break;
				}
				break;
				
			default:
				$tpl = DevblocksPlatform::services()->template();
				$tpl->assign('config', $config);
				
				$interaction = $stack;
				
				if(!empty($interaction)) {
					@$params = $_GET;
					
					if(isset($params) && is_array($params)) {
						$interaction_params = json_encode($params);
						
						$tpl->assign('interaction', $interaction);
						$tpl->assign('interaction_params', $interaction_params);
					}
				}
				
				$tpl->assign('cerb_app_build', APP_BUILD);
				
				try {
					$tpl->display('devblocks:cerb.bots.portal.widget::portal/index.tpl');
				} catch (Exception $e) {
					error_log($e->getMessage());
				}
				break;
		}
	}
	
	/**
	 * @param Model_CommunityTool $instance
	 */
	public function configure(Model_CommunityTool $portal) {
		$tpl = DevblocksPlatform::services()->template();
		$tpl->assign('portal', $portal);
		
		$params = DAO_CommunityToolProperty::getAllByTool($portal->code);
		$tpl->assign('params', $params);
		
		$tpl->display('devblocks:cerb.bots.portal.widget::portal/config.tpl');
	}
	
	public function saveConfiguration(Model_CommunityTool $instance) {
		$params = DevblocksPlatform::importGPC($_POST['params'] ?? null, 'array',[]);
		
		if(isset($params[self::PARAM_BOT_NAME])) {
			$value = strval($params[self::PARAM_BOT_NAME]);
			DAO_CommunityToolProperty::set($instance->code, self::PARAM_BOT_NAME, $value);
		}
		
		if(isset($params[self::PARAM_CORS_ALLOW_ORIGIN])) {
			$value = strval($params[self::PARAM_CORS_ALLOW_ORIGIN]);
			$value = rtrim($value, '/');
			DAO_CommunityToolProperty::set($instance->code, self::PARAM_CORS_ALLOW_ORIGIN, $value);
		}
		
		if(array_key_exists(self::PARAM_INTERACTION_BEHAVIOR_ID, $params)) {
			$behavior_id = $params[self::PARAM_INTERACTION_BEHAVIOR_ID];
			
			if(false !== ($behavior = DAO_TriggerEvent::get($behavior_id))) {
				// Validate the event type
				if($behavior->event_point == Event_NewInteractionChatPortal::ID) {
					DAO_CommunityToolProperty::set($instance->code, self::PARAM_INTERACTION_BEHAVIOR_ID, $behavior->id);
				}
			}
		} else {
			DAO_CommunityToolProperty::set($instance->code, self::PARAM_INTERACTION_BEHAVIOR_ID, 0);
		}
		
		if(isset($params[self::PARAM_PAGE_CSS])) {
			$value = strval($params[self::PARAM_PAGE_CSS]);
			DAO_CommunityToolProperty::set($instance->code, self::PARAM_PAGE_CSS, $value);
		}
		
		if(isset($params[self::PARAM_PAGE_HIDE_ICON])) {
			$value = intval($params[self::PARAM_PAGE_HIDE_ICON]) ? 1 : 0;
			DAO_CommunityToolProperty::set($instance->code, self::PARAM_PAGE_HIDE_ICON, $value);
		}
		
		if(isset($params[self::PARAM_PAGE_TITLE])) {
			$value = strval($params[self::PARAM_PAGE_TITLE]);
			DAO_CommunityToolProperty::set($instance->code, self::PARAM_PAGE_TITLE, $value);
		}
	}
}