<?php
/**
 * Ability: wp-agent/delete-post
 *
 * Die Ability verschiebt Beiträge ausschließlich in den reversiblen
 * Papierkorb. Endgültiges Remote-Löschen ist absichtlich nicht verfügbar,
 * weil der WordPress-Kern dafür keinen belastbaren bedingten Löschvorgang
 * anbietet. Ein force=true-Request scheitert vor jeder Mutation.
 *
 * @package WPAgentCompanion
 */

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

function wpagent_ability_delete_post(): array {
	return array(
		'label'               => __( 'Beitrag in den Papierkorb verschieben', 'wp-agent-companion' ),
		'description'         => __( 'Verschiebt einen Beitrag konfliktgeschützt in den Papierkorb. Endgültiges Remote-Löschen ist aus Sicherheitsgründen nicht verfügbar.', 'wp-agent-companion' ),
		'category'            => 'wp-agent',
		'input_schema'        => array(
			'type'                 => 'object',
			'properties'           => array(
				'post_id'             => array( 'type' => 'integer', 'minimum' => 1 ),
				'expected_state_hash' => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ),
				'force'   => array(
					'type'        => 'boolean',
					'default'     => false,
					'description' => __( 'Endgültiges Remote-Löschen ist nicht verfügbar und wird immer abgewiesen.', 'wp-agent-companion' ),
				),
			),
			'required'             => array( 'post_id', 'expected_state_hash' ),
			'additionalProperties' => false,
		),
		'output_schema'       => array(
			'type'                 => 'object',
			'properties'           => array(
				'post_id'  => array( 'type' => 'integer' ),
				'forced'   => array( 'type' => 'boolean' ),
				'trashed'  => array( 'type' => 'boolean' ),
				'deleted'  => array( 'type' => 'boolean' ),
				'verified' => array( 'type' => 'boolean' ),
				'previous_state_hash' => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ),
				'state_hash' => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ),
			),
			'required'             => array( 'post_id', 'forced', 'trashed', 'deleted', 'verified', 'previous_state_hash', 'state_hash' ),
			'additionalProperties' => false,
		),
		'execute_callback'    => 'wpagent_exec_delete_post',
		'permission_callback' => 'wpagent_perm_edit_posts',
		'meta'                => array(
			'show_in_rest' => true,
			'annotations'  => array(
				'readonly'    => false,
				'destructive' => false,
				'idempotent'  => false,
			),
		),
	);
}

function wpagent_post_delete_candidate_hash( WP_Post $post ): string {
	$state                = wpagent_post_state_values( $post );
	$state['post_status'] = 'trash';
	if ( '0000-00-00 00:00:00' === $post->post_date_gmt ) {
		$state['post_date_gmt'] = get_gmt_from_date( $post->post_date );
	}
	// Core makes a public slug available again while trashing. Its public helper
	// mutates the database, so reproduce its deterministic calculation only.
	$trash_slug           = str_ends_with( $post->post_name, '__trashed' )
		? $post->post_name
		: _truncate_post_slug( $post->post_name, 191 ) . '__trashed';
	$state['post_name']   = wp_unique_post_slug( $trash_slug, $post->ID, 'trash', $post->post_type, (int) $post->post_parent );
	return wpagent_post_state_hash_from_values( $state );
}

function wpagent_post_delete_matches_trash( ?WP_Post $post, WP_Post $before, string $candidate_hash ): bool {
	if ( ! $post instanceof WP_Post || 'trash' !== $post->post_status ) {
		return false;
	}
	// wp_trash_post() gives date-floating drafts a fresh local timestamp. That
	// timestamp cannot be known before the Core write, so verify the exact full
	// state after admitting only that documented normalization.
	if ( in_array( $before->post_status, array( 'draft', 'pending', 'auto-draft' ), true ) && '0000-00-00 00:00:00' === $before->post_date_gmt ) {
		$expected                   = wpagent_post_state_values( $before );
		$expected['post_status']    = 'trash';
		$trash_slug                  = str_ends_with( $before->post_name, '__trashed' )
			? $before->post_name
			: _truncate_post_slug( $before->post_name, 191 ) . '__trashed';
		$expected['post_name']      = wp_unique_post_slug( $trash_slug, $before->ID, 'trash', $before->post_type, (int) $before->post_parent );
		$expected['post_date']      = $post->post_date;
		$expected['post_date_gmt']  = $post->post_date_gmt;
		return '0000-00-00 00:00:00' !== $post->post_date
			&& hash_equals( get_gmt_from_date( $post->post_date ), $post->post_date_gmt )
			&& hash_equals( wpagent_post_state_hash_from_values( $expected ), wpagent_post_state_hash( $post ) );
	}
	return hash_equals( $candidate_hash, wpagent_post_state_hash( $post ) );
}

/** @return WP_Error */
function wpagent_post_delete_recovery_required( int $post_id, string $previous_hash, ?WP_Post $fresh, string $reason ): WP_Error {
	return new WP_Error(
		'wpagent_post_delete_recovery_required',
		__( 'Der Papierkorb-Vorgang konnte nicht vollständig verifiziert werden. Prüfe den aktuellen Beitrag manuell und lies seinen state_hash neu.', 'wp-agent-companion' ),
		array(
			'status'              => 500,
			'post_id'             => $post_id,
			'previous_state_hash' => $previous_hash,
			'current_state_hash'  => $fresh instanceof WP_Post ? wpagent_post_state_hash( $fresh ) : '',
			'rolled_back'         => false,
			'rollback_verified'   => false,
			'recovery_required'   => true,
			'reason'              => $reason,
		)
	);
}

/** @return WP_Error */
function wpagent_post_delete_fail_after_uncertain_trash( int $post_id, WP_Post $before, string $previous_hash, string $candidate_hash, string $lock ): WP_Error {
	$fresh = wpagent_update_post_fresh( $post_id );
	if ( $fresh instanceof WP_Post && hash_equals( $previous_hash, wpagent_post_state_hash( $fresh ) ) ) {
		return new WP_Error( 'wpagent_trash_failed', __( 'In den Papierkorb verschieben fehlgeschlagen.', 'wp-agent-companion' ), array( 'status' => 500, 'rolled_back' => false, 'rollback_verified' => false, 'recovery_required' => false ) );
	}
	return wpagent_post_delete_recovery_required( $post_id, $previous_hash, $fresh, 'trash_error_state_unknown' );
}

/**
 * @param mixed $input
 * @return array|WP_Error
 */
function wpagent_exec_delete_post( $input ) {
	$input   = is_array( $input ) ? $input : array();
	$post_id = (int) ( $input['post_id'] ?? 0 );
	$force   = rest_sanitize_boolean( $input['force'] ?? false );
	if ( ! current_user_can( 'delete_post', $post_id ) ) {
		return new WP_Error( 'wpagent_forbidden', __( 'Keine Berechtigung.', 'wp-agent-companion' ), array( 'status' => 403 ) );
	}
	$post = get_post( $post_id );
	if ( ! $post ) {
		return new WP_Error( 'wpagent_forbidden', __( 'Keine Berechtigung.', 'wp-agent-companion' ), array( 'status' => 403 ) );
	}

	$protection = wpagent_check_protected_post( $post_id );
	if ( is_wp_error( $protection ) ) {
		return $protection;
	}
	if ( $force ) {
		return new WP_Error( 'wpagent_permanent_delete_unavailable', __( 'Endgültiges Remote-Löschen ist nicht verfügbar. Verschiebe den Beitrag in den Papierkorb und führe eine permanente Löschung nur lokal mit einer separaten, beaufsichtigten Administration durch.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	$expected_state_hash = is_string( $input['expected_state_hash'] ?? null ) ? strtolower( $input['expected_state_hash'] ) : '';
	if ( 1 !== preg_match( '/^[a-f0-9]{64}$/D', $expected_state_hash ) ) {
		return new WP_Error( 'wpagent_post_expected_hash', __( 'expected_state_hash muss der vollständige state_hash aus get-post sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$lock = wpagent_update_post_acquire_lock( $post_id );
	if ( is_wp_error( $lock ) ) {
		return $lock;
	}
	try {
		$current = wpagent_update_post_fresh( $post_id );
		if ( ! $current instanceof WP_Post ) {
			return new WP_Error( 'wpagent_forbidden', __( 'Keine Berechtigung.', 'wp-agent-companion' ), array( 'status' => 403 ) );
		}
		if ( ! current_user_can( 'delete_post', $post_id ) || is_wp_error( wpagent_check_protected_post( $post_id ) ) ) {
			return new WP_Error( 'wpagent_forbidden', __( 'Die Berechtigung oder der Schutzstatus änderte sich während der Sperrübernahme.', 'wp-agent-companion' ), array( 'status' => 403 ) );
		}
		$previous_hash = wpagent_post_state_hash( $current );
		if ( ! hash_equals( $expected_state_hash, $previous_hash ) ) {
			return new WP_Error( 'wpagent_post_conflict', __( 'Der Beitrag wurde seit dem Lesen verändert. Lies ihn neu und wiederhole den Vorgang mit dem aktuellen state_hash.', 'wp-agent-companion' ), array( 'status' => 409, 'current_state_hash' => $previous_hash ) );
		}
		if ( ! wpagent_update_post_refresh_lock( $post_id, $lock ) ) {
			return new WP_Error( 'wpagent_post_busy', __( 'Die exklusive Beitragssperre ging vor dem Schreiben verloren.', 'wp-agent-companion' ), array( 'status' => 409 ) );
		}
		if ( 'trash' === $current->post_status ) {
			$fresh = wpagent_update_post_fresh( $post_id );
			if ( ! $fresh instanceof WP_Post || ! hash_equals( $expected_state_hash, wpagent_post_state_hash( $fresh ) ) || ! wpagent_update_post_lock_is_owned( $post_id, $lock ) ) {
				return new WP_Error( 'wpagent_post_conflict', __( 'Der Beitrag änderte sich während der No-op-Prüfung.', 'wp-agent-companion' ), array( 'status' => 409 ) );
			}
			return array( 'post_id' => $post_id, 'forced' => false, 'trashed' => true, 'deleted' => false, 'verified' => true, 'previous_state_hash' => $previous_hash, 'state_hash' => $previous_hash );
		}
		if ( ! wpagent_trash_is_available() ) {
			return wpagent_trash_disabled_error();
		}
		$candidate_hash = wpagent_post_delete_candidate_hash( $current );
		$trashed        = wp_trash_post( $post_id );
		if ( ! $trashed || is_wp_error( $trashed ) ) {
			return wpagent_post_delete_fail_after_uncertain_trash( $post_id, $current, $previous_hash, $candidate_hash, $lock );
		}
		$fresh = wpagent_update_post_fresh( $post_id );
		if ( ! wpagent_post_delete_matches_trash( $fresh, $current, $candidate_hash ) || ! wpagent_update_post_lock_is_owned( $post_id, $lock ) ) {
			return wpagent_post_delete_recovery_required( $post_id, $previous_hash, $fresh, 'trash_readback_or_lock_failed' );
		}
		return array( 'post_id' => $post_id, 'forced' => false, 'trashed' => true, 'deleted' => false, 'verified' => true, 'previous_state_hash' => $previous_hash, 'state_hash' => wpagent_post_state_hash( $fresh ) );
	} finally {
		wpagent_update_post_release_lock( $post_id, $lock );
	}
}
