<?php
/**
 * Tool Result Message Class.
 *
 * Represents programmatic tool execution results in the conversation. This is a
 * structured data container that carries tool result metadata. The actual
 * content for LLM providers is generated from the metadata.
 *
 * @package   Agenistrator
 * @since     1.0.0
 * @author    Alex Ruban <alex@maximum.guru>
 * @author    Maximum Software Inc <contact@maximum.software>
 * @license   GPL-3.0-only
 * @link      https://agenistrator.com/
 *
 * SPDX-FileCopyrightText: 2025-2026 Alex Ruban <alex@maximum.guru>
 * SPDX-FileCopyrightText: 2025-2026 Maximum Software Inc <contact@maximum.software>
 * SPDX-License-Identifier: GPL-3.0-only
 */

namespace Agenistrator;

// Direct access prevention
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Tool_Result_Message class.
 */
class Tool_Result_Message extends Message {
	/**
	 * Constructor
	 *
	 * @param string $call_id Required call ID from LLM provider (must match tool call ID)
	 * @param string $tool_id The ID of the tool that was executed
	 * @param mixed $result The tool execution result
	 * @param bool $success Whether the tool execution was successful (defaults to true)
	 * @param int|null $timestamp Optional timestamp (defaults to current time)
	 * @param int|null $message_id Optional message ID from database
	 * @since     1.0.0
	 */
	public function __construct( $call_id, $tool_id, $result, $success = true, $timestamp = null, $message_id = null ) {
		if ( empty( $call_id ) ) {
			$tool      = Tool_Manager::get_instance()->get_tool( $tool_id );
			$tool_name = $tool ? $tool->get_name() : $tool_id;
			// phpcs:disable WordPress.Security.EscapeOutput.ExceptionNotEscaped -- Exception messages are not HTML output
			throw new \InvalidArgumentException(
				String_Utils::replace_tags(
					\__( "Tool '{tool_name}': Tool result call ID is required and must match the original tool call ID from LLM provider", 'agenistrator' ),
					array( 'tool_name' => $tool_name )
				)
			);
			// phpcs:enable WordPress.Security.EscapeOutput.ExceptionNotEscaped
		}
		$metadata = array(
			'tool_id' => $tool_id,
			'result'  => $result,
			'call_id' => $call_id,
			'success' => $success,
		);

		// Tool results are programmatic - no human-readable content needed
		parent::__construct( null, $metadata, $timestamp, $message_id );
	}

	/**
	 * Create Tool_Result_Message instance from array data
	 *
	 * @param array $data Message data array
	 * @return Tool_Result_Message|null Message instance or null if invalid
	 * @since     1.0.0
	 */
	public static function from_array( $data ) {
		if ( ! isset( $data['metadata'] ) || ! is_array( $data['metadata'] ) ) {
			return null;
		}

		$metadata = $data['metadata'];

		$instance = new self(
			$metadata['call_id'] ?? null,
			$metadata['tool_id'] ?? 'unknown_tool',
			$metadata['result'] ?? 'No result',
			$metadata['success'] ?? true,
			$data['timestamp'] ?? time(),
			$data['message_id'] ?? null
		);

		// Restore full metadata (preserves token_count and other cached fields)
		$instance->set_metadata( $metadata );

		return $instance;
	}

	/**
	 * Get the message role
	 *
	 * @return string The message role
	 * @since     1.0.0
	 */
	public function get_role() {
		return 'tool_result';
	}

	/**
	 * Get the tool ID
	 *
	 * @return string The tool ID
	 * @since     1.0.0
	 */
	public function get_tool_id() {
		return $this->metadata['tool_id'] ?? 'unknown_tool';
	}

	/**
	 * Get the tool result
	 *
	 * @return mixed The tool result
	 * @since     1.0.0
	 */
	public function get_result() {
		return $this->metadata['result'] ?? 'No result';
	}

	/**
	 * Get the call ID
	 *
	 * @return string The call ID
	 * @since     1.0.0
	 */
	public function get_call_id() {
		return $this->metadata['call_id'];
	}

	/**
	 * Check if the tool execution was successful
	 *
	 * @return bool True if successful, false if failed
	 * @since     1.0.0
	 */
	public function is_success() {
		return $this->metadata['success'] ?? true; // Default to true for backward compatibility
	}

	/**
	 * Set the tool ID
	 *
	 * @param string $tool_id The tool ID
	 * @return Tool_Result_Message This instance for method chaining
	 * @since     1.0.0
	 */
	public function set_tool_id( $tool_id ) {
		if ( ! is_array( $this->metadata ) ) {
			$this->metadata = array();
		}
		$this->metadata['tool_id'] = $tool_id;
		return $this;
	}

	/**
	 * Set the tool result
	 *
	 * @param mixed $result The tool result
	 * @return Tool_Result_Message This instance for method chaining
	 * @since     1.0.0
	 */
	public function set_result( $result ) {
		if ( ! is_array( $this->metadata ) ) {
			$this->metadata = array();
		}
		$this->metadata['result'] = $result;
		return $this;
	}

	/**
	 * Set the call ID
	 *
	 * @param string|null $call_id The call ID
	 * @return Tool_Result_Message This instance for method chaining
	 * @since     1.0.0
	 */
	public function set_call_id( $call_id ) {
		if ( ! is_array( $this->metadata ) ) {
			$this->metadata = array();
		}
		$this->metadata['call_id'] = $call_id;
		return $this;
	}
}
