<?php
/**
 * Tool Base Class.
 *
 * Abstract base class for all tools that can be called by language models.
 * Defines the interface and common functionality for tool implementation.
 *
 * @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://maximum.software/
 *
 * 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' ) ) {
	return;
}

/**
 * Tool class.
 */
abstract class Tool {

	/**
	 * Constructor
	 * @since     1.0.0
	 */
	public function __construct() {
		// Initialize the tool
	}

	/**
	 * Get the tool ID (machine-readable identifier)
	 *
	 * This is used for API calls, configuration keys, and internal lookups.
	 * Should be a snake_case string like 'create_post' or 'search_content'.
	 *
	 * @return     string Tool ID
	 * @since     1.0.0
	 */
	abstract public function get_id();

	/**
	 * Get the tool name (human-readable display name)
	 *
	 * This is used for UI display purposes.
	 * Should be a properly formatted name like 'Create Post' or 'Search Content'.
	 *
	 * @return     string Tool name
	 * @since     1.0.0
	 */
	abstract public function get_name();

	/**
	 * Get the tool description
	 *
	 * A brief description of what the tool does, suitable for display in the
	 * admin UI and the list_all_tools output.
	 *
	 * @return     string Tool description
	 * @since     1.0.0
	 */
	abstract public function get_description();

	/**
	 * Get brief usage hints for the LLM
	 *
	 * Description instructions provide hints about when to use this tool and
	 * how it relates to other tools (e.g., "Use list_post_types to see available types").
	 * These are appended to the tool description in list_all_tools output and tool
	 * definitions sent to the LLM, but NOT shown in the admin UI.
	 *
	 * @return     string Brief usage hints (empty by default)
	 * @since     1.0.0
	 */
	public function get_description_instructions() {
		return '';
	}

	/**
	 * Get usage instructions for the LLM
	 *
	 * Instructions provide detailed guidance on how to use the tool effectively.
	 * Unlike descriptions, instructions are only sent to the LLM after the tool
	 * is imported and are not shown in the admin UI or list_all_tools output.
	 *
	 * @return     string Tool usage instructions (empty by default)
	 * @since     1.0.0
	 */
	public function get_instructions() {
		return '';
	}

	/**
	 * Get the parameters for this tool
	 *
	 * MUST return a complete JSON Schema object with the following structure:
	 * [
	 *   'type' => 'object',
	 *   'properties' => [
	 *     'param1' => ['type' => 'string', 'description' => 'Description of param1'],
	 *     'param2' => ['type' => 'integer', 'description' => 'Description of param2'],
	 *     ...
	 *   ],
	 *   'required' => ['param1', 'param2', ...] // Always include this, even if empty array
	 * ]
	 *
	 * @return     array Complete parameters schema in JSON Schema format
	 * @since     1.0.0
	 */
	abstract public function get_parameters();

	/**
	 * Check if this tool is read-only (has no side effects)
	 *
	 * Read-only tools only retrieve data without modifying state.
	 * Read-write tools create, update, or delete content.
	 *
	 * @return     bool True if read-only, false if read-write
	 * @since     1.0.0
	 */
	abstract public function is_read_only();

	/**
	 * Check if this tool is enabled
	 *
	 * @return     bool True if enabled, false otherwise
	 * @since     1.0.0
	 */
	public function is_enabled() {
		// Delegate to Tool_Manager
		return Tool_Manager::get_instance()->is_tool_enabled( $this->get_id() );
	}

	/**
	 * Get the default enabled status for this tool
	 *
	 * By default, read-only tools are enabled and read-write tools are disabled.
	 * Individual tools can override this method to change the default behavior.
	 *
	 * @return     bool True if enabled by default, false otherwise
	 * @since     1.0.0
	 */
	public function get_default_enabled_status() {
		return $this->is_read_only();
	}

	/**
	 * Check if this tool is always enabled (cannot be disabled by user)
	 *
	 * Core tools like list_all_tools, import_tools, unimport_tools return true.
	 * Regular tools return false and can be enabled/disabled via settings.
	 *
	 * @return     bool True if always enabled, false otherwise
	 * @since     1.0.0
	 */
	public function is_always_enabled() {
		return false;
	}

	/**
	 * Check if this tool is always imported (always in context)
	 *
	 * Core tools like list_all_tools, import_tools, unimport_tools return true.
	 * Regular tools return false and must be imported to appear in context.
	 *
	 * @return     bool True if always imported, false otherwise
	 * @since     1.0.0
	 */
	public function is_always_imported() {
		return false;
	}

	/**
	 * Check if the current user has permission to execute this tool
	 *
	 * @return     bool Whether the user has permission
	 * @since     1.0.0
	 */
	abstract public function current_user_can_execute();

	/**
	 * Run the tool with the given arguments
	 *
	 * @param      array $args Arguments for the tool as an associative array
	 * @return     mixed Result of running the tool
	 * @since     1.0.0
	 */
	public function run( $args ) {
		// Validate arguments against schema (basic validation)
		$this->validate_arguments( $args );

		// Call the abstract execute method to run the tool
		return $this->execute( $args );
	}

	/**
	 * Validate arguments against the schema
	 *
	 * @param      array $args Arguments to validate
	 * @throws     \Exception If validation fails
	 * @since     1.0.0
	 */
	protected function validate_arguments( $args ) {
		// Get parameters schema
		$schema = $this->get_parameters();

		// Check required parameters
		if ( isset( $schema['required'] ) && is_array( $schema['required'] ) ) {
			foreach ( $schema['required'] as $required_param ) {
				if ( ! isset( $args[ $required_param ] ) ) {
					// phpcs:disable WordPress.Security.EscapeOutput.ExceptionNotEscaped -- Exception messages are not HTML output
					throw new \Exception(
						String_Utils::replace_tags(
							\__( 'Missing required argument: {required_param}', 'agenistrator' ),
							array( 'required_param' => $required_param )
						)
					);
					// phpcs:enable WordPress.Security.EscapeOutput.ExceptionNotEscaped
				}
			}
		}

		// Basic type checking could be added here
		// For more complex validation, a full JSON Schema validator would be needed
	}

	/**
	 * Execute the tool with the given arguments
	 * This is the main method that should be implemented by each tool
	 *
	 * @param      array $args Validated arguments for the tool
	 * @return     mixed Result of executing the tool
	 * @since     1.0.0
	 */
	abstract protected function execute( $args );

	/**
	 * Create a success response
	 *
	 * @param      string $message Success message
	 * @param      array $data Optional data to include in response
	 * @return     array Formatted success response
	 * @since     1.0.0
	 */
	protected function success_response( $message, $data = array() ) {
		return array(
			'success' => true,
			'message' => $message,
			'data'    => $data,
		);
	}

	/**
	 * Create an error response
	 *
	 * @param      string $message Error message
	 * @param      array $data Optional data to include in response
	 * @return     array Formatted error response
	 * @since     1.0.0
	 */
	protected function error_response( $message, $data = array() ) {
		return array(
			'success' => false,
			'message' => $message,
			'data'    => $data,
		);
	}
}
