<?php

namespace Limb_Chatbot\Includes\AI_Providers\Claude\Services;

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

/**
 * Class Message_Service
 *
 * Prepares message payloads for sending to Claude's Messages API by formatting mixed content types
 * like plain text, image attachments, and documents according to Claude's format.
 *
 * @package Limb_Chatbot\Includes\AI_Providers\Claude\Services
 * @since 1.0.9
 */
class Message_Service {

	/**
	 * Transforms a message object into a structured array suitable for Claude API requests.
	 *
	 * @param  Message  $message  The message to prepare.
	 * @param  AI_Model  $model  The AI model used to validate feature support.
	 *
	 * @return array|null Returns an array with the message structure or null to skip.
	 * @throws Exception If the model does not support required features.
	 * @since 1.0.9
	 */
	public function prepare_message( Message $message, AI_Model $model ) {
		$role = $message->get_role();

		if ( $role === 'system' ) {
			$content = $this->extract_text_content( $message->get_content() );

			return array(
				'is_system' => true,
				'content'   => $content,
			);
		}

		$content = Helper::maybe_json_decode( $message->get_content() );

		if ( is_array( $content ) ) {
			$processed_content = $this->process_content_array( $content, $model );

			if ( count( $processed_content ) === 1 && isset( $processed_content[0]['type'] ) && $processed_content[0]['type'] === 'text' ) {
				return array(
					'role'    => $role,
					'content' => $processed_content[0]['text'],
				);
			}

			if ( empty( $processed_content ) ) {
				return null;
			}

			return array(
				'role'    => $role,
				'content' => $processed_content,
			);
		}

		return array(
			'role'    => $role,
			'content' => is_string( $content ) ? $content : '',
		);
	}

	/**
	 * Extract text content from message content.
	 *
	 * @param  mixed  $content  The message content.
	 *
	 * @return string Extracted text.
	 * @since 1.0.9
	 */
	private function extract_text_content( $content ): string {
		if ( is_string( $content ) ) {
			return $content;
		}

		if ( is_array( $content ) ) {
			foreach ( $content as $part ) {
				if ( isset( $part['type'] ) && $part['type'] === 'text' ) {
					return $part['text']['value'] ?? $part['text'] ?? '';
				}
			}
		}

		return '';
	}

	/**
	 * Process an array of content blocks.
	 *
	 * @param  array  $content  The content array.
	 * @param  AI_Model  $model  The AI model.
	 *
	 * @return array Processed content blocks for Claude.
	 * @since 1.0.9
	 */
	private function process_content_array( array $content, AI_Model $model ): array {
		$processed           = array();
		$has_wc_context_text = false;
		$wc_blocks           = array();

		foreach ( $content as $part ) {
			$type = $part['type'] ?? 'text';

			switch ( $type ) {
				case Message::CONTENT_TYPE_PARAMETER_VALUE:
				case Message::CONTENT_TYPE_PARAMETER:
					$filtered_text = apply_filters(
						"limb_chatbot_message_content_part_{$type}",
						$part['text']['value'] ?? '',
						$part
					);
					$filtered_text = is_string( $filtered_text ) ? trim( $filtered_text ) : '';

					if ( '' !== $filtered_text ) {
						$wc_blocks[]         = array( 'type' => 'text', 'text' => $filtered_text );
						$has_wc_context_text = true;
					}
					break;

				case 'text':
					$text = $part['text']['value'] ?? $part['text'] ?? '';
					if ( ! empty( $text ) ) {
						$processed[] = array(
							'type' => 'text',
							'text' => $text,
						);
					}
					break;

				case Message::CONTENT_TYPE_ACTION_SUBMISSION:
					$processed[] = array(
						'type' => 'text',
						'text' => $part[ Message::CONTENT_TYPE_ACTION_SUBMISSION ]['message'] ?? 'Action submitted',
					);
					break;

				case Message::CONTENT_TYPE_ACTION_CANCELLATION:
					$processed[] = array(
						'type' => 'text',
						'text' => ! empty( $part[ Message::CONTENT_TYPE_ACTION_CANCELLATION ]['text'] )
							? $part[ Message::CONTENT_TYPE_ACTION_CANCELLATION ]['text']
							: __( 'Cancel submission of this action', 'limb-chatbot' ),
					);
					break;

				case 'attachment':
					break;

				default:
					if ( isset( $part['content'] ) && is_string( $part['content'] ) ) {
						$processed[] = array(
							'type' => 'text',
							'text' => $part['content'],
						);
					}
					break;
			}
		}

		if ( $has_wc_context_text ) {
			return $wc_blocks;
		}

		return $processed;
	}
}
