<?php
/**
 * Ability: wp-agent/list-comments
 *
 * Read-only. Listet Kommentare mit optionalem Beitrags-, Status- und
 * Paginierungs-Filter als schlanke Liste (id, post_id, parent, author,
 * author_email, content, status, date) plus Gesamtzahl. Nutzt get_comments()
 * zweimal: einmal für die paginierten Treffer, einmal mit dem eingebauten
 * 'count' => true Query-Var für die Gesamtzahl (siehe
 * WP_Comment_Query::get_comments()), analog zu list-posts.php, das denselben
 * Zweck über WP_Query::$found_posts löst.
 *
 * Die 'status'-Angabe wird 1:1 an get_comments() durchgereicht (Default
 * 'all' = genehmigt + wartend, ohne Spam/Papierkorb). Akzeptiert u. a.
 * 'hold', 'approve', 'spam', 'trash', 'all' oder 'any' (WordPress' eigenes
 * Vokabular für WP_Comment_Query, siehe deren Doku-Kommentar).
 *
 * @package WPAgentCompanion
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

if ( ! function_exists( 'wpagent_perm_moderate_comments' ) ) {
	/**
	 * Permission callback: der Aufrufer muss Kommentare moderieren dürfen.
	 *
	 * Grobe Schranke für die gesamte Kommentare-Ability-Gruppe (list-comments,
	 * moderate-comment, reply-to-comment, delete-comment). Für Abilities mit
	 * einem konkreten Kommentar-Ziel kommt zusätzlich im execute_callback ein
	 * feingranularer current_user_can( 'edit_comment', $comment_id )-Check dazu,
	 * analog zum edit_post-Feincheck der Content-Lifecycle-Abilities in
	 * update-post.php/get-post.php.
	 *
	 * Absichtlich als eigene, mit function_exists() abgesicherte Definition in
	 * dieser Datei statt in includes/helpers.php: Diese Phase legt ausschließlich
	 * neue Dateien an, geteilte Dateien bleiben der Integrationsphase
	 * vorbehalten. Dieselbe Definition steht identisch (function_exists()-
	 * geschützt) auch in den drei anderen neuen Kommentare-Ability-Dateien,
	 * damit keine Ladereihenfolge zwischen ihnen vorausgesetzt werden muss.
	 *
	 * @param mixed $input Ungenutzter Ability-Input.
	 * @return bool
	 */
	function wpagent_perm_moderate_comments( $input = null ): bool {
		return current_user_can( 'moderate_comments' );
	}
}

function wpagent_ability_list_comments(): array {
	return array(
		'label'               => __( 'Kommentare auflisten', 'wp-agent-companion' ),
		'description'         => __( 'Listet Kommentare mit optionalem Beitrags-, Status- und Paginierungs-Filter als schlanke Liste (id, post_id, parent, author, author_email, content, status, date) plus Gesamtzahl.', 'wp-agent-companion' ),
		'category'            => 'wp-agent',
		'input_schema'        => array(
			'type'       => 'object',
			'properties' => array(
				'post_id'  => array(
					'type'        => 'integer',
					'description' => __( 'Optional: nur Kommentare zu diesem Beitrag.', 'wp-agent-companion' ),
				),
				'status'   => array(
					'type'        => 'string',
					'default'     => 'all',
					'description' => __( 'Wird an get_comments() durchgereicht. Akzeptiert u. a. hold, approve, spam, trash, all (Default, ohne Spam/Papierkorb) oder any (wirklich alle Stati).', 'wp-agent-companion' ),
				),
				'per_page' => array(
					'type'    => 'integer',
					'default' => 20,
				),
				'page'     => array(
					'type'    => 'integer',
					'default' => 1,
				),
			),
		),
		'output_schema'       => array(
			'type'       => 'object',
			'properties' => array(
				'items' => array(
					'type'  => 'array',
					'items' => array(
						'type'       => 'object',
						'properties' => array(
							'id'           => array( 'type' => 'integer' ),
							'post_id'      => array( 'type' => 'integer' ),
							'parent'       => array( 'type' => 'integer' ),
							'author'       => array( 'type' => 'string' ),
							'author_email' => array( 'type' => 'string' ),
							'content'      => array( 'type' => 'string' ),
							'status'       => array( 'type' => 'string' ),
							'date'         => array( 'type' => 'string' ),
						),
					),
				),
				'total' => array( 'type' => 'integer' ),
			),
		),
		'execute_callback'    => 'wpagent_exec_list_comments',
		'permission_callback' => 'wpagent_perm_moderate_comments',
		'meta'                => array(
			'show_in_rest' => true,
			'annotations'  => array(
				'readonly'    => true,
				'destructive' => false,
				'idempotent'  => true,
			),
		),
	);
}

/**
 * @param mixed $input
 * @return array|WP_Error
 */
function wpagent_exec_list_comments( $input ) {
	$input = is_array( $input ) ? $input : array();

	$post_id = isset( $input['post_id'] ) ? (int) $input['post_id'] : 0;
	if ( $post_id > 0 && ! get_post( $post_id ) ) {
		return new WP_Error( 'wpagent_no_post', __( 'Beitrag nicht gefunden.', 'wp-agent-companion' ), array( 'status' => 404 ) );
	}

	$status = (string) ( $input['status'] ?? 'all' );
	if ( '' === $status ) {
		$status = 'all';
	}

	$per_page = (int) ( $input['per_page'] ?? 20 );
	if ( $per_page <= 0 ) {
		$per_page = 20;
	}
	$per_page = min( $per_page, 100 );

	$page = (int) ( $input['page'] ?? 1 );
	if ( $page <= 0 ) {
		$page = 1;
	}

	$query_args = array(
		'status' => $status,
		'number' => $per_page,
		'paged'  => $page,
		'order'  => 'DESC',
	);
	if ( $post_id > 0 ) {
		$query_args['post_id'] = $post_id;
	}

	$comments = get_comments( $query_args );

	// get_comments() liefert bei 'count' => true direkt einen int zurück (siehe
	// WP_Comment_Query::get_comments()); dieselben Filter OHNE Paginierung
	// liefern so die Gesamtzahl, ohne den WP_Comment_Query-Objektzustand separat
	// auslesen zu müssen (kein Zugriff auf ->found_comments nötig).
	$count_args          = $query_args;
	$count_args['count'] = true;
	unset( $count_args['number'], $count_args['paged'], $count_args['order'] );
	$total = (int) get_comments( $count_args );

	$items = array();
	foreach ( $comments as $comment ) {
		$items[] = array(
			'id'           => (int) $comment->comment_ID,
			'post_id'      => (int) $comment->comment_post_ID,
			'parent'       => (int) $comment->comment_parent,
			'author'       => $comment->comment_author,
			'author_email' => $comment->comment_author_email,
			'content'      => $comment->comment_content,
			// wp_get_comment_status() liest hier zwar den bereits über
			// get_comments() gecachten Kommentar erneut aus (WP-Objektcache,
			// keine erneute DB-Anfrage), gibt dafür aber garantiert exakt das
			// vom WordPress-Kern selbst definierte Status-Vokabular zurück
			// (approved/unapproved/spam/trash) statt einer eigenen, doppelt
			// gepflegten Neuinterpretation von comment_approved.
			'status'       => wp_get_comment_status( $comment->comment_ID ),
			'date'         => $comment->comment_date,
		);
	}

	return array(
		'items' => $items,
		'total' => $total,
	);
}
