<?php

namespace Limb_Chatbot\Includes\Services\Actions;

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\Stream_Event_Service;

/**
 * Class Validation_Error_Message_Generator
 *
 * Generates friendly, conversational validation error messages.
 * Follows Single Responsibility Principle - only handles error message generation.
 *
 * @package Limb_Chatbot\Includes\Services\Actions
 * @since 1.0.0
 */
class Validation_Error_Message_Generator {

	/**
	 * Parameter type registry
	 *
	 * @var Parameter_Type_Registry
	 */
	private Parameter_Type_Registry $registry;

	/**
	 * Constructor
	 *
	 * @param  Parameter_Type_Registry|null  $registry  Type registry (for dependency injection)
	 *
	 * @since 1.0.0
	 */
	public function __construct( ?Parameter_Type_Registry $registry = null ) {
		$this->registry = $registry ?? Parameter_Type_Registry::instance();
	}

	/**
	 * Generate a validation error message
	 *
	 * @param  Action_Plan_Step  $step  The step that failed validation
	 * @param  Parameter_Value_Result  $result  The validation result
	 *
	 * @return Message The error message
	 * @since 1.0.0
	 */
	public function generate(
		Action_Plan_Step $step,
		Parameter_Value_Result $result,
		$stream = false
	): Message {
		$data      = $step->get_data();
		$parameter = $data['parameter'] ?? null;

		if ( ! $parameter instanceof Parameter ) {
			return $this->create_message( __( 'An error occurred. Please try again.', 'limb-chatbot' ), $parameter, $stream );
		}

		// Generate friendly error message
		$error_text = $this->generate_friendly_error_text( $parameter, $result );

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

	/**
	 * Create a message object
	 *
	 * @param  string  $text  The message text
	 * @param  Parameter|null  $parameter  The parameter (for metadata)
	 *
	 * @return Message
	 * @since 1.0.0
	 */
	private function create_message( string $text, ?Parameter $parameter, $stream = false ): Message {
		$content = [
			[
				'type' => Message::CONTENT_TYPE_TEXT,
				'text' => [ 'value' => $text ],
			]
		];

		if ( $stream ) {
			Stream_Event_Service::text( $text );
		}

		// Include parameter metadata so frontend knows to keep showing the same field
		if ( $parameter instanceof Parameter ) {
			$content[] = [
				'type'      => Message::CONTENT_TYPE_PARAMETER,
				'parameter' => $parameter,
			];
		}

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

		$message->set_is_action_message( true );

		return $message;
	}

	/**
	 * Generate friendly error text
	 *
	 * @param  Parameter  $parameter  The parameter
	 * @param  Parameter_Value_Result  $result  The validation result
	 *
	 * @return string
	 * @since 1.0.0
	 */
	private function generate_friendly_error_text( Parameter $parameter, Parameter_Value_Result $result ): string {
		$error_message = $result->get_error_message();

		// Add a friendly prefix
		$prefix = $this->get_friendly_prefix();

		// Get helpful hint from the parameter type handler
		$hint = $this->get_hint_from_type_handler( $parameter );

		$text_parts = array_filter( [ $prefix, $error_message, $hint ] );

		return implode( ' ', $text_parts );
	}

	/**
	 * Get a friendly error prefix
	 *
	 * @return string
	 * @since 1.0.0
	 */
	private function get_friendly_prefix(): string {
		$prefixes = [
			__( 'Oops!', 'limb-chatbot' ),
			__( 'Hmm,', 'limb-chatbot' ),
			__( 'Sorry,', 'limb-chatbot' ),
		];

		return $prefixes[ array_rand( $prefixes ) ];
	}

	/**
	 * Get helpful hint from the parameter type handler
	 *
	 * Each parameter type is responsible for generating its own hint.
	 * This delegates to the appropriate type handler via the registry.
	 *
	 * @param  Parameter  $parameter  The parameter
	 *
	 * @return string|null
	 * @since 1.0.0
	 */
	private function get_hint_from_type_handler( Parameter $parameter ): ?string {
		$type = $parameter->get_type() ?? Parameter::TYPE_TEXT;

		// Get the type handler from registry
		$type_handler = $this->registry->get( $type );

		if ( ! $type_handler ) {
			return null;
		}

		// Delegate hint generation to the type handler
		return $type_handler->get_hint( $parameter );
	}
}

