<?php
/**
 * Ability: wp-agent/reply-to-comment
 *
 * Legt einen neuen, sofort genehmigten Kommentar über wp_insert_comment() an.
 * Ziel ist entweder ein bestehender Kommentar (comment_id, der neue Kommentar
 * wird dessen Kind: comment_parent gesetzt) ODER direkt ein Beitrag (post_id,
 * ein neuer Kommentar auf oberster Ebene, comment_parent bleibt 0). Genau
 * eines von beiden ist Pflicht.
 *
 * Der Autor ist immer der aktuell angemeldete Nutzer (der Bot), nicht ein
 * anonymer/leerer Autor. Das spiegelt exakt, wie WordPress' eigener
 * Kommentar-Einreichungspfad (wp_handle_comment_submission() in
 * wp-includes/comment.php) einen angemeldeten Nutzer behandelt: comment_author
 * = display_name (Fallback auf user_login, falls display_name leer ist),
 * comment_author_email = user_email, comment_author_url = user_url, user_id
 * gesetzt.
 *
 * Bewusst wp_insert_comment() statt des öffentlich-facing wp_new_comment():
 * Letzteres würde zusätzliche, für einen bereits privilegierten internen
 * Aufrufer unpassende Schichten durchlaufen (u. a. Kommentar-Flood- und
 * Duplicate-Checks, die auf anonyme Website-Besucher zielen, sowie eine
 * comment_status=open-Prüfung des Ziel-Beitrags). Diese Ability moderiert
 * bereits über die eigene Capability-Prüfung; ein zusätzliches
 * "sind Kommentare auf diesem Beitrag offen?"-Gate würde einen Bot ausbremsen,
 * der z. B. gezielt auf einem geschlossenen Support-Thread antworten soll.
 *
 * @package WPAgentCompanion
 */

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

if ( ! function_exists( 'wpagent_perm_moderate_comments' ) ) {
	/**
	 * Permission callback: der Aufrufer muss Kommentare moderieren dürfen.
	 *
	 * Siehe die ausführliche Begründung in list-comments.php (identische,
	 * function_exists()-geschützte Definition in allen vier 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_reply_to_comment(): array {
	return array(
		'label'               => __( 'Auf Kommentar antworten', 'wp-agent-companion' ),
		'description'         => __( 'Legt einen neuen, sofort genehmigten Kommentar an: als Antwort auf einen bestehenden Kommentar (comment_id) oder als Kommentar auf oberster Ebene für einen Beitrag (post_id). Genau eines von beiden ist erforderlich. Autor ist immer der aktuell angemeldete Nutzer. Re-Read-verifiziert.', 'wp-agent-companion' ),
		'category'            => 'wp-agent',
		'input_schema'        => array(
			'type'                 => 'object',
			'properties'           => array(
				'comment_id' => array(
					'type'        => 'integer', 'minimum' => 1, 'maximum' => 2147483647,
					'description' => __( 'Kommentar, auf den geantwortet wird. Der neue Kommentar wird dessen Kind (comment_parent); post_id wird daraus abgeleitet.', 'wp-agent-companion' ),
				),
				'post_id'    => array(
					'type'        => 'integer', 'minimum' => 1, 'maximum' => 2147483647,
					'description' => __( 'Beitrag, auf dem ein neuer Kommentar auf oberster Ebene erstellt wird, falls comment_id nicht gesetzt ist.', 'wp-agent-companion' ),
				),
				'content'    => array( 'type' => 'string', 'minLength' => 1, 'maxLength' => 10000 ),
			),
			'required'   => array( 'content' ),
			'additionalProperties' => false,
		),
		'output_schema'       => array(
			'type'                 => 'object',
			'properties'           => array(
				'comment_id' => array( 'type' => 'integer', 'minimum' => 1, 'maximum' => 2147483647 ),
				'post_id'    => array( 'type' => 'integer', 'minimum' => 1, 'maximum' => 2147483647 ),
				'parent'     => array( 'type' => 'integer', 'minimum' => 0, 'maximum' => 2147483647 ),
				'author_id'  => array( 'type' => 'integer', 'minimum' => 1, 'maximum' => 2147483647 ),
				'verified'   => array( 'type' => 'boolean' ),
			),
			'required'             => array( 'comment_id', 'post_id', 'parent', 'author_id', 'verified' ),
			'additionalProperties' => false,
		),
		'execute_callback'    => 'wpagent_exec_reply_to_comment',
		'permission_callback' => 'wpagent_perm_moderate_comments',
		'meta'                => array(
			'show_in_rest' => true,
			'annotations'  => array(
				'readonly'    => false,
				'destructive' => false,
				// Anders als z. B. create-post-from-markdown gibt es hier KEINEN
				// post_id-artigen Upsert-Parameter, der einen Re-Run auf dasselbe
				// Ergebnis abbilden könnte: jeder Aufruf legt zwingend einen neuen
				// Kommentar-Datensatz an. Wiederholte identische Aufrufe erzeugen
				// also mehrere unterschiedliche Kommentare, nicht denselben
				// Endzustand, daher hier bewusst idempotent:false.
				'idempotent'  => false,
			),
		),
	);
}

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

	$content = wpagent_core_mutator_bounded_text( $input['content'] ?? null, 10000 );
	if ( is_wp_error( $content ) ) {
		return new WP_Error( 'wpagent_missing_content', __( 'Inhalt darf nicht leer sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}

	$comment_id_input = 0;
	$post_id_input    = 0;
	if ( array_key_exists( 'comment_id', $input ) ) {
		$comment_id_input = wpagent_core_schema_input_integer( $input['comment_id'], 1, 2147483647, 'comment_id' );
		if ( is_wp_error( $comment_id_input ) ) {
			return $comment_id_input;
		}
	}
	if ( array_key_exists( 'post_id', $input ) ) {
		$post_id_input = wpagent_core_schema_input_integer( $input['post_id'], 1, 2147483647, 'post_id' );
		if ( is_wp_error( $post_id_input ) ) {
			return $post_id_input;
		}
	}

	if ( $comment_id_input <= 0 && $post_id_input <= 0 ) {
		return new WP_Error( 'wpagent_missing_target', __( 'comment_id oder post_id ist erforderlich.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}

	$target_post_id = 0;

	if ( $comment_id_input > 0 ) {
		// Resolve the comment only after WordPress' target-aware meta
		// capability has denied inaccessible and missing IDs alike.
		if ( ! current_user_can( 'edit_comment', $comment_id_input ) ) {
			return new WP_Error( 'wpagent_forbidden', __( 'Keine Berechtigung.', 'wp-agent-companion' ), array( 'status' => 403 ) );
		}
		$parent_comment = get_comment( $comment_id_input );
		if ( ! $parent_comment ) {
			return new WP_Error( 'wpagent_forbidden', __( 'Keine Berechtigung.', 'wp-agent-companion' ), array( 'status' => 403 ) );
		}
		$target_post_id = (int) $parent_comment->comment_post_ID;

		if ( $post_id_input > 0 && $post_id_input !== $target_post_id ) {
			return new WP_Error(
				'wpagent_target_mismatch',
				__( 'post_id gehört nicht zu dem angegebenen comment_id.', 'wp-agent-companion' ),
				array( 'status' => 400 )
			);
		}

	} else {
		$target_post_id = $post_id_input;
		// edit_post statt moderate_comments: löst über WordPress' eigene
		// Meta-Capability-Zuordnung die für DIESEN Beitrag tatsächlich
		// zuständige Capability auf (z. B. edit_pages bei einer Seite).
		if ( ! current_user_can( 'edit_post', $target_post_id ) ) {
			return new WP_Error( 'wpagent_forbidden', __( 'Keine Berechtigung.', 'wp-agent-companion' ), array( 'status' => 403 ) );
		}
		if ( ! get_post( $target_post_id ) ) {
			return new WP_Error( 'wpagent_forbidden', __( 'Keine Berechtigung.', 'wp-agent-companion' ), array( 'status' => 403 ) );
		}
	}

	// Autor = aktueller Nutzer, exakt wie WordPress' eigener
	// wp_handle_comment_submission() einen angemeldeten Nutzer behandelt
	// (siehe Datei-Kommentar oben).
	$user = wp_get_current_user();
	if ( empty( $user->display_name ) ) {
		$user->display_name = $user->user_login;
	}

	$comment_parent = $comment_id_input > 0 ? $comment_id_input : 0;

	$commentdata = array(
		'comment_post_ID'      => $target_post_id,
		'comment_author'       => $user->display_name,
		'comment_author_email' => $user->user_email,
		'comment_author_url'   => $user->user_url,
		'comment_author_IP'    => isset( $_SERVER['REMOTE_ADDR'] ) ? preg_replace( '/[^0-9a-fA-F:., ]/', '', (string) $_SERVER['REMOTE_ADDR'] ) : '',
		'comment_agent'        => isset( $_SERVER['HTTP_USER_AGENT'] ) ? substr( (string) $_SERVER['HTTP_USER_AGENT'], 0, 254 ) : '',
		'comment_content'      => $content,
		'comment_type'         => 'comment',
		'comment_parent'       => $comment_parent,
		'user_id'              => $user->ID,
		// Explizit gesetzt statt auf den wp_insert_comment()-Default (1) zu
		// vertrauen: dieser Wert IST der eigentliche Vertrag der Ability
		// ("als approved"), nicht nur ein zufällig passender Kern-Default.
		'comment_approved'     => 1,
	);

	$filter_comment = false;
	if ( ! current_user_can( 'unfiltered_html' ) && ! has_filter( 'pre_comment_content', 'wp_filter_kses' ) ) {
		$filter_comment = true;
		add_filter( 'pre_comment_content', 'wp_filter_kses' );
	}

	$commentdata = wp_filter_comment( $commentdata );

	if ( $filter_comment ) {
		remove_filter( 'pre_comment_content', 'wp_filter_kses' );
	}

	$new_comment_id = wp_insert_comment( $commentdata );
	if ( ! $new_comment_id ) {
		return new WP_Error( 'wpagent_reply_failed', __( 'Antwort konnte nicht gespeichert werden.', 'wp-agent-companion' ), array( 'status' => 500 ) );
	}
	$new_comment_id = (int) $new_comment_id;
	do_action( 'wpagent_reply_comment_after_insert', $new_comment_id );

	$fresh = get_comment( $new_comment_id );
	$stored_content = (string) wp_unslash( $commentdata['comment_content'] );

	$verified = (
		$fresh instanceof WP_Comment
		&& (string) $fresh->comment_content === $stored_content
		&& '1' === $fresh->comment_approved
		&& (int) $fresh->comment_parent === $comment_parent
		&& (int) $fresh->comment_post_ID === $target_post_id
		&& (int) $fresh->user_id === (int) $user->ID
		&& current_user_can( $comment_id_input > 0 ? 'edit_comment' : 'edit_post', $comment_id_input > 0 ? $comment_id_input : $target_post_id )
	);
	if ( ! $verified ) {
		return wpagent_reply_comment_recovery_required( $new_comment_id, __( 'Die neue Antwort konnte nicht vollständig verifiziert werden. Sie bleibt zur manuellen Prüfung erhalten.', 'wp-agent-companion' ) );
	}

	return array(
		'comment_id' => $new_comment_id,
		'post_id'    => $target_post_id,
		'parent'     => $comment_parent,
		'author_id'  => (int) $user->ID,
		'verified'   => true,
	);
}

/** @return WP_Error */
function wpagent_reply_comment_recovery_required( int $comment_id, string $message ): WP_Error {
	return new WP_Error(
		'wpagent_reply_comment_recovery_required',
		$message,
		array( 'status' => 500, 'comment_id' => $comment_id, 'recovery_required' => true, 'rollback_verified' => false )
	);
}
