<?php

namespace Limb_Chatbot\Includes\Services\Actions;

use Limb_Chatbot\Includes\Data_Objects\Action_Submission;
use Limb_Chatbot\Includes\Data_Objects\Chatbot_User;

/**
 * Class Action_Callback_Execution_Context
 *
 * Encapsulates context for callback execution.
 * Provides variable replacement using extracted callback variables.
 *
 * Variable Format: {key}
 * - {simple_key} → From extracted variables
 * - {nested.path.value} → Using dot notation navigation
 * - Not found → Stays as {key} unchanged
 *
 * @package Limb_Chatbot\Includes\Services\Actions
 * @since 1.0.0
 */
class Action_Callback_Execution_Context {

	/**
	 * @var Action_Submission Action submission
	 */
	private Action_Submission $submission;

	/**
	 * @var array Extracted variables from previous callbacks
	 */
	private array $variables = [];

	/**
	 * @var Variable_Replacer Variable replacer utility
	 */
	private Variable_Replacer $replacer;
	private array $parameters;

	/**
	 * Constructor
	 *
	 * @param Action_Submission $submission Action submission
	 * @param array $extracted_variables Extracted variables from previous callbacks
	 */
	public function __construct(
		Action_Submission $submission,
		array $extracted_variables = [],
		array $parameters = []
	) {
		$this->submission = $submission;
		$this->variables  = $extracted_variables;
		
		// Merge action_data (form parameters) with extracted variables
		// Form parameters are available as simple keys like {email}, {full_name}
		// Extracted variables are available with dot notation like {callback_name.data.value}
		$all_variables = array_merge(
			$submission->get_action_data() ?? [],
			$extracted_variables
		);
		
		$this->replacer = new Variable_Replacer( $all_variables );
		$this->parameters = $parameters;
	}

	/**
	 * Process template string with variable substitution
	 *
	 * Format: {key}
	 * - {simple_key} → extracted_vars['simple_key']
	 * - {nested.path.value} → extracted_vars['nested']['path']['value']
	 *
	 * @param string $template Template string
	 * @return string Processed string
	 */
	public function process_template( string $template ): string {
		return $this->replacer->replace( $template );
	}

	/**
	 * Process template recursively on arrays and objects
	 *
	 * @param mixed $data Data to process
	 * @return mixed Processed data
	 */
	public function process_template_data( $data ) {
		return $this->replacer->replace( $data );
	}

	/**
	 * Update context with new extracted variables
	 *
	 * @param array $new_variables New extracted variables to merge
	 * @return void
	 */
	public function merge_extracted_variables( array $new_variables ): void {
		$this->variables = array_merge( $this->variables, $new_variables );
		
		// Rebuild replacer with merged action_data + all extracted variables
		$all_variables = array_merge(
			$this->submission->get_action_data() ?? [],
			$this->variables
		);
		
		$this->replacer->merge_extracted_vars( $all_variables );
	}

	/**
	 * Get context headers for HTTP requests (chat UUID, user UUID, user IP, etc.)
	 *
	 * @return array Array of context headers to inject
	 */
	public function get_context_headers(): array {
		$headers = [];

		// Add chat UUID if available
		$chat_uuid = $this->submission->get_chat_uuid();
		if ( $chat_uuid ) {
			$headers['X-Chat-UUID'] = $chat_uuid;
		}

		// Add user UUID if available
		$chatbot_user_id = $this->submission->get_chatbot_user_id();
		if ( $chatbot_user_id ) {
			try {
				$user = Chatbot_User::find( $chatbot_user_id );
				if ( $user && $user->uuid ) {
					$headers['X-User-UUID'] = $user->uuid;
				}
				// Add user IP if available
				if ( $user && $user->ip ) {
					$headers['X-User-IP'] = $user->ip;
				}
				// Add device UUID if available
				if ( $user && $user->device_uuid ) {
					$headers['X-Device-UUID'] = $user->device_uuid;
				}
			} catch ( \Exception $e ) {
				// Silently fail if user cannot be retrieved
			}
		}

		return $headers;
	}

	public function get_parameters(){
		return $this->parameters;
	}

	public function get_variables(){
		return $this->variables;
	}

	public function get_submission(): Action_Submission {
		return $this->submission;
	}
}

