<?php

namespace Limb_Chatbot\Includes\Services\Actions;

use Limb_Chatbot\Includes\Data_Objects\Action;
use Limb_Chatbot\Includes\Data_Objects\Action_Plan;
use Limb_Chatbot\Includes\Data_Objects\Action_Plan_Step;
use Limb_Chatbot\Includes\Data_Objects\Message;
use Limb_Chatbot\Includes\Data_Objects\Parameter;
use Limb_Chatbot\Includes\Services\Helper;
use Limb_Chatbot\Includes\Services\Stream_Event_Service;
use Limb_Chatbot\Includes\Utilities\Chatbot_Utility;
use Limb_Chatbot\Includes\Utilities\Copilot_Utility;

/**
 * Class Parameter_Request_Message_Builder
 *
 * Responsible for building parameter request messages.
 * Separates parameter message generation concerns from action service coordination.
 * Follows Single Responsibility Principle by handling only message creation logic.
 *
 * @package Limb_Chatbot\Includes\Services\Actions
 * @since 1.0.0
 */
class Parameter_Request_Message_Builder {

	/**
	 * Chatbot utility for AI-powered question generation
	 *
	 * @var Chatbot_Utility|null
	 */
	private ?Chatbot_Utility $chatbot_utility;

	/**
	 * Constructor with dependency injection
	 *
	 * @param Chatbot_Utility|null $chatbot_utility Optional chatbot utility for AI features
	 *
	 * @since 1.0.0
	 */
	public function __construct( ?Chatbot_Utility $chatbot_utility = null ) {
		$this->chatbot_utility = $chatbot_utility;
	}

	/**
	 * Build a parameter request message
	 *
	 * Creates a message asking the user to provide a value for a parameter.
	 * Uses pre-defined questions, AI-generated questions, or parameter labels.
	 *
	 * @param Action_Plan      $action_plan The action plan containing context
	 * @param Action_Plan_Step $step        The step with parameter data
	 *
	 * @return Message|null The parameter request message or null if parameter is invalid
	 * @since 1.0.0
	 */
	public function build( Action_Plan $action_plan, Action_Plan_Step $step, $repeat = false ): ?Message {
		$data      = $step->get_data();
		$parameter = $data['parameter'];

		if ( ! $parameter instanceof Parameter ) {
			return null;
		}

		$question = null;

		if ( $parameter->is_searchable() ) {
			$search_result_provider = new Search_Results_Provider( $this->chatbot_utility );
			$search_results         = $search_result_provider->get_from_last_message( $action_plan, $parameter );
			$parameter->inject_results( $search_results );

			// Check if this is the first step (no previous step) and parameter is searchable
			$question = $this->get_ai_question_for_searchable_parameter( $search_results, $action_plan, $step );
		}

		if ( empty( $question ) ) {
			$question = $this->determine_question( $parameter, $action_plan, $step, $repeat );
		}

		return $this->create_message( $parameter, $question );
	}

	/**
	 * Determine the question to ask for the parameter
	 *
	 * Priority order:
	 * 1. Pre-defined question in parameter
	 * 2. AI-generated question (if chatbot utility available)
	 * 3. Parameter label as fallback
	 *
	 * @param Parameter        $parameter  The parameter to ask about
	 * @param Action_Plan      $action_plan The action plan for context
	 * @param Action_Plan_Step $step       The step for context
	 *
	 * @return string The question to display to the user
	 * @since 1.0.0
	 */
	private function determine_question(
		Parameter $parameter,
		Action_Plan $action_plan,
		Action_Plan_Step $step,
		$repeat = false
	): string {
		// Use pre-defined question if available
		if ( ! empty( $parameter->get_question() ) ) {
			return $parameter->get_question();
		}

		// Generate AI-powered question if utility available
		if ( ! empty( $this->chatbot_utility ) ) {
			$question = $this->generate_ai_question( $action_plan, $step, $repeat );
			if ( ! empty( $question ) ) {
				return $question;
			}
		}

		// Fallback to parameter label
		return $parameter->get_label();
	}

	/**
	 * Generate an AI-powered question for the parameter
	 *
	 * @param Action_Plan      $action_plan The action plan for context
	 * @param Action_Plan_Step $step        The step for context
	 *
	 * @return string|null The generated question or null if generation fails
	 * @since 1.0.0
	 */
	private function generate_ai_question( Action_Plan $action_plan, Action_Plan_Step $step, $repeat = false ): ?string {
		try {
			$copilot  = new Copilot_Utility(
				$this->chatbot_utility->get_ai_model(),
				$this->chatbot_utility->get_config()
			);
			$question = $copilot->generate_data_collect_question( $action_plan, $step, $repeat, $this->chatbot_utility->get_stream() );

			if ( $question instanceof Message ) {
				return $question->extract_text();
			}

			return $question;
		} catch ( \Exception $e ) {
			Helper::log( 'Failed to generate AI question: ' . $e->getMessage() );

			return null;
		}
	}

	/**
	 * Create the actual message object
	 *
	 * @param Parameter $parameter The parameter to include in the message
	 * @param string    $question  The question text
	 *
	 * @return Message The constructed message
	 * @since 1.0.0
	 */
	private function create_message( Parameter $parameter, string $question ): Message {
		$parameter_content = [
			'type'         => Message::CONTENT_TYPE_PARAMETER,
			'parameter'    => $parameter,
			'has_callback' => (bool) Action::find( $parameter->get_action_id() )->has_callbacks(),
		];

		$text_content = [
			'type' => Message::CONTENT_TYPE_TEXT,
			'text' => [ 'value' => $question ],
		];

		$message = Message::make( [
			'role'    => Message::ROLE_ASSISTANT,
			'content' => [
				$text_content,
				$parameter_content,
			]
		] );

		$message->set_is_action_message( true );

		return $message;
	}

	private function get_ai_question_for_searchable_parameter( $search_results, Action_Plan $action_plan, Action_Plan_Step $step ) {
		$question = null;
		$first_step    = $action_plan->get_first_step();
		$is_first_step = $first_step === $step;
		$previous_step = $action_plan->get_previous_step();

		// Check if search was attempted (indicated by presence of search_query key)
		$search_attempted = ! empty( $search_results ) && isset( $search_results['search_query'] );

		if ( $is_first_step && ! $previous_step && $search_attempted && ! empty( $this->chatbot_utility ) ) {
			// This is the first step, no previous step, and a search was attempted
			$keyword     = $search_results['search_query'] ?? '';
			$has_results = ! empty( $search_results['results'] ) && is_array( $search_results['results'] ) && count( $search_results['results'] ) > 0;

			// Get the user's last message
			$last_user_message = $this->chatbot_utility->chat ? $this->chatbot_utility->chat->get_last_user_message() : null;
			$user_message_text = $last_user_message ? $last_user_message->extract_text() : '';

			// Generate AI-powered search result message
			try {
				$copilot    = new Copilot_Utility(
					$this->chatbot_utility->get_ai_model(),
					$this->chatbot_utility->get_config()
				);
				$ai_message = $copilot->generate_search_result_message( $user_message_text,
					$keyword,
					$has_results, $this->chatbot_utility->get_stream() );

				if ( $ai_message instanceof Message ) {
					$generated_text = $ai_message->extract_text();
					if ( ! empty( $generated_text ) ) {
						$question = $generated_text;
					}
				}
			} catch ( \Exception $e ) {
				Helper::log( 'Failed to generate AI search result message: ' . $e->getMessage() );
			}
		}
		return $question ?? null;
	}
}
