<?php
/**
 * Get Post Blocks Segment Tool
 *
 * Extracts specific blocks from post content using path arrays and optional index ranges.
 *
 * @package AgenticWP
 */

namespace Agentic_WP;

use Agentic_WP\Error_Handler;

defined( 'ABSPATH' ) || exit;

/**
 * Get post blocks segment tool for extracting specific blocks using path arrays.
 *
 * @since 1.0.0
 */
class Tool_Get_Post_Blocks_Segment {

	/**
	 * Returns the OpenAI tool schema for extracting block segments.
	 *
	 * @since 1.0.0
	 *
	 * @return array Tool schema definition.
	 */
	public static function schema(): array {
		return array(
			'type'        => 'function',
			'name'        => 'get_post_blocks_segment',
			'description' => 'Extract specific blocks using path arrays and optional index ranges',
			'strict'      => true,
			'parameters'  => array(
				'type'                 => 'object',
				'properties'           => array(
					'post_id'     => array(
						'type'        => 'integer',
						'description' => 'Post ID to extract blocks from',
					),
					'path'        => array(
						'type'        => 'array',
						'items'       => array( 'type' => 'integer' ),
						'description' => 'Array of zero-based block indexes for path navigation (e.g., [0, 2, 1] for first block > third inner block > second nested block)',
					),
					'start_index' => array(
						'type'        => 'integer',
						'description' => 'Optional start index for range selection within the target block level',
					),
					'end_index'   => array(
						'type'        => 'integer',
						'description' => 'Optional end index for range selection within the target block level',
					),
				),
				'required'             => array( 'post_id', 'path', 'start_index', 'end_index' ),
				'additionalProperties' => false,
			),
		);
	}

	/**
	 * Executes the get post blocks segment tool.
	 *
	 * @since 1.0.0
	 *
	 * @param array $args Tool arguments containing post_id, path, and optional range.
	 * @return string JSON response or error message.
	 */
	public static function run( array $args ): string {
		try {
			if ( ! function_exists( 'get_post' ) || ! function_exists( 'parse_blocks' ) ) {
				return 'ERROR: wp_functions_unavailable';
			}

			$post_id = isset( $args['post_id'] ) && is_int( $args['post_id'] ) ? $args['post_id'] : 0;
			if ( $post_id <= 0 ) {
				return 'ERROR: invalid_post_id';
			}

			$path = isset( $args['path'] ) && is_array( $args['path'] ) ?
				array_map( 'intval', $args['path'] ) : array();

			if ( ! self::validate_path( $path ) ) {
				return 'ERROR: invalid_path_format';
			}

			$start_index = isset( $args['start_index'] ) && is_int( $args['start_index'] ) ?
				$args['start_index'] : null;

			$end_index = isset( $args['end_index'] ) && is_int( $args['end_index'] ) ?
				$args['end_index'] : null;

			$post = get_post( $post_id );
			if ( ! $post || 'auto-draft' === $post->post_status ) {
				return 'ERROR: post_not_found';
			}

			if ( ! current_user_can( 'edit_post', $post_id ) ) {
				return 'ERROR: insufficient_permissions';
			}

			$blocks = parse_blocks( $post->post_content );
			if ( empty( $blocks ) ) {
				return 'ERROR: no_blocks_found';
			}

			$target_blocks = self::navigate_block_path( $blocks, $path );
			if ( null === $target_blocks ) {
				return 'ERROR: invalid_path';
			}

			$segment_blocks = self::extract_segment( $target_blocks, $start_index, $end_index );
			if ( false === $segment_blocks ) {
				return 'ERROR: invalid_range';
			}

			$segment_blocks = self::sanitize_blocks( $segment_blocks );

			$response = array(
				'success'     => true,
				'post_id'     => $post_id,
				'path'        => $path,
				'start_index' => $start_index,
				'end_index'   => $end_index,
				'blocks'      => $segment_blocks,
				'markup'      => serialize_blocks( $segment_blocks ),
				'block_count' => count( $segment_blocks ),
			);

			return wp_json_encode( $response );

		} catch ( \Throwable $e ) {
			Error_Handler::log_error(
				'get_post_blocks_segment',
				$e->getMessage(),
				array(
					'post_id' => $post_id ?? 0,
					'trace'   => $e->getTraceAsString(),
				)
			);
			return 'ERROR: processing_failed';
		}
	}

	/**
	 * Navigates to a specific block location using path array.
	 *
	 * @since 1.0.0
	 *
	 * @param array $blocks Block array to navigate.
	 * @param array $path   Path array of indexes.
	 * @return array|null Block array at path or null if invalid.
	 */
	private static function navigate_block_path( array $blocks, array $path ): ?array {
		$current = $blocks;

		foreach ( $path as $index ) {
			if ( ! isset( $current[ $index ] ) ) {
				return null;
			}

			if ( end( $path ) === $index ) {
				break;
			}

			$block = $current[ $index ];
			if ( ! isset( $block['innerBlocks'] ) || ! is_array( $block['innerBlocks'] ) ) {
				return null;
			}

			$current = $block['innerBlocks'];
		}

		return $current;
	}

	/**
	 * Extracts a segment of blocks using start and end indexes.
	 *
	 * @since 1.0.0
	 *
	 * @param array    $blocks      Block array.
	 * @param int|null $start_index Optional. Start index.
	 * @param int|null $end_index   Optional. End index.
	 * @return array|false Extracted blocks or false on invalid range.
	 */
	private static function extract_segment( array $blocks, ?int $start_index, ?int $end_index ): array|false {
		if ( null === $start_index && null === $end_index ) {
			return $blocks;
		}

		$count = count( $blocks );
		$start = $start_index ?? 0;
		$end   = $end_index ?? ( $count - 1 );

		if ( $start < 0 || $end >= $count || $start > $end ) {
			return false;
		}

		$length = $end - $start + 1;
		return array_slice( $blocks, $start, $length );
	}

	/**
	 * Validates path array for security and limits.
	 *
	 * @since 1.0.0
	 *
	 * @param array $path Path array to validate.
	 * @return bool True if valid, false otherwise.
	 */
	private static function validate_path( array $path ): bool {
		foreach ( $path as $segment ) {
			if ( ! is_int( $segment ) || $segment < 0 || $segment > 1000 ) {
				return false;
			}
		}
		return count( $path ) <= 10;
	}

	/**
	 * Sanitizes blocks recursively using wp_kses_post.
	 *
	 * @since 1.0.0
	 *
	 * @param array $blocks Block array to sanitize.
	 * @return array Sanitized blocks.
	 */
	private static function sanitize_blocks( array $blocks ): array {
		return array_map(
			function ( $block ) {
				if ( isset( $block['innerHTML'] ) ) {
					$block['innerHTML'] = wp_kses_post( $block['innerHTML'] );
				}
				if ( isset( $block['innerBlocks'] ) && is_array( $block['innerBlocks'] ) ) {
					$block['innerBlocks'] = self::sanitize_blocks( $block['innerBlocks'] );
				}
				return $block;
			},
			$blocks
		);
	}
}
