<?php
/**
 * Read File Tool.
 *
 * Read contents of a file on the server filesystem using line/byte/search modes.
 * Extends Abstract_File_Reader_Tool for memory-efficient large file operations.
 *
 * @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;
}

/**
 * Read_File_Tool class.
 */
class Read_File_Tool extends Abstract_File_Reader_Tool {

	/**
	 * Get the tool ID.
	 *
	 * @return string The tool ID.
	 * @since     1.0.0
	 */
	public function get_id() {
		return 'read_file';
	}

	/**
	 * Get the tool name.
	 *
	 * @return string The tool name.
	 * @since     1.0.0
	 */
	public function get_name() {
		return __( 'Read File', 'agenistrator' );
	}

	/**
	 * Get the tool description.
	 *
	 * @return string The tool description.
	 * @since     1.0.0
	 */
	public function get_description() {
		return 'Read file contents.';
	}

	/**
	 * Get usage instructions for the LLM.
	 *
	 * @return string Instructions for using this tool.
	 * @since     1.0.0
	 */
	public function get_instructions() {
		return parent::get_instructions() . ' File path is relative to WordPress root or absolute.';
	}

	/**
	 * Get the parameters schema for this tool.
	 *
	 * Note: the parameter description embeds the current value of
	 * WordPress_Utils::get_allowed_paths(). Its return value is typically stable,
	 * but a poorly behaved plugin filtering wp_upload_dir() dynamically could
	 * cause it to change between requests, invalidating LLM provider prompt
	 * caches and increasing API costs.
	 *
	 * @return array Parameters schema in JSON Schema format.
	 * @since     1.0.0
	 */
	public function get_parameters() {
		$paths_desc                                  = WordPress_Utils::format_paths_description( WordPress_Utils::get_allowed_paths() );
		$params                                      = parent::get_parameters();
		$params['properties']['file']['description'] = 'File path (relative to WordPress root or absolute). Must be within one of: ' . $paths_desc . '. Use ' . DIRECTORY_SEPARATOR . ' as directory separator.';
		return $params;
	}

	/**
	 * Execute the tool with the given arguments.
	 *
	 * @param array $args The tool arguments.
	 *
	 * @return array The tool execution result.
	 * @since     1.0.0
	 */
	protected function execute( $args ) {
		$path = $args['file'];

		// Resolve path
		if ( strncmp( $path, DIRECTORY_SEPARATOR, strlen( DIRECTORY_SEPARATOR ) ) !== 0 ) {
			$path = ABSPATH . $path;
		}

		// Validate path is within allowed directories
		$path = WordPress_Utils::is_allowed_path( $path );
		if ( false === $path ) {
			return $this->error_response(
				'Invalid path: must be within one of: ' . WordPress_Utils::format_paths_description( WordPress_Utils::get_allowed_paths() )
			);
		}

		if ( ! file_exists( $path ) ) {
			return $this->error_response( 'File not found: ' . $args['file'] );
		}

		if ( ! is_file( $path ) ) {
			return $this->error_response( 'Path is not a file: ' . $args['file'] );
		}

		if ( ! is_readable( $path ) ) {
			return $this->error_response( 'File is not readable: ' . $args['file'] );
		}

		try {
			$data = $this->execute_mode( $path, $args, array( 'path' => $path ) );
		} catch ( \Throwable $e ) {
			return $this->error_response( $e->getMessage() );
		}

		return $this->success_response( 'File read', $data );
	}
}
