<?php
/**
 * Agents profiles and instruction/tool composition.
 *
 * @package AgenticWP
 */

namespace Agentic_WP;

defined( 'ABSPATH' ) || exit;

use Agentic_WP\Error_Handler;

/**
 * Agent profiles and instruction composition.
 *
 * Manages agent system prompts, tools, and configurations.
 *
 * @since 1.0.0
 */
class Agents {

	/**
	 * Retrieves block editor principles for agent system prompts.
	 *
	 * Shared block-aware editing principles used by Editor and Interlinking agents.
	 *
	 * @since 1.0.0
	 *
	 * @return string Block-aware editing principles.
	 */
	private static function get_block_aware_principles(): string {
		return 'BLOCK-AWARE EDITING:
WordPress content uses nested blocks with parent-child relationships.

1. Navigate using path arrays: [0, 2, 1]
2. Preserve existing block hierarchy
3. Use get_post_blocks_segment for current structure; target specific blocks with paths
4. Include all required fields: slug, attrs (JSON), text, html, children
5. Make surgical edits, preserving structure/formatting unless instructed otherwise';
	}

	/**
	 * Retrieves link formatting guidelines for agent system prompts.
	 *
	 * Shared link formatting rules used by all content agents.
	 *
	 * @since 1.0.0
	 *
	 * @return string Link formatting rules.
	 */
	private static function get_link_formatting_rules(): string {
		return 'Internal links: Use relative URLs ("/about/", "/contact/"), not ID-based URLs ("?p=123", "?page_id=456").';
	}

	/**
	 * Retrieves common agent behaviors for agent system prompts.
	 *
	 * Common agent behavior directives.
	 *
	 * @since 1.0.0
	 *
	 * @return string Common behavior rules.
	 */
	private static function get_common_behavior(): string {
		return 'Execute clear instructions immediately. Clarify only for ambiguous scope or destructive actions.';
	}

	/**
	 * Retrieves intent interpretation framework for agent system prompts.
	 *
	 * Shared decision framework for understanding user intent.
	 *
	 * @since 1.0.0
	 *
	 * @return string Intent interpretation rules.
	 */
	private static function get_intent_framework(): string {
		return '## Decision Framework
- Clear request + single match → Execute immediately
- Multiple matches → Show titles, ask to select
- Destructive action → Confirm once
- Ambiguous scope (e.g., "improve this") → Ask what specifically';
	}

	/**
	 * Retrieves block usage examples for agent system prompts.
	 *
	 * Condensed block reference for Post Creator agent.
	 *
	 * @since 1.0.0
	 *
	 * @return string Block usage reference.
	 */
	private static function get_block_examples(): string {
		return '## Block Reference
Format: { slug, attrs (JSON string), text, html, children }

Leaf blocks (no children):
- core/paragraph: attrs="{}", text="Content"
- core/heading: attrs="{\"level\":2}", text="Title"
- core/list: attrs="{\"ordered\":false,\"items\":[\"Item 1\",\"Item 2\"]}"
- core/quote: attrs="{\"citation\":\"Author\"}", text="Quote text"
- core/image: attrs="{\"alt\":\"Description\",\"caption\":\"Caption\"}"
- core/table: attrs="{\"rows\":[[\"H1\",\"H2\"],[\"R1C1\",\"R1C2\"]],\"hasHeader\":true}"
- core/code: attrs="{\"language\":\"js\"}", text="code here"

Container blocks (require children):
- core/buttons → core/button: attrs="{\"url\":\"/path/\"}", text="Label"
- core/columns → core/column → content blocks
- core/media-text: attrs="{\"mediaPosition\":\"left\"}" → content blocks

Use get_block_info(slug) for full attribute specifications.';
	}

	/**
	 * Retrieves main agent instructions for agent system prompts.
	 *
	 * Main agent (orchestrator) minimal instructions.
	 *
	 * @since 1.0.0
	 *
	 * @return string Main agent instructions.
	 */
	public static function get_main_instructions(): string {
		// Get available post types dynamically.
		$available_post_types = self::get_available_post_types_list();

		$instructions = 'AgenticWP Main Agent. Orchestrate content tasks via sub-agents. Use concise, markdown-formatted responses.

' . $available_post_types . '

## Your Capabilities
You can ONLY:
- Search and read existing posts/pages (search_content, read_post)
- Create new posts/pages (delegate to Post Creator)
- Edit existing content (delegate to Post Editor)
- Add internal links (delegate to Interlinking agent)
- Generate meta descriptions (delegate to Meta Description agent)

For requests that you cannot complete with these capabilities or sub-agents, politely explain you cannot help and suggest using the WordPress admin instead.

You CANNOT: publish posts, manage plugins/themes, upload media, manage categories/tags/taxonomies, moderate comments, create menus/widgets, manage users, change site settings, or any other WordPress administration tasks.

## Sub-agents
- Post Creator: New posts/pages
- Post Editor: Modify existing content
- Interlinking: Add internal links (published posts only)
- Meta Description: Generate SEO descriptions
- When a subagent completes a task, users will be notified by a toast message in the WordPress admin.

' . self::get_intent_framework() . '

## Rules
- Check post lock before delegating; inform user if locked
- Make safe assumptions from context (e.g., "blog post about X" → post type "post")
- Be proactive about using search if a user is vague to help them quickly find content
- ' . self::get_link_formatting_rules() . '

## Workflows
**Finding posts:** When user mentions a post by name/title/topic, use search_content to find it. Never ask user for IDs or slugs.

**Search results:** Single match = proceed, multiple = show titles and confirm

**Edit:** read_post → specific request = delegate immediately, vague scope = present sections and clarify';

		/**
		 * Filters the main agent system prompt instructions.
		 *
		 * The main agent orchestrates content workflows, delegating to specialized
		 * agents (post creator, editor, interlinking, meta description). This filter
		 * allows customization of the main agent's behavior and capabilities.
		 *
		 * @hook agentic_wp_main_agent_instructions
		 * @since 1.0.0
		 *
		 * @param string $instructions The default main agent instructions.
		 * @return string The filtered main agent instructions.
		 */
		return apply_filters( 'agentic_wp_main_agent_instructions', $instructions );
	}

	/**
	 * Retrieves post creator agent instructions for agent system prompts.
	 *
	 * Post Creator agent instructions (block-aware creation primer).
	 *
	 * @since 1.0.0
	 *
	 * @return string Post creator agent instructions.
	 */
	public static function get_post_creator_instructions(): string {
		// Get available post types dynamically.
		$available_post_types = self::get_available_post_types_list();

		$instructions = 'AgenticWP Post Creator. ' . self::get_common_behavior() . '

' . $available_post_types . '

## Workflow
1. Output post_layout_plan JSON: { title, post_type, sections[] }
2. start_post with exact post_type
3. append_blocks_structured (1 block per call)
4. finalize_post; stop and report errors

## Content Guidelines
- First heading: complement title, not duplicate
- Use diverse blocks: paragraphs, lists, quotes, images, tables, columns, buttons or others depending on context
- Maintain logical flow and structure
- ' . self::get_link_formatting_rules() . '

' . self::get_block_examples() . '

## Error Recovery
- invalid_block_slug → use get_block_info(slug) to verify
- invalid_leaf_payload → provide text+attrs or html
- invalid_attrs_type → attrs must be JSON string
- buttons_missing_children → add core/button children
- list_missing_items → add attrs.items array';

		if ( class_exists( __NAMESPACE__ . '\\Settings' ) && method_exists( '\\Agentic_WP\\Settings', 'get_create_post_directions' ) ) {
			$directions = trim( Settings::get_create_post_directions() );
			if ( '' !== $directions ) {
				$instructions .= "\n\nStyle Guidelines:\n" . $directions;
			}
		}

		/**
		 * Filters the post creator agent system prompt instructions.
		 *
		 * The post creator agent is specialized for creating new WordPress posts
		 * from scratch using block-based content. This filter allows customization
		 * of creation behavior, style guidelines, and block preferences.
		 *
		 * @hook agentic_wp_post_creator_instructions
		 * @since 1.0.0
		 *
		 * @param string $instructions The default post creator instructions.
		 * @return string The filtered post creator instructions.
		 */
		return apply_filters( 'agentic_wp_post_creator_instructions', $instructions );
	}

	/**
	 * Retrieves post creator tool array for agent system prompts.
	 *
	 * @since 1.0.0
	 *
	 * @return array Post creator tools.
	 */
	public static function get_post_creator_tools(): array {
		if ( class_exists( __NAMESPACE__ . '\\Tools' ) && method_exists( '\\Agentic_WP\\Tools', 'get_post_creator_tools' ) ) {
			$tools = Tools::get_post_creator_tools();

			// Add web search if enabled in settings.
			if ( class_exists( __NAMESPACE__ . '\\Settings' ) && Settings::is_web_search_enabled() ) {
				$tools[] = array( 'type' => 'web_search' );
			}

			return $tools;
		}

		Error_Handler::log_error(
			'agent_tools',
			'Tools class not available for post creator tools',
			array( 'agent' => 'post_creator' )
		);
		return array();
	}

	/**
	 * Retrieves allowed post types list for agent system prompts.
	 *
	 * Get a formatted list of available post types for agent context.
	 *
	 * @since 1.0.0
	 *
	 * @return string Formatted post types list.
	 */
	private static function get_available_post_types_list(): string {
		$post_types = get_post_types(
			array(
				'public'       => true,
				'show_in_rest' => true,
			),
			'objects'
		);

		$excluded = array( 'attachment' );
		$types    = array();

		foreach ( $post_types as $post_type ) {
			if ( in_array( $post_type->name, $excluded, true ) ) {
				continue;
			}
			if ( ! post_type_supports( $post_type->name, 'editor' ) ) {
				continue;
			}
			$types[] = $post_type->name . ' (' . $post_type->label . ')';
		}

		if ( empty( $types ) ) {
			return 'Available post types: post, page';
		}

		return 'Available post types: ' . implode( ', ', $types );
	}

	/**
	 * Structured Outputs schema for the first layout turn.
	 */
	public static function get_post_layout_schema(): array {
		return array(
			'type'   => 'json_schema',
			'name'   => 'post_layout_plan',
			'strict' => true,
			'schema' => array(
				'type'                 => 'object',
				'properties'           => array(
					'title'     => array( 'type' => 'string' ),
					'post_type' => array(
						'type'        => 'string',
						'description' => 'Post type slug (must be from available post types list in instructions)',
					),
					'sections'  => array(
						'type'     => 'array',
						'items'    => array(
							'type'                 => 'object',
							'properties'           => array(
								'id'     => array( 'type' => 'string' ),
								'title'  => array( 'type' => 'string' ),
								'blocks' => array(
									'type'  => 'array',
									'items' => array( 'type' => 'string' ),
								),
							),
							'required'             => array( 'id', 'title', 'blocks' ),
							'additionalProperties' => false,
						),
						'maxItems' => 12,
					),
				),
				'required'             => array( 'title', 'post_type', 'sections' ),
				'additionalProperties' => false,
			),
		);
	}

	/**
	 * Retrieves editor agent instructions for agent system prompts.
	 *
	 * Editor agent instructions for WordPress post modification.
	 *
	 * @since 1.0.0
	 *
	 * @return string Editor agent instructions.
	 */
	public static function get_editor_instructions(): string {
		$instructions = 'AgenticWP Post Editor. All edits require replace_blocks_segment (auto-saves). ' . self::get_common_behavior() . '

## Workflow
1. read_post → understand structure
2. get_post_blocks_segment → extract target blocks
3. replace_blocks_segment → apply changes
4. Verify success

## Principles
- Surgical edits over full rewrites
- Preserve formatting/structure unless instructed otherwise
- Use block paths [0, 2, 1] for precision targeting
- ' . self::get_link_formatting_rules() . '

' . self::get_block_aware_principles();

		if ( class_exists( __NAMESPACE__ . '\\Settings' ) && method_exists( __NAMESPACE__ . '\\Settings', 'get_edit_post_directions' ) ) {
			$directions = trim( Settings::get_edit_post_directions() );
			if ( '' !== $directions ) {
				$instructions .= "\n\nStyle Guidelines:\n" . $directions;
			}
		}

		/**
		 * Filters the editor agent system prompt instructions.
		 *
		 * The editor agent is specialized for modifying existing WordPress posts,
		 * handling tasks like content updates, rewrites, and block manipulation.
		 * This filter allows customization of editing behavior and style guidelines.
		 *
		 * @hook agentic_wp_editor_instructions
		 * @since 1.0.0
		 *
		 * @param string $instructions The default editor instructions.
		 * @return string The filtered editor instructions.
		 */
		return apply_filters( 'agentic_wp_editor_instructions', $instructions );
	}

	/**
	 * Retrieves editor tool array for agent system prompts.
	 *
	 * @since 1.0.0
	 *
	 * @return array Editor tools.
	 */
	public static function get_editor_tools(): array {
		if ( class_exists( __NAMESPACE__ . '\\Tools' ) && method_exists( __NAMESPACE__ . '\\Tools', 'get_editor_tools' ) ) {
			return Tools::get_editor_tools();
		}
		return array();
	}

	/**
	 * Retrieves interlinking agent instructions for agent system prompts.
	 *
	 * Interlinking agent instructions for WordPress interlinking tasks.
	 *
	 * @since 1.0.0
	 *
	 * @return string Interlinking agent instructions.
	 */
	public static function get_interlinking_instructions(): string {
		$instructions = 'AgenticWP Interlinking Agent. ' . self::get_common_behavior() . '

## Workflow
1. If no post ID given, use search_content to find posts by slug/title from requirements
2. read_post to load content
3. get_post_blocks_segment → identify anchor opportunities
4. replace_blocks_segment → add links (auto-saves)

## Rules
- Max 1 link per paragraph
- Natural, contextual anchor text (no keyword stuffing)
- Check post lock status first
- ' . self::get_link_formatting_rules() . '

## Link Format
Block with link: { slug, attrs: "{}", text: "plain text", html: "<p>Text with <a href=\"/slug/\">anchor</a>.</p>", children: [] }

' . self::get_block_aware_principles();

		/**
		 * Filters the interlinking agent system prompt instructions.
		 *
		 * The interlinking agent is specialized for adding contextual internal links
		 * to existing WordPress content. This filter allows customization of linking
		 * strategy, relevance criteria, and link placement preferences.
		 *
		 * @hook agentic_wp_interlinking_instructions
		 * @since 1.0.0
		 *
		 * @param string $instructions The default interlinking instructions.
		 * @return string The filtered interlinking instructions.
		 */
		return apply_filters( 'agentic_wp_interlinking_instructions', $instructions );
	}

	/**
	 * Retrieves interlinking tool array for agent system prompts.
	 *
	 * @since 1.0.0
	 *
	 * @return array Interlinking tools.
	 */
	public static function get_interlinking_tools(): array {
		if ( class_exists( __NAMESPACE__ . '\\Tools' ) && method_exists( __NAMESPACE__ . '\\Tools', 'get_interlinking_tools' ) ) {
			return Tools::get_interlinking_tools();
		}
		return array();
	}

	/**
	 * Retrieves meta description agent instructions for agent system prompts.
	 *
	 * Meta Description agent instructions for WordPress meta description generation tasks.
	 *
	 * @since 1.0.0
	 *
	 * @return string Meta description agent instructions.
	 */
	public static function get_meta_description_instructions(): string {
		$instructions = 'Meta Description agent for AgenticWP. ' . self::get_common_behavior() . '

Workflow:
1. read_post: Analyze content/structure
2. Check existing meta descriptions
3. Extract key topics/keywords
4. Generate SEO-optimized description (150-160 chars)
5. save_meta_description
6. Report status/warnings

Requirements:
- Length: 150-160 characters (optimal for search engines)
- Natural keyword inclusion (no stuffing)
- Compelling, actionable copy
- Unique, accurate summaries
- No duplication across site

Errors:
- Handle existing descriptions (update vs create)
- Report save failures/permission errors
- Report length validation warnings
';

		/**
		 * Filters the meta description agent system prompt instructions.
		 *
		 * The meta description agent is specialized for generating SEO-optimized
		 * meta descriptions for WordPress posts. This filter allows customization
		 * of description style, length preferences, and optimization criteria.
		 *
		 * @hook agentic_wp_meta_description_instructions
		 * @since 1.0.0
		 *
		 * @param string $instructions The default meta description instructions.
		 * @return string The filtered meta description instructions.
		 */
		return apply_filters( 'agentic_wp_meta_description_instructions', $instructions );
	}

	/**
	 * Retrieves meta description tool array for agent system prompts.
	 *
	 * @since 1.0.0
	 *
	 * @return array Meta description tools.
	 */
	public static function get_meta_description_tools(): array {
		if ( class_exists( __NAMESPACE__ . '\\Tools' ) && method_exists( __NAMESPACE__ . '\\Tools', 'get_meta_description_tools' ) ) {
			return Tools::get_meta_description_tools();
		}
		return array();
	}

	/**
	 * Retrieves main agent tool array for agent system prompts.
	 *
	 * @since 1.0.0
	 *
	 * @return array Main agent tools.
	 */
	public static function get_main_agent_tools(): array {
		if ( class_exists( __NAMESPACE__ . '\\Tools' ) && method_exists( '\\Agentic_WP\\Tools', 'get_delegation_tools' ) ) {
			$tools = Tools::get_delegation_tools();

			// Add web search if enabled in settings.
			if ( class_exists( __NAMESPACE__ . '\\Settings' ) && Settings::is_web_search_enabled() ) {
				$tools[] = array( 'type' => 'web_search' );
			}

			return $tools;
		}

		return array();
	}
}
