<?php

namespace Limb_Chatbot\Includes\Utilities;

use Limb_Chatbot\Includes\Data_Objects\Action_Plan;
use Limb_Chatbot\Includes\Data_Objects\Action_Plan_Step;
use Limb_Chatbot\Includes\Data_Objects\AI_Model;
use Limb_Chatbot\Includes\Data_Objects\Chat;
use Limb_Chatbot\Includes\Data_Objects\Config;
use Limb_Chatbot\Includes\Data_Objects\Message;
use Limb_Chatbot\Includes\Data_Objects\Parameter;
use Limb_Chatbot\Includes\Exceptions\Error_Codes;
use Limb_Chatbot\Includes\Exceptions\Exception;
use Limb_Chatbot\Includes\Interfaces\Utility_Interface;
use Limb_Chatbot\Includes\Services\Collection;

/**
 * Class Copilot Utility
 *
 * Utility class for managing copilot operations
 *
 * @package Limb_Chatbot\Includes\Utilities
 *
 * @since 1.0.0
 */
class Copilot_Utility extends Utility implements Utility_Interface {

	/**
	 * Static utility name.
	 *
	 * @var string
	 * @since 1.0.0
	 */
	public static string $name = 'Copilot';

	/**
	 * The AI model associated with this utility.
	 *
	 * @var AI_Model|null
	 * @since 1.0.0
	 */
	public ?AI_Model $ai_model = null;

	/**
	 * Optional configuration related to the AI model.
	 *
	 * @var Config|null
	 * @since 1.0.0
	 */
	public ?Config $config = null;

	/**
	 * AI provider identifier.
	 *
	 * @var string|null
	 * @since 1.0.0
	 */
	public ?string $ai_provider_id;

	/**
	 * Constructor.
	 *
	 * Initializes the Copilot_Utility with optional model, config, and AI provider ID.
	 *
	 * @param  AI_Model|null  $ai_model  AI model instance. If null, must be set later.
	 * @param  Config|null  $config  Optional configuration object.
	 * @param  string|null  $ai_provider_id  Optional AI provider ID; if null, derived from the model.
	 *
	 * @since 1.0.0
	 */
	public function __construct(
		?Ai_Model $ai_model = null,
		?Config $config = null,
		?string $ai_provider_id = null
	) {
		$this->ai_provider_id = $ai_provider_id;
		if ( ! is_null( $ai_model ) ) {
			$this->ai_model = $ai_model;
		}
		if ( is_null( $this->ai_provider_id ) && ! is_null( $this->ai_model ) ) {
			$this->ai_provider_id = $this->ai_model->get_ai_provider_id();
		}
		if ( ! is_null( $config ) ) {
			$this->config = $config;
		}
	}

	/**
	 * Get the AI provider ID associated with this utility.
	 *
	 * @return string|null AI provider identifier or null if not set.
	 *
	 * @since 1.0.0
	 */
	public function get_ai_provider_id(): ?string {
		return $this->ai_provider_id;
	}

	/**
	 * Get the configuration object.
	 *
	 * @return Config|null Config object or null if not set.
	 *
	 * @since 1.0.0
	 */
	public function get_config(): ?Config {
		return $this->config;
	}

	/**
	 * Get the AI_Model object
	 *
	 * @return AI_Model AI_Model object or null
	 * @since 1.0.0
	 */
	public function get_ai_model(): AI_Model {
		return $this->ai_model;
	}

	/**
	 * Determines if a user message is suitable for retrieval from the vector store.
	 *
	 * Only considers the current message. Returns '1' if vector search is appropriate, '0' otherwise.
	 *
	 * @param  string  $user_input  User's message text.
	 *
	 * @return string '1' if eligible, '0' if not.
	 * @since 1.0.0
	 * @throws Exception
	 */
	public function is_vector_search_applicable( $user_input ) {
		$messages       = new Collection();
		$system_message = implode( "\n", [
			"You are an AI chatbot embedded in " . ucfirst( get_option( 'blogname' ) ?? '' ) . " website. Your task is to decide whether a user message is suitable for retrieval from the vector store.",
			"## Rules",
			"- If the message relies only on vague pronouns (e.g., 'it', 'this', 'there') **without meaningful keywords**, return `0`.",
			"- If the message has clear, standalone, search-friendly keywords, return `1`.",
			"- Return `0` if the message has only 1 or 2 words.",
			"- Output **only** `1` or `0`. No explanations, formatting, or extra text.",
			"- Treat every message independently for vector search eligibility."
		] );

		$messages->push_item( Message::make( [
			'role'    => 'system',
			'content' => [
				[
					'type' => 'text',
					'text' => [ 'value' => $system_message ],
				]
			],
		] ) );

		$messages->push_item( Message::make( [
			'role'    => 'user',
			'content' => [
				[
					'type' => 'text',
					'text' => [ 'value' => 'User: ' . $user_input ],
				]
			],
		] ) );

		return $this->get_ai_provider_utility()->is_vector_search_applicable( $messages );
	}

	/**
	 * Enhanced conversation analysis with essential AI context
	 */
	public function analyze_turn( $payload ) {
		$system_message = implode( "\n", [
			"You are an expert conversation analyst specializing in maintaining coherent, context-aware AI conversations.",
			"Your analysis directly impacts AI response quality and user experience.",
			"",
			"## CRITICAL OUTPUT FORMAT:",
			"Return ONLY a valid JSON object with EXACTLY these keys:",
			"intent, topic, entities, summary, confidence, sentiment, user_preferences, user_intent_history",
			"",
			"## ANALYSIS REQUIREMENTS:",
			"",
			"### Core State Management:",
			"- topic: Maintain continuity. Only change if user explicitly shifts topics. Preserve context.",
			"- entities: MUST be structured as object with categories. NO flat arrays allowed:",
			"  { people:[], orgs:[], locations:[], dates:[], products:[], services:[], misc:[] }",
			"  - people: Names of individuals mentioned",
			"  - orgs: Company/organization names",
			"  - locations: Geographic locations, addresses, countries, cities",
			"  - dates: Specific dates, time periods",
			"  - products: Specific product names, models, equipment",
			"  - services: Service types, offerings, solutions",
			"  - misc: Other important entities not fitting above categories",
			"- summary: REPLACE previous summary with updated version. Do NOT append. Keep concise (max 2 sentences).",
			"",
			"### AI Response Quality:",
			"- confidence: 0.0-1.0. Analyze user's reaction to LAST assistant message:",
			"  * 0.8-1.0: User is satisfied, continuing topic",
			"  * 0.5-0.7: User is neutral, slight topic shift",
			"  * 0.2-0.4: User seems confused or unsatisfied",
			"  * 0.0-0.1: User is frustrated or asking for clarification",
			"",
			"### Conversation Intelligence:",
			"- sentiment: From CURRENT user message only: ['positive','negative','neutral','frustrated','satisfied']",
			"",
			"### Context Preservation:",
			"- user_preferences: MUST be a key-value object (no arrays allowed). Capture all preferences (personal info, favourite things, settings, etc.) and any information the user mentioned about themselves using clear, descriptive keys. This data will be used for analytics and reporting purposes:",
			"  { \"desired_contact_way\": \"email\", \"color_preference\": \"red\", \"location\": \"Armenia\", \"customer_type\": \"business\" }",
			"- user_intent_history: Append current intent. Maintain chronological order",
			"",
			"## MERGING RULES:",
			"- ALWAYS merge entities, preferences, and intent history with previous_state values",
			"- NEVER reset topic or summary unless user explicitly changes subject",
			"- Confidence should reflect user feedback to last assistant response",
			"- Maintain conversation continuity across turns",
			"- REMOVE duplicates when merging entities and preferences",
			"- YOU MUST categorize entities intelligently - do NOT put everything in misc",
			"- YOU MUST extract preferences as key-value pairs - do NOT use flat arrays",
			"",
			"## OUTPUT VALIDATION:",
			"- Include ALL required keys",
			"- Use exact schema values",
			"- Provide null for uncertain values",
			"- No commentary or extra text",
			"- Ensure JSON is valid and parseable",
			"- entities MUST be object with proper categorization, NOT array",
			"- user_preferences MUST be object with key-value pairs, NOT array",
			"- CRITICAL: Do the intelligent categorization yourself - don't rely on fallbacks",
			"",
			"## EXAMPLE OUTPUT:",
			'{"intent":"Location inquiry","topic":"Solar solutions inquiry","entities":{"people":[],"orgs":["Solar Integrations"],"locations":["Armenia"],"dates":[],"products":[],"services":["Solar Power","Energy Storage","EV Infrastructure","Incentive Management"],"misc":[]},"summary":"Business customer inquiring about Solar Integrations solar solutions in Armenia, with preference for red-colored systems and email contact.","confidence":0.7,"sentiment":"neutral","user_preferences":{"desired_contact_way":"email","color_preference":"red","location":"Armenia","customer_type":"business"},"user_intent_history":["Identity inquiry","Service inquiry","Business inquiry","Contact inquiry","Product inquiry","Location inquiry"]}'
		] );

		$messages = new Collection();
		$messages->push_item( Message::make( [
			'role'    => 'system',
			'content' => [ [ 'type' => 'text', 'text' => [ 'value' => $system_message ] ] ]
		] ) );
		$messages->push_item( Message::make( [
			'role'    => 'user',
			'content' => [
				[
					'type' => 'text',
					'text' => [ 'value' => $payload ]
				]
			]
		] ) );

		return $this->get_ai_provider_utility()->analyze_turn( $messages );
	}

	/**
	 * Generate a natural question for collecting a specific parameter in an action plan.
	 *
	 * This method uses AI to generate a conversational question that requests the user
	 * to provide a specific field value. The AI considers the context of the action,
	 * previous steps, and any previously collected data to generate an appropriate
	 * and natural-sounding question or acknowledgment.
	 *
	 * @param  Action_Plan  $plan  The action plan being executed.
	 * @param  Action_Plan_Step  $step  The current step requiring data collection.
	 *
	 * @return string The generated question or message.
	 * @throws Exception If question generation fails.
	 * @since 1.0.0
	 */
	public function generate_data_collect_question( Action_Plan $plan, Action_Plan_Step $step, $repeat = false, $stream = false ) {
		$messages = new Collection();

		// Get the current parameter
		$data      = $step->get_data();
		$parameter = $data['parameter'] ?? null;

		if ( ! $parameter instanceof Parameter ) {
			throw new Exception( Error_Codes::TECHNICAL_ERROR, __( 'Invalid parameter in action plan step.', 'limb-chatbot' ) );
		}
		// Get the action
		$action = $plan->action();
		// Build context about previously collected parameters
		$previous_step = $plan->get_previous_step();
		if ( ! $previous_step ) {
			$chat = Chat::find_by_uuid( $plan->get_chat_uuid() );
			if ( $chat instanceof Chat ) {
				$last_user_message = $chat->get_last_user_message();
				if ( $last_user_message instanceof Message ) {
					$previous_step = [
						'field' => 'initial input',
						'value' => $last_user_message->extract_text(),
					];
				}
			}
		}

		// Build the system message with detailed context
		$system_message = implode( "\n", [
			"You are a friendly assistant helping users complete a form by collecting information step by step.",
			"Your task is to generate a natural, conversational question or acknowledgment message to collect the next piece of information.",
			"",
			"## CONTEXT:",
			"- Action: " . ( $action ? $action->get_name() : 'Unknown' ),
			"- Action Purpose: " . ( $action && $action->get_ai_instructions() ? $action->get_ai_instructions() : 'Collecting user information' ),
			"- Current Field to Collect: " . ( $parameter->get_label() ?? $parameter->get_name() ),
			"- Field Type: " . ( $parameter->get_type() ?? 'text' ),
			! empty( $parameter->get_placeholder() ) ? "- Example: " . $parameter->get_placeholder() : "",
			! empty( $parameter->get_validation_rules() ) ? "- Requirements: " . $parameter->get_validation_rules( true ) : "",
			"",
			"## YOUR TASK:",
			! empty( $previous_step ) ? "1. First, briefly acknowledge the user's previous input: \"{$previous_step['value']}\" for {$previous_step['field']}" : "1. This is the first field, no acknowledgment needed",
			"2. Then, ask for the next field: " . ( $parameter->get_label() ?? $parameter->get_name() ),
			$repeat ? "IMPORTANT: This is a repeat request because the previous attempt failed. You MUST include the word 'again' in your question naturally. For example: 'Could you please share your email address again?' or 'I need your phone number again, please.'" : "",
			"3. Be conversational, friendly, and natural",
			"4. Don't use formal language or bullet points",
			"5. Keep it concise (1-2 sentences maximum)",
			! empty( $parameter->get_placeholder() ) ? "6. You can mention an example if helpful: " . $parameter->get_placeholder() : "",
			"",
			"## OUTPUT FORMAT:",
			"Return ONLY the question/message text, without any formatting, quotes, or extra commentary.",
			"You can use emojis, for your response warmness.",
			"",
			"## EXAMPLES:",
			$repeat ? "Good (repeat): \"Could you please share your email address again?\"" : "",
			$repeat ? "Good (repeat): \"I need your phone number again, please.\"" : "",
			"Good: \"Great! Now, what's your email address so we can send you the details?\"",
			"Good: \"Perfect! And which product are you interested in?\"",
			"Good: \"Thanks! Could you share your phone number?\"",
			"Bad: \"Please provide your email address.\" (too formal)",
			"Bad: \"Email: \" (not conversational)"
		] );

		// Remove empty lines from system message
		$system_message = implode( "\n", array_filter( explode( "\n", $system_message ) ) );
		$system_message = apply_filters( 'lbaic_copilot_system_message', $system_message );

		$messages->push_item( Message::make( [
			'role'    => 'system',
			'content' => [
				[
					'type' => 'text',
					'text' => [ 'value' => $system_message ],
				]
			],
		] ) );

		// Build the user message with field details
		$user_context = [
			'field_name'    => $parameter->get_name(),
			'field_label'   => $parameter->get_label() ?? $parameter->get_name(),
			'field_type'    => $parameter->get_type() ?? 'text',
			'required'      => $parameter->get_required() === '1' || $parameter->get_required() === 1,
			'placeholder'   => $parameter->get_placeholder(),
			'previous_step' => $previous_step,
		];

		$messages->push_item( Message::make( [
			'role'    => 'user',
			'content' => [
				[
					'type' => 'text',
					'text' => [ 'value' => json_encode( $user_context, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT ) ],
				]
			],
		] ) );

		return $this->get_ai_provider_utility()->generate_data_collect_question( $messages, $stream );
	}

	/**
	 * Generate a beautiful success message for action completion
	 *
	 * Generates a warm, celebratory message to show users after they complete an action.
	 * Uses AI to create personalized, engaging success messages based on the action context.
	 *
	 * @param  string  $action_context  The action context/purpose (e.g., "Generate Voucher")
	 * @param  bool  $is_success  Whether the action was successful or failed
	 *
	 * @return Message The generated success message
	 * @throws Exception If message generation fails
	 * @since 1.0.0
	 */
	public function generate_action_success_message( string $action_context, bool $is_success = true, $stream = false ) {
		$messages = new Collection();

		// Build system message for success message generation
		$system_message = implode( "\n", [
			"You are a friendly assistant helping users by providing positive, encouraging feedback about success/failure of the given action.",
			"Your task is to generate a short, warm, celebratory success message for a completed action.",
			"",
			"## GUIDELINES:",
			"- Keep it to ONE sentence maximum",
			"- Use 1-2 appropriate emojis to add warmth",
			$is_success ? "- Make it celebratory and positive" : "- Be empathetic and supportive if it failed",
			"- Be conversational and friendly",
			"- No technical details or jargon",
			"- Make the user feel appreciated",
			"",
			"## OUTPUT FORMAT:",
			"Return ONLY the success/failure message text, without any formatting, quotes, or extra commentary."
		] );

		$system_message = apply_filters( 'lbaic_copilot_system_message', $system_message );

		$messages->push_item( Message::make( [
			'role'    => 'system',
			'content' => [
				[
					'type' => 'text',
					'text' => [ 'value' => $system_message ],
				]
			],
		] ) );

		// Build user message with action context and status
		$status_text = $is_success ? 'successfully completed' : 'attempted but failed';
		$user_prompt = sprintf(
		/* translators: %1$s: action context, %2$s: status (success/failed) */
			__( 'Generate a message for a user who just %1$s: "%2$s"', 'limb-chatbot' ),
			$status_text,
			$action_context
		);

		$messages->push_item( Message::make( [
			'role'    => 'user',
			'content' => [
				[
					'type' => 'text',
					'text' => [ 'value' => $user_prompt ],
				]
			],
		] ) );

		// Delegate to AI provider utility
		return $this->get_ai_provider_utility()->generate_action_success_message( $messages, $stream );
	}

	/**
	 * Generate action success message with extracted variables context
	 *
	 * Creates a beautiful success message that includes information from extracted variables.
	 * Example: "Congrats, your voucher code is: SAVE20XYZ"
	 *
	 * @param string $action_context The action context/purpose
	 * @param string $details        Formatted extracted variables details (pre-formatted string)
	 * @param bool   $is_success     Whether the action was successful or failed
	 *
	 * @return Message The AI-generated success message
	 * @throws Exception
	 * @since 1.0.0
	 */
	public function generate_action_success_message_with_context( string $action_context, string $details, bool $is_success = true, $stream = false ) {
		$messages = new Collection();

		// Build system message for success message generation with context
		$system_message = implode( "\n", [
			"You are a friendly assistant helping users by providing positive, encouraging feedback about success or failure of the given action.",
			"Your task is to generate a short, warm, celebratory success message for a completed action.",
			"",
			"## GUIDELINES:",
			"- Keep it to ONE sentence maximum",
			"- Use 1-2 appropriate emojis to add warmth",
			$is_success ? "- Make it celebratory and positive" : "- Be empathetic and supportive if it failed",
			"- Be conversational and friendly",
			"- No technical details or jargon",
			"- Make the user feel appreciated",
			"- IMPORTANT: Include the provided data/values in the message naturally",
			"",
			"## OUTPUT FORMAT:",
			"If you are going to use any detail in your response like visitor name, make sure the detail is filled, do not use something like {visitor_name}.",
			"Return ONLY the success/failure message text, without any formatting, quotes, or extra commentary.",
		] );

		// Build user prompt with status information
		$status_text = $is_success ? 'successfully completed' : 'attempted but failed';
		$user_prompt = sprintf( __( 'Generate a message for a user who %1$s: "%2$s" with these details: %3$s', 'limb-chatbot' ), $status_text, $action_context, $details );

		$system_message = apply_filters( 'lbaic_copilot_system_message', $system_message );

		$messages->push_item( Message::make( [
			'role'    => 'system',
			'content' => [
				[
					'type' => 'text',
					'text' => [ 'value' => $system_message ],
				]
			],
		] ) );

		$messages->push_item( Message::make( [
			'role'    => 'user',
			'content' => [
				[
					'type' => 'text',
					'text' => [ 'value' => $user_prompt ],
				]
			],
		] ) );

		// Delegate to AI provider utility
		return $this->get_ai_provider_utility()->generate_action_success_message( $messages, $stream );
	}

	/**
	 * Generate a context-aware message for live agent connection.
	 *
	 * Creates a warm, reassuring message to inform users about live agent connection status.
	 * Considers connection success/failure, reason for connection, and any error messages.
	 *
	 * @param  bool  $is_success  Whether the connection was successful.
	 * @param  string  $reason  User's reason for requesting live agent.
	 * @param  string|null  $error_message  Error message if connection failed.
	 *
	 * @return Message The generated message
	 * @throws Exception If message generation fails
	 * @since 1.0.0
	 */
	public function generate_live_agent_connection_message(
		bool $is_success,
		string $reason = '',
		?string $error_message = null,
		$stream = false
	) {
		$messages = new Collection();

		// Build context-aware system message
		$system_message = implode( "\n", array_filter( [
			"You are a friendly AI assistant helping users connect with live human agents.",
			"Your task is to generate a warm, reassuring message about the live agent connection.",
			"",
			"## CONTEXT:",
			"- Connection Status: " . ( $is_success ? "Successfully Connected" : "Connection Failed" ),
			$reason ? "- User's Reason: " . $reason : "",
			$error_message ? "- Error: " . $error_message : "",
			"",
			"## GUIDELINES:",
			$is_success
				? "- Reassure the user that a live agent will be with them shortly"
				: "- Be empathetic and apologize for the inconvenience",
			$is_success
				? "- Let them know their request has been received and prioritized"
				: "- Suggest they try again or contact support through alternative means",
			"- Use 1-2 appropriate emojis to add warmth",
			"- Keep it to 1-2 sentences maximum",
			"- Be conversational and friendly",
			"- Make the user feel valued and supported",
			$reason ? "- Acknowledge their specific reason/concern if provided" : "",
			"",
			"## OUTPUT FORMAT:",
			"Return ONLY the message text, without any formatting, quotes, or extra commentary.",
			"",
			"## EXAMPLES:",
			"Good (Success): \"Thanks for reaching out! 👋 A live agent has been notified and will be with you shortly to help with your question.\"",
			"Good (Success with reason): \"I understand you need help with billing. 💙 A live agent has been connected and will assist you right away!\"",
			"Good (Failure): \"I apologize, but I'm having trouble connecting you to a live agent right now. 😔 Please try again in a moment or contact our support team directly.\"",
		] ) );

		$system_message = apply_filters( 'lbaic_copilot_system_message', $system_message );

		$messages->push_item( Message::make( [
			'role'    => 'system',
			'content' => [
				[
					'type' => 'text',
					'text' => [ 'value' => $system_message ],
				]
			],
		] ) );

		// Build user prompt with all context
		$user_prompt = sprintf(
			'Generate a message for live agent connection. Status: %s%s%s',
			$is_success ? 'connected' : 'failed',
			$reason ? ', Reason: ' . $reason : '',
			$error_message ? ', Error: ' . $error_message : ''
		);

		$messages->push_item( Message::make( [
			'role'    => 'user',
			'content' => [
				[
					'type' => 'text',
					'text' => [ 'value' => $user_prompt ],
				]
			],
		] ) );

		// Delegate to AI provider utility
		return $this->get_ai_provider_utility()->generate_action_success_message( $messages, $stream );
	}

	/**
	 * Generate a warm message for live agent disconnection.
	 *
	 * Creates a friendly, helpful message to inform users that the live agent
	 * session has ended and offers continued assistance from the AI.
	 *
	 * @return Message The generated message
	 * @throws Exception If message generation fails
	 * @since 1.0.0
	 */
	public function generate_live_agent_disconnection_message( $stream = false ) {
		$messages = new Collection();

		// Build system message
		$system_message = implode( "\n", [
			"You are a friendly AI assistant informing users that their live agent session has ended.",
			"Your task is to generate a warm, professional message about the disconnection.",
			"",
			"## GUIDELINES:",
			"- Thank the user for their patience and conversation",
			"- Let them know the live agent session has ended",
			"- Reassure them you're still here to help with any questions",
			"- Be warm, friendly, and encouraging",
			"- Use 1-2 appropriate emojis to add warmth",
			"- Keep it to 2-3 sentences maximum",
			"- Make the user feel supported and valued",
			"",
			"## OUTPUT FORMAT:",
			"Return ONLY the message text, without any formatting, quotes, or extra commentary.",
			"",
			"## EXAMPLES:",
			"Good: Thank you for chatting with our live agent! 👋 Your session has ended, but I'm still here if you need any further assistance. How can I help you today?",
			"Good: The live agent has disconnected. 💙 Thanks for your time! I'm back to assist you with anything else you might need.",
			"Good: Your live agent session has concluded. 😊 Feel free to ask me anything - I'm here to help!",
		] );

		$system_message = apply_filters( 'lbaic_copilot_system_message', $system_message );

		$messages->push_item( Message::make( [
			'role'    => 'system',
			'content' => [
				[
					'type' => 'text',
					'text' => [ 'value' => $system_message ],
				]
			],
		] ) );

		$messages->push_item( Message::make( [
			'role'    => 'user',
			'content' => [
				[
					'type' => 'text',
					'text' => [ 'value' => 'Generate a disconnection message for the user.' ],
				]
			],
		] ) );

		// Delegate to AI provider utility
		return $this->get_ai_provider_utility()->generate_action_success_message( $messages, $stream );
	}

	/**
	 * Refines a user's search query for vector search optimization.
	 *
	 * Extracts meaningful search keywords from natural language input,
	 * improving vector search accuracy by focusing on key terms and removing noise.
	 *
	 * Returns a Message with empty/null content if no valid search intent is detected,
	 * allowing the caller to skip vector search for non-searchable queries.
	 *
	 * @param string|null $user_input Raw user input/message text.
	 *
	 * @return Message A Message object containing the refined search query text, or empty if no search intent.
	 * @throws Exception If AI call fails.
	 * @since 1.0.0
	 */
	public function refine_search_query( ?string $user_input ): ?Message {
		$messages = new Collection();

		// Build system message for search query refinement
		$system_message = implode( "\n", [
			"You are an expert search query optimizer.",
			"Your task is to extract and refine search keywords from user messages.",
			"",
			"IMPORTANT:",
			"- First, determine whether the user has a CLEAR and SPECIFIC SEARCH INTENT.",
			"- Generic browsing requests are NOT valid search intent.",
			"",
			"## VALID SEARCH INTENT:",
			"The user explicitly mentions a specific product, category, or identifiable attributes.",
			"Examples:",
			"- 'blue hoodie'",
			"- 'red dress size m'",
			"- 'running shoes under 100 dollars'",
			"- 'wireless headphones'",
			"",
			"## INVALID SEARCH INTENT (RETURN 'none'):",
			"- Generic or vague requests with no specific product",
			"- Requests that only contain catalog-level words",
			"",
			"INVALID examples:",
			"- 'products'",
			"- 'available products'",
			"- 'items'",
			"- 'show me products'",
			"- 'what do you sell'",
			"- 'can you share available products'",
			"- greetings, thanks, or uncertainty",
			"",
			"## STRICT RULES:",
			"1. If the input contains ONLY generic words like:",
			"   products, product, items, item, catalog, shop",
			"   → This is NOT a search query.",
			"2. NEVER return generic catalog words as a search query.",
			"3. If no specific product or attribute is mentioned → return EXACTLY: none",
			"",
			"## IF SEARCH INTENT EXISTS:",
			"- Identify the core product or category",
			"- Extract attributes (color, size, brand, feature, price, etc.)",
			"- Remove filler words, pronouns, and noise",
			"- Output a concise, search-ready phrase",
			"",
			"## OUTPUT FORMAT:",
			"- Return ONLY the refined search query text",
			"- OR return EXACTLY: none",
			"- No punctuation, no explanations, no extra text",
			"",
			"## EXAMPLES:",
			"Input: 'I want a blue hoodie for winter' → Output: blue hoodie winter",
			"Input: 'Do you have red shoes in size 10?' → Output: red shoes size 10",
			"Input: 'Show me shoes' → Output: shoes",
			"Input: 'Can you share available products?' → Output: none",
			"Input: 'Show me products' → Output: none",
			"Input: 'Thanks' → Output: none",
			"Input: 'Hi there' → Output: none",
			"Input: 'I don\\'t know what I want' → Output: none",
		] );

		$messages->push_item( Message::make( [
			'role'    => 'system',
			'content' => [
				[
					'type' => 'text',
					'text' => [ 'value' => $system_message ],
				]
			],
		] ) );
		$messages->push_item( Message::make( [
			'role'    => 'user',
			'content' => [
				[
					'type' => 'text',
					'text' => [ 'value' => $user_input ],
				]
			],
		] ) );
		// todo change this
		return $this->get_ai_provider_utility()->generate_action_success_message( $messages );
	}

	/**
	 * Lightweight query rewrite for clearer, more explicit retrieval queries.
	 *
	 * This is intentionally language-neutral:
	 * - Preserves the original language
	 * - Does not translate or add new intent
	 * - Focuses on spelling cleanup and clarity
	 *
	 * @param $payload
	 *
	 * @return string|null Rewritten query text or null on failure.
	 * @throws Exception
	 * @since 1.0.0
	 */
	public function rewrite_query(  $payload ): ?string {
		$messages = new Collection();
		$system_lines = [
			'You rewrite user queries for knowledge retrieval.',
			'',
			'Rewrite ONLY when necessary to resolve missing or unclear references.',
			'',
			'Rules:',
			'- Rewrite ONLY the "Current query".',
			'- If the query is already clear and self-contained, return it unchanged.',
			'',
			'',
			'- Use conversation ONLY if:',
			'  1) The current query contains a pronoun or unclear reference (e.g. "it", "one", "that", "this", "how?", "how to create one?"), OR',
			'  2) The current query is a short affirmative/negative or confirmation (e.g. "yes", "no", "okay", "please show", "sure") AND the previous assistant message contains an offer, explanation, or incomplete instruction.',
			'  3) A specific feature, concept, or named functionality was clearly mentioned earlier.',
			'',
			'- If condition 1, 2, or 3 is met, rewrite the query into a **complete, explicit, retrieval-ready question** that follows the user intent and reuses any terminology previously introduced by the assistant.',
			'',
			'- If there is no clearly established feature name, return the query unchanged.',
			'',
			'- Do NOT generalize.',
			'- Do NOT add abstract phrases like "in the context of..." or similar meta-language.',
			'- Do NOT introduce new feature names.',
			'- Do NOT assume a subject unless it was explicitly mentioned.',
			'- Do NOT change user intent.',
			'- Fix typos if needed.',
			'',
			'- Return only the rewritten query.',
			'- Keep the same language as the input.',
		];
		$system_message = implode( "\n", $system_lines );

		$messages->push_item( Message::make( [
			'role'    => 'system',
			'content' => [
				[
					'type' => 'text',
					'text' => [ 'value' => $system_message ],
				],
			],
		] ) );

		$messages->push_item( Message::make( [
			'role'    => 'user',
			'content' => [
				[
					'type' => 'text',
					'text' => [
						'value' => $payload,
					],
				],
			],
		] ) );

		$response = $this->get_ai_provider_utility()->rerank( $messages );
		$rewritten = trim( $response->extract_text() );

		return $rewritten !== '' ? $rewritten : null;
	}

	/**
	 * Generates a message for search results on the first step of a searchable parameter.
	 *
	 * Creates a natural, conversational message informing the user about search results
	 * based on their initial query. The message is a statement, not a question.
	 *
	 * @param string $user_message The user's original message/query
	 * @param string $search_query The refined search query that was used
	 * @param bool   $has_results Whether search results were found
	 *
	 * @return Message The generated message
	 * @throws Exception If message generation fails
	 * @since 1.0.0
	 */
	public function generate_search_result_message( string $user_message, string $search_query, bool $has_results, $stream = false ): ?Message {
		$messages = new Collection();

		// Build system message
		$system_message = implode( "\n", [
			"You are a friendly AI assistant helping users with product searches.",
			"Your task is to generate a natural, conversational message about search results based on the user's query.",
			"",
			"## CONTEXT:",
			"- This is the FIRST step in a searchable parameter collection process",
			"- The user has just provided their initial search query",
			"- You need to inform them about the search results",
			"",
			"## GUIDELINES:",
			"- The message should be a STATEMENT, not a question",
			"- Make your message corresponding to whether results were found or not",
			"- Make your message corresponding to user message and tone",
			"- Make your message warm and helpful",
			"- Be natural and conversational, matching the user's tone",
			"- Reference the search query/keyword naturally in your message",
			"- If results were found: Express that you found items related to their query",
			"- If no results found: Politely inform them and ask them to refine their search",
			"- Keep it concise (1-3 sentences)",
			"- Be helpful and encouraging",
			"",
			"## OUTPUT FORMAT:",
			"Return ONLY the message text, without any extra commentary.",
			"",
			"## EXAMPLES:",
			"Found results:",
			"  User: 'I want a blue hoodie'",
			"  Output: 'Here's what I found related to \"*blue hoodie*\"'",
			"",
			"No results:",
			"  User: 'I want a blue hoodie'",
			"  Output: 'I couldn't find anything related to \"*blue hoodie*\", could you please refine your search?'",
			"",
			"No Keyword:",
			"  User: 'Can you share available products?'",
			"  Output: 'Here are some of our available products. You can also use the search below to quickly find the product you’re looking for.'",
			"",
		] );

		$system_message = apply_filters( 'lbaic_copilot_system_message', $system_message );

		$messages->push_item( Message::make( [
			'role'    => 'system',
			'content' => [
				[
					'type' => 'text',
					'text' => [ 'value' => $system_message ],
				]
			],
		] ) );

		// Build user message with context
		$user_prompt = sprintf(
			"User's original message: %s\nSearch query used: %s\nResults found: %s\n\nGenerate an appropriate message about the search results.",
			$user_message,
			$search_query,
			$has_results ? 'Yes' : 'No'
		);

		$messages->push_item( Message::make( [
			'role'    => 'user',
			'content' => [
				[
					'type' => 'text',
					'text' => [ 'value' => $user_prompt ],
				]
			],
		] ) );

		// Delegate to AI provider utility
		return $this->get_ai_provider_utility()->generate_action_success_message( $messages, $stream );
	}

	public function detect_language( string $text ) {
		$messages = new Collection();

		$system_message = implode( "\n", [
			'You analyze any input text and determine the language it is written in. Always respond with the language name only (e.g., “English”, “Spanish”, “German”).',
			'If the text contains multiple languages, return the dominant one.',
			'If you are uncertain, return the most likely language.',
			'Examples:',
			'Input: "Bonjour, comment allez-vous ?"',
			'Output: French',
			'Input: "¿Dónde está la estación?"',
			'Output: Spanish',
			'Input: "Guten Morgen!"',
			'Output: German',
		] );

		$messages->push_item( Message::make( [
			'role' => 'system',
			'content' => [
				[
					'type' => 'text',
					'text' => [ 'value' => $system_message ],
				]
			],
		] ) );
		$messages->push_item( Message::make( [
			'role'    => 'user',
			'content' => [
				[
					'type' => 'text',
					'text' => [ 'value' => $text ],
				]
			],
		] ) );
		// todo change this
		return $this->get_ai_provider_utility()->generate_action_success_message( $messages );
	}

	/**
	 * Checks if the given content appears to be AI instructions rather than an entity overview.
	 *
	 * Uses AI to determine if the content is instructions for an AI system rather than
	 * a descriptive overview of an entity (company, person, organization).
	 *
	 * @param  string  $content  The content to check.
	 *
	 * @return bool True if content appears to be instructions, false otherwise.
	 * @throws Exception If the AI request fails.
	 * @since 1.0.0
	 */
	public function is_instructions_content( string $content ): bool {
		$messages = new Collection();

		// Build system message for instruction detection
		$system_message = implode( "\n", [
			"You are a content classifier. Your task is to determine if the given text is AI instructions or an entity overview/description.",
			"",
			"## DEFINITIONS:",
			"- AI INSTRUCTIONS: Text that tells an AI system HOW to behave, what to do, or how to respond. Examples:",
			"  * 'You are a helpful assistant. Always be polite and professional.'",
			"  * 'When asked about products, provide detailed specifications.'",
			"  * 'Respond in a friendly tone and use emojis when appropriate.'",
			"  * 'If the user asks about pricing, redirect them to the contact page.'",
			"",
			"- ENTITY OVERVIEW: Text that DESCRIBES what an entity (company, person, organization) IS, what it does, or its background. Examples:",
			"  * 'We are a software company specializing in AI solutions.'",
			"  * 'Our company was founded in 2020 and provides cloud services.'",
			"  * 'We offer web design, development, and digital marketing services.'",
			"  * 'John is a software engineer with 10 years of experience in web development.'",
			"",
			"## YOUR TASK:",
			"Analyze the provided text and determine if it is AI INSTRUCTIONS or an ENTITY OVERVIEW.",
			"",
			"## OUTPUT FORMAT:",
			"Return ONLY 'yes' if the text contains AI instructions, or 'no' if it is an entity overview.",
			"Do not include any explanations, formatting, or additional text.",
			"",
			"## EXAMPLES:",
			"Input: 'You should always greet users warmly and provide helpful responses.'",
			"Output: yes",
			"",
			"Input: 'We are a technology company that develops mobile applications.'",
			"Output: no",
			"",
			"Input: 'When customers ask about shipping, tell them it takes 3-5 business days.'",
			"Output: yes",
			"",
			"Input: 'Our company specializes in e-commerce solutions and has been serving clients since 2015.'",
			"Output: no",
		] );
		$messages->push_item( Message::make( [
			'role'    => 'system',
			'content' => [
				[
					'type' => 'text',
					'text' => [ 'value' => $system_message ],
				]
			],
		] ) );
		$messages->push_item( Message::make( [
			'role'    => 'user',
			'content' => [
				[
					'type' => 'text',
					'text' => [ 'value' => $content ],
				]
			],
		] ) );
		// Make request through AI provider utility
		$ai_provider_utility = $this->get_ai_provider_utility();
		$response            = $ai_provider_utility->generate_action_success_message( $messages );
		// Extract response text
		$response_text = '';
		if ( $response instanceof Message ) {
			$response_text = trim( strtolower( $response->extract_text() ) );
		}

		// Check if response indicates instructions
		return str_starts_with( $response_text, 'yes' ) || str_contains( $response_text, 'yes' );
	}

	/**
	 * Reranks candidate knowledge retrieval results based on relevance to the latest user question.
	 *
	 * Uses AI to analyze the latest user question, recent conversation context, and a list of candidate
	 * knowledge snippets. The AI selects the most relevant candidates that can help answer the question,
	 * following strict relevance rules and returning only the IDs of the selected candidates.
	 *
	 * @param string $payload A JSON-serializable array containing:
	 *                       - "latest_question": string – the current user question.
	 *                       - "conversation": string|null – short recent transcript, or null.
	 *                       - "candidates": array of { "id": number, "text": string }.
	 *
	 * @return Message|null An array of selected candidate IDs, ordered from most relevant to least relevant.
	 * @throws Exception If the AI request fails or returns invalid output.
	 * @since 1.0.0
	 */
	public function rerank( $payload ) {
		// Explicit JSON contract for the model.
		$system_message = implode("\n", [
			'You are a KNOWLEDGE RETRIEVAL RE-RANKER.',
			'',
			'You will receive a JSON object with:',
			'- "question": string – the current user question.',
			'- "candidates": array of { "id": number, "text": string }.',
			'',
			'TASK:',
			'- Select the candidate IDs that most directly help answer the specific task or question described in "question".',
			'',
			'EVALUATION RULES:',
			'1. A candidate is relevant it explains or describes how to perform the SAME task, feature, or concept as the question.',
			'2. Prefer candidates that contain actionable instructions, explanations, or steps matching the user’s intent.',
			'3. Exclude candidates that only partially overlap in wording but describe a different task or broader/unrelated topic.',
			'4. If multiple candidates describe different valid approaches to the SAME task, include them.',
			'5. Prefer precision over recall.',
			'6. Return at most 3 IDs.',
			'7. If no candidate clearly answers the question, return [].',
			'',
			'STRICT OUTPUT FORMAT:',
			'- Return ONLY a JSON array of candidate IDs, e.g. [1734, 1773].',
			'- Each ID MUST be taken from candidates[i].id.',
			'- NEVER return list positions like 1, 2, 3 – only real IDs.',
			'- Order IDs from most relevant to least relevant.',
			'- Exclude irrelevant candidates entirely.',
			'- Do NOT include explanations or extra text.',
			'- The first non-whitespace character MUST be "[" and the last MUST be "]".',
			'- Candidate texts may be truncated. Do your best to infer relevance from the visible content.',
		]);
		$messages = new Collection();

		$messages->push_item( Message::make( [
			'role'    => 'system',
			'content' => [
				[
					'type' => 'text',
					'text' => [ 'value' => $system_message ],
				],
			],
		] ) );

		$messages->push_item( Message::make( [
			'role'    => 'user',
			'content' => [
				[
					'type' => 'text',
					'text' => [ 'value' => $payload ],
				],
			],
		] ) );

		return $this->get_ai_provider_utility()->rerank( $messages );
	}
}