<?php
/**
 * Create Comment Tool.
 *
 * Create new comments on posts using wp_insert_comment() with support for
 * author info, parent comments, and status. Validates post exists and accepts comments.
 *
 * @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;
}

/**
 * Create_Comment_Tool class.
 */
class Create_Comment_Tool extends Tool {

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

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

	/**
	 * Get the tool description.
	 *
	 * @return string The tool description.
	 * @since     1.0.0
	 */
	public function get_description() {
		return 'Create a new comment on a post. Respects WordPress discussion settings by default.';
	}

	/**
	 * Get usage instructions for the LLM.
	 *
	 * @return string Instructions for using this tool.
	 * @since     1.0.0
	 */
	public function get_instructions() {
		return <<<'INST'
FORCE PARAMETER:
- force=false (default): Respects WordPress discussion settings. Comment may be blocked if comments are closed, user registration is required, or name/email validation fails. Status is determined by WordPress moderation rules.
- force=true: Bypasses all discussion settings checks. Use to add comments to posts with comments disabled, skip spam/moderation checks, or set an explicit status.

USER ATTRIBUTION:
- user_id=0: Anonymous comment. Requires author and author_email (unless force=true with require_name_email disabled).
- user_id=N (N>0): Registered user. Author name, email, and URL are auto-populated from the user record. Any provided author/author_email/author_url are ignored.
- user_id omitted: Falls back to author fields if provided (anonymous), otherwise uses current logged-in user.

STATUS PARAMETER:
- Only applied when force=true. With force=false, WordPress determines status via moderation rules.
- Values: approve (published), hold (pending moderation), spam, trash.

COMMON PATTERNS:
- Add comment as registered user: { post_id, content, user_id }
- Add anonymous comment: { post_id, content, user_id: 0, author, author_email }
- Force comment on closed post: { post_id, content, user_id, force: true }
- Add pre-approved comment: { post_id, content, user_id, force: true, status: "approve" }
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(
				'post_id'      => array(
					'type'        => 'integer',
					'description' => 'The ID of the post to comment on',
				),
				'content'      => array(
					'type'        => 'string',
					'description' => 'The comment content in plain text or limited HTML format',
				),
				'user_id'      => array(
					'type'        => 'integer',
					'description' => 'User ID to attribute comment to. Use 0 for anonymous. If omitted: uses current user unless author is provided.',
				),
				'author'       => array(
					'type'        => 'string',
					'description' => 'Comment author name. Required for anonymous comments if require_name_email is enabled.',
				),
				'author_email' => array(
					'type'        => 'string',
					'description' => 'Comment author email. Required for anonymous comments if require_name_email is enabled.',
					'format'      => 'email',
				),
				'author_url'   => array(
					'type'        => 'string',
					'description' => 'Comment author URL',
				),
				'parent'       => array(
					'type'        => 'integer',
					'description' => 'Parent comment ID for replies',
				),
				'status'       => array(
					'type'        => 'string',
					'description' => 'Comment status. Only applied when force=true; otherwise WordPress determines status.',
					'enum'        => array( 'approve', 'hold', 'spam', 'trash' ),
				),
				'force'        => array(
					'type'        => 'boolean',
					'description' => 'Bypass discussion settings (comments_open, comment_registration, require_name_email) and force status.',
					'default'     => false,
				),
			),
			'required'   => array( 'post_id', 'content' ),
		);
	}

	/**
	 * 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( 'moderate_comments' );
	}

	/**
	 * 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 false;
	}

	/**
	 * 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 ) {
		$post_id = intval( $args['post_id'] ?? 0 );
		$content = $args['content'] ?? '';
		$force   = ! empty( $args['force'] );

		if ( ! $post_id ) {
			return $this->error_response( 'Post ID is required.' );
		}

		if ( empty( $content ) ) {
			return $this->error_response( 'Comment content is required.' );
		}

		$post = get_post( $post_id );
		if ( ! $post ) {
			return $this->error_response(
				'Post not found.',
				array(
					'post_id' => $post_id,
					'hint'    => 'Verify the post ID exists using the get_post tool.',
				)
			);
		}

		// Determine user_id and build author data
		$current_user = wp_get_current_user();
		if ( isset( $args['user_id'] ) ) {
			$user_id = intval( $args['user_id'] );
		} elseif ( isset( $args['author'] ) ) {
			// Author provided without user_id = anonymous
			$user_id = 0;
		} else {
			// No user_id, no author = current user
			$user_id = $current_user->ID;
		}

		$is_anonymous = 0 === $user_id;

		// Build author data based on user_id
		if ( $user_id > 0 ) {
			$user = get_userdata( $user_id );
			if ( ! $user ) {
				return $this->error_response(
					"Invalid user_id: user {$user_id} does not exist.",
					array( 'hint' => 'Use user_id=0 for anonymous comments, or provide a valid user ID. Use list_users tool to find valid user IDs.' )
				);
			}
			$author_data = array(
				'user_id'              => $user_id,
				'comment_author'       => $user->display_name,
				'comment_author_email' => $user->user_email,
				'comment_author_url'   => $user->user_url ?? '',
			);
		} else {
			// Anonymous comment
			$author_data = array(
				'user_id'              => 0,
				'comment_author'       => isset( $args['author'] ) ? sanitize_text_field( $args['author'] ) : '',
				'comment_author_email' => isset( $args['author_email'] ) ? sanitize_email( $args['author_email'] ) : '',
				'comment_author_url'   => isset( $args['author_url'] ) ? esc_url_raw( $args['author_url'] ) : '',
			);
		}

		// Check discussion settings (unless force=true)
		if ( ! $force ) {
			if ( ! comments_open( $post_id ) ) {
				return $this->error_response(
					'Comments are closed on this post.',
					array(
						'post_id' => $post_id,
						'hint'    => 'Use force=true to bypass this check, or enable comments on the post first.',
					)
				);
			}

			if ( $is_anonymous && get_option( 'comment_registration' ) ) {
				return $this->error_response(
					'This site requires users to be registered and logged in to comment.',
					array( 'hint' => 'Use force=true to bypass, or provide a valid user_id instead of anonymous.' )
				);
			}

			if ( $is_anonymous && get_option( 'require_name_email' ) ) {
				return $this->error_response(
					'Name and email are required for anonymous comments on this site.',
					array( 'hint' => 'Provide author and author_email parameters, use force=true to bypass, or use a registered user_id.' )
				);
			}
		}

		// Build comment data
		$comment_data = array(
			'comment_post_ID'      => $post_id,
			'comment_content'      => $content,
			'comment_author'       => $author_data['comment_author'],
			'comment_author_email' => $author_data['comment_author_email'],
			'comment_author_url'   => $author_data['comment_author_url'],
			'comment_parent'       => intval( $args['parent'] ?? 0 ),
			'user_id'              => $author_data['user_id'],
		);

		if ( $force ) {
			// Use wp_insert_comment for full control
			$comment_data['comment_approved'] = isset( $args['status'] )
				? self::status_to_approved( $args['status'] )
				: 1;
			$comment_id                       = wp_insert_comment( $comment_data );
		} else {
			// Use wp_new_comment to respect WordPress validation/moderation
			$comment_id = wp_new_comment( $comment_data, true );
		}

		if ( is_wp_error( $comment_id ) ) {
			return $this->error_response(
				$comment_id->get_error_message(),
				array( 'error_code' => $comment_id->get_error_code() )
			);
		}

		if ( ! $comment_id ) {
			return $this->error_response( 'Failed to create comment.' );
		}

		return $this->success_response(
			'Comment created successfully.',
			array(
				'comment_id' => $comment_id,
				'post_id'    => $post_id,
				'status'     => self::approved_to_status( wp_get_comment_status( $comment_id ) ),
				'user_id'    => $author_data['user_id'],
				'author'     => $author_data['comment_author'],
			)
		);
	}

	/**
	 * Convert comment tool status string to WordPress comment_approved value.
	 *
	 * @param string $status Status string ('approve', 'hold', 'spam', 'trash').
	 * @return int|string The comment_approved value (1, 0, 'spam', 'trash').
	 * @since     1.0.0
	 */
	public static function status_to_approved( $status ) {
		$map = array(
			'approve' => 1,
			'hold'    => 0,
			'spam'    => 'spam',
			'trash'   => 'trash',
		);
		return $map[ $status ] ?? 1;
	}

	/**
	 * Convert WordPress comment_approved value to comment tool status string.
	 *
	 * @param int|string $approved The comment_approved value.
	 * @return string Status string ('approve', 'hold', 'spam', 'trash').
	 * @since     1.0.0
	 */
	public static function approved_to_status( $approved ) {
		$map = array(
			'1'     => 'approve',
			'0'     => 'hold',
			'spam'  => 'spam',
			'trash' => 'trash',
		);
		return $map[ (string) $approved ] ?? 'hold';
	}
}
