<?php
/**
 * List Categories Tool.
 *
 * Retrieve lists of WordPress categories using get_categories() with support
 * for filtering by parent, ordering, hiding empty, and pagination.
 *
 * @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;
}

/**
 * List_Categories_Tool class.
 */
class List_Categories_Tool extends Tool {

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

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

	/**
	 * Get the tool description.
	 *
	 * @return string The tool description.
	 * @since     1.0.0
	 */
	public function get_description() {
		return 'List WordPress categories with optional filtering.';
	}

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

	/**
	 * 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(
				'parent'     => array(
					'type'        => 'integer',
					'description' => 'Parent category ID (0 for top-level only)',
				),
				'hide_empty' => array(
					'type'        => 'boolean',
					'description' => 'Whether to hide categories with no posts',
					'default'     => false,
				),
				'search'     => array(
					'type'        => 'string',
					'description' => 'Search term to find in category names',
				),
				'limit'      => array(
					'type'        => 'integer',
					'description' => 'Maximum number of categories to return',
					'default'     => 100,
				),
				'offset'     => array(
					'type'        => 'integer',
					'description' => 'Number of categories to skip',
					'default'     => 0,
				),
				'orderby'    => array(
					'type'        => 'string',
					'description' => 'Field to order by',
					'enum'        => array( 'name', 'slug', 'term_id', 'count' ),
					'default'     => 'name',
				),
				'order'      => array(
					'type'        => 'string',
					'description' => 'Order direction',
					'enum'        => array( 'ASC', 'DESC' ),
					'default'     => 'ASC',
				),
			),
			'required'   => array(),
		);
	}

	/**
	 * 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 ) {
		$query_args = array(
			'taxonomy'   => 'category',
			'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'] );
		}

		$categories = get_terms( $query_args );

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

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

		if ( empty( $categories ) ) {
			return $this->success_response(
				'No categories found',
				array(
					'categories' => 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 );

		$formatted = array();
		foreach ( $categories as $category ) {
			$formatted[] = array(
				'id'                    => $category->term_id,
				'name'                  => $category->name,
				'slug'                  => $category->slug,
				'truncated_description' => String_Utils::truncate_to_token_boundary_with_ellipsis( $category->description, 200 ),
				'parent'                => $category->parent,
				'count'                 => $category->count,
			);
		}

		return $this->success_response(
			'Categories retrieved successfully',
			array(
				'categories' => $formatted,
				'count'      => count( $formatted ),
				'total'      => $total,
				'limit'      => $limit,
				'offset'     => $offset,
				'has_more'   => ( $offset + count( $formatted ) ) < $total,
			)
		);
	}
}
