<?php

namespace Limb_Chatbot\Includes\AI_Providers\Open_Ai\Services;

use Limb_Chatbot\Includes\Data_Objects\AI_Model;
use Limb_Chatbot\Includes\Data_Objects\Message;
use Limb_Chatbot\Includes\Services\Helper;

/**
 * Class Message_Service
 *
 * Prepares message payloads for sending to OpenAI's Assistant APIs by formatting mixed content types
 * like plain text and image attachments according to the capabilities of the selected model.
 *
 * @package Limb_Chatbot\Includes\AI_Providers\Open_Ai\Services
 * @since 1.0.0
 */
class Message_Service {

	/**
	 * Transforms a message object into a structured array suitable for OpenAI API requests.
	 *
	 * Attachment content is ignored; only supported text-based content is sent to the provider.
	 *
	 * @param Message   $message The message to prepare.
	 * @param AI_Model  $model   The AI model in use.
	 *
	 * @return array Returns an array with the message `role` and `content` prepared for OpenAI.
	 * @since 1.0.0
	 */
	public function prepare_message( Message $message, AI_Model $model ) {
		$content = Helper::maybe_json_decode( $message->get_content() );
		if ( is_array( $content ) ) {
			$has_wc_context_text = false;
			foreach ( $content as $index => &$part ) {
				$part_type = $part['type'] ?? '';
				if (
					$part_type === Message::CONTENT_TYPE_PARAMETER
					|| $part_type === Message::CONTENT_TYPE_PARAMETER_VALUE
				) {
					$filtered_text = apply_filters(
						"limb_chatbot_message_content_part_{$part_type}",
						$part['text']['value'] ?? '',
						$part
					);
					$filtered_text = is_string( $filtered_text ) ? trim( $filtered_text ) : '';
					// Keep provider payload textual when a formatter returns context; otherwise drop UI-only part.
					if ( '' === $filtered_text ) {
						unset( $content[ $index ] );
						continue;
					}
					$part = [
						'type'         => 'text',
						'text'         => [ 'value' => $filtered_text ],
						'__wc_context' => true,
					];
					$has_wc_context_text = true;
				}

				if ( $part['type'] === 'text' ) {
					if ( count( $content ) === 1 ) {
						// Plain text content case
						$content = $part['text']['value'];
						break;
					} else {
						$part['text'] = $part['text']['value'];
					}
				} elseif ( $part['type'] === 'attachment' ) {
					unset( $content[ $index ] );
					continue;
				} elseif ( $part['type'] === Message::CONTENT_TYPE_ACTION_SUBMISSION ) {
					$part['type'] = 'text';
					$part['text'] = $part[ Message::CONTENT_TYPE_ACTION_SUBMISSION ]['message'] ?? 'Action submitted';
					unset( $part[ Message::CONTENT_TYPE_ACTION_SUBMISSION ] );
				} elseif ( $part['type'] === Message::CONTENT_TYPE_ACTION_CANCELLATION ) {
					$part['type'] = 'text';
					$part['text'] = ! empty( $part[ Message::CONTENT_TYPE_ACTION_CANCELLATION ]['text'] )
						? $part[ Message::CONTENT_TYPE_ACTION_CANCELLATION ]['text']
						: __( 'Cancel submission of this action', 'limb-chatbot' );
					unset( $part[ Message::CONTENT_TYPE_ACTION_CANCELLATION ] );
				}
			}
			unset( $part );

			if ( is_array( $content ) && $has_wc_context_text ) {
				// For mixed WooCommerce messages, keep only generated WC context text for model input.
				$content = array_values(
					array_filter(
						$content,
						static function ( $part ) {
							return is_array( $part ) && ! empty( $part['__wc_context'] );
						}
					)
				);
			}

			if ( is_array( $content ) ) {
				foreach ( $content as &$part ) {
					if ( is_array( $part ) ) {
						unset( $part['__wc_context'] );
					}
				}
				unset( $part );

				if ( 1 === count( $content ) && isset( $content[0]['type'] ) && 'text' === $content[0]['type'] ) {
					$text_value = $content[0]['text'] ?? '';
					if ( is_array( $text_value ) ) {
						$text_value = $text_value['value'] ?? '';
					}
					$content = is_string( $text_value ) ? $text_value : '';
				}
			}
		}

		return array(
			'role'    => $message->get_role(),
			'content' => $content,
		);
	}
}