<?php
/**
 * List Terms Tool.
 *
 * List terms from any taxonomy with filtering, search, pagination, and
 * hierarchical display support. Uses get_terms().
 *
 * @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;
}

/**
 * List_Terms_Tool class.
 */
class List_Terms_Tool extends Tool {

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

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

	/**
	 * Get the tool description.
	 *
	 * @return string The tool description.
	 * @since     1.0.0
	 */
	public function get_description() {
		return 'List terms from any taxonomy with optional filtering. Works with categories, tags, and custom taxonomies.';
	}

	/**
	 * Get usage instructions for the LLM.
	 *
	 * @return string Instructions for using this tool.
	 * @since     1.0.0
	 */
	public function get_instructions() {
		return <<<'INST'
TRUNCATION NOTE:
The `truncated_description` field is truncated for brevity. Use the `get_term_details` tool with the taxonomy and term ID to retrieve the full description.
INST;
	}

	/**
	 * Get the parameters schema for this tool.
	 *
	 * @return array Parameters schema in JSON Schema format.
	 * @since     1.0.0
	 */
	public function get_parameters() {
		return array(
			'type'       => 'object',
			'properties' => array(
				'taxonomy'         => array(
					'type'        => 'string',
					'description' => 'The taxonomy to list terms from (e.g., "category", "post_tag", "product_cat")',
				),
				'hide_empty'       => array(
					'type'        => 'boolean',
					'description' => 'Whether to hide terms with no posts',
					'default'     => false,
				),
				'parent'           => array(
					'type'        => 'integer',
					'description' => 'Parent term ID to get children of. Use 0 for top-level terms only.',
				),
				'search'           => array(
					'type'        => 'string',
					'description' => 'Search term to find in term names',
				),
				'limit'            => array(
					'type'        => 'integer',
					'description' => 'Maximum number of terms to return',
					'default'     => 100,
				),
				'offset'           => array(
					'type'        => 'integer',
					'description' => 'Number of terms to skip',
					'default'     => 0,
				),
				'orderby'          => array(
					'type'        => 'string',
					'description' => 'Field to order by',
					'enum'        => array( 'name', 'slug', 'term_id', 'count', 'parent' ),
					'default'     => 'name',
				),
				'order'            => array(
					'type'        => 'string',
					'description' => 'Order direction',
					'enum'        => array( 'ASC', 'DESC' ),
					'default'     => 'ASC',
				),
				'include_children' => array(
					'type'        => 'boolean',
					'description' => 'Whether to include child terms in hierarchical taxonomies',
					'default'     => true,
				),
			),
			'required'   => array( 'taxonomy' ),
		);
	}

	/**
	 * Check if the current user can execute this tool.
	 *
	 * @return bool True if the current user has permission.
	 * @since     1.0.0
	 */
	public function current_user_can_execute() {
		return current_user_can( 'read' );
	}

	/**
	 * Check if this tool is read-only.
	 *
	 * @return bool True if the tool only reads data.
	 * @since     1.0.0
	 */
	public function is_read_only() {
		return true;
	}

	/**
	 * 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 ) {
		if ( ! isset( $args['taxonomy'] ) || empty( $args['taxonomy'] ) ) {
			return $this->error_response( 'Taxonomy name is required' );
		}

		$taxonomy_name = sanitize_key( $args['taxonomy'] );

		if ( ! taxonomy_exists( $taxonomy_name ) ) {
			return $this->error_response( 'Taxonomy not found: ' . $taxonomy_name );
		}

		$query_args = array(
			'taxonomy'   => $taxonomy_name,
			'number'     => isset( $args['limit'] ) ? intval( $args['limit'] ) : 100,
			'offset'     => isset( $args['offset'] ) ? intval( $args['offset'] ) : 0,
			'orderby'    => $args['orderby'] ?? 'name',
			'order'      => $args['order'] ?? 'ASC',
			'hide_empty' => $args['hide_empty'] ?? false,
		);

		if ( isset( $args['parent'] ) ) {
			$query_args['parent'] = intval( $args['parent'] );
		}

		if ( isset( $args['search'] ) && ! empty( $args['search'] ) ) {
			$query_args['search'] = sanitize_text_field( $args['search'] );
		}

		if ( isset( $args['include_children'] ) && ! $args['include_children'] ) {
			$query_args['childless'] = true;
		}

		$terms = get_terms( $query_args );

		if ( is_wp_error( $terms ) ) {
			return $this->error_response( 'Failed to retrieve terms: ' . $terms->get_error_message() );
		}

		$limit  = intval( $query_args['number'] );
		$offset = intval( $query_args['offset'] );

		if ( empty( $terms ) ) {
			return $this->success_response(
				'No terms found',
				array(
					'terms'    => array(),
					'count'    => 0,
					'total'    => 0,
					'limit'    => $limit,
					'offset'   => $offset,
					'has_more' => false,
				)
			);
		}

		// Get true total count with same filters but no limit/offset
		$count_args = array_merge(
			$query_args,
			array(
				'number' => 0,
				'offset' => 0,
				'fields' => 'count',
			)
		);
		$total      = (int) get_terms( $count_args );

		$taxonomy  = get_taxonomy( $taxonomy_name );
		$formatted = array();

		foreach ( $terms as $term ) {
			$term_data = array(
				'id'                    => $term->term_id,
				'name'                  => $term->name,
				'slug'                  => $term->slug,
				'truncated_description' => String_Utils::truncate_to_token_boundary_with_ellipsis( $term->description, 200 ),
				'count'                 => $term->count,
				'url'                   => get_term_link( $term ),
			);

			if ( $taxonomy->hierarchical ) {
				$term_data['parent'] = $term->parent;
				if ( $term->parent > 0 ) {
					$parent = get_term( $term->parent, $taxonomy_name );
					if ( $parent && ! is_wp_error( $parent ) ) {
						$term_data['parent_name'] = $parent->name;
					}
				}
			}

			$formatted[] = $term_data;
		}

		return $this->success_response(
			'Terms retrieved successfully',
			array(
				'taxonomy'     => $taxonomy_name,
				'hierarchical' => $taxonomy->hierarchical,
				'terms'        => $formatted,
				'count'        => count( $formatted ),
				'total'        => $total,
				'limit'        => $limit,
				'offset'       => $offset,
				'has_more'     => ( $offset + count( $formatted ) ) < $total,
			)
		);
	}
}
