<?php
/**
 * Ability: wp-agent/delete-media
 *
 * The remote path only moves an attachment into the reversible Core trash.
 * Permanent attachment/file deletion has no trustworthy conditional Core
 * primitive, so force=true is rejected before every mutation.
 *
 * @package WPAgentCompanion
 */

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

function wpagent_ability_delete_media(): array {
	return array(
		'label'               => __( 'Medienbeitrag in den Papierkorb verschieben', 'wp-agent-companion' ),
		'description'         => __( 'Verschiebt einen Medienbeitrag 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(
				'attachment_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( 'attachment_id', 'expected_state_hash' ),
			'additionalProperties' => false,
		),
		'output_schema'       => array(
			'type'                 => 'object',
			'properties'           => array(
				'attachment_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( 'attachment_id', 'forced', 'trashed', 'deleted', 'verified', 'previous_state_hash', 'state_hash' ),
			'additionalProperties' => false,
		),
		'execute_callback'    => 'wpagent_exec_delete_media',
		'permission_callback' => 'wpagent_perm_edit_posts',
		'meta'                => array(
			'show_in_rest' => true,
			'annotations'  => array(
				'readonly'    => false,
				'destructive' => false,
				'idempotent'  => false,
			),
		),
	);
}

/** @param array<int,string> $alt_values */
function wpagent_media_delete_candidate_hash( WP_Post $attachment, array $alt_values ): string {
	$post_state                = wpagent_post_state_values( $attachment );
	$post_state['post_status'] = 'trash';
	if ( '0000-00-00 00:00:00' === $attachment->post_date_gmt ) {
		$post_state['post_date_gmt'] = get_gmt_from_date( $attachment->post_date );
	}
	$trash_slug                = str_ends_with( $attachment->post_name, '__trashed' )
		? $attachment->post_name
		: _truncate_post_slug( $attachment->post_name, 191 ) . '__trashed';
	$post_state['post_name']   = wp_unique_post_slug( $trash_slug, $attachment->ID, 'trash', $attachment->post_type, (int) $attachment->post_parent );
	return hash(
		'sha256',
		"wpagently-attachment-alt-state-v1\0" . serialize(
			array(
				'post_state_hash' => wpagent_post_state_hash_from_values( $post_state ),
				'alt_meta_values' => array_values( $alt_values ),
			)
		)
	);
}

/** @param array{attachment:WP_Post,snapshot:array{values:array<int,string>,alt:string,state_hash:string}}|null $current */
function wpagent_media_delete_matches_trash( ?array $current, string $candidate_hash ): bool {
	return is_array( $current )
		&& 'trash' === $current['attachment']->post_status
		&& hash_equals( $candidate_hash, $current['snapshot']['state_hash'] );
}

/** @param array{attachment:WP_Post,snapshot:array{values:array<int,string>,alt:string,state_hash:string}}|null $current */
function wpagent_media_delete_recovery_required( int $attachment_id, string $previous_hash, ?array $current, string $reason ): WP_Error {
	return new WP_Error(
		'wpagent_media_delete_recovery_required',
		__( 'Der Papierkorb-Vorgang für das Medium konnte nicht vollständig verifiziert werden. Prüfe den aktuellen Medienbeitrag manuell und lies seinen state_hash neu.', 'wp-agent-companion' ),
		array(
			'status'              => 500,
			'attachment_id'       => $attachment_id,
			'previous_state_hash' => $previous_hash,
			'current_state_hash'  => is_array( $current ) ? $current['snapshot']['state_hash'] : '',
			'rolled_back'         => false,
			'rollback_verified'   => false,
			'recovery_required'   => true,
			'reason'              => $reason,
		)
	);
}

/**
 * @param array{attachment:WP_Post,snapshot:array{values:array<int,string>,alt:string,state_hash:string}} $before
 * @return WP_Error
 */
function wpagent_media_delete_fail_after_uncertain_trash( int $attachment_id, array $before, string $candidate_hash, string $lock ): WP_Error {
	$fresh = wpagent_attachment_alt_current( $attachment_id );
	if ( ! is_wp_error( $fresh ) && hash_equals( $before['snapshot']['state_hash'], $fresh['snapshot']['state_hash'] ) ) {
		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_media_delete_recovery_required( $attachment_id, $before['snapshot']['state_hash'], is_array( $fresh ) ? $fresh : null, 'trash_error_state_unknown' );
}

/**
 * @param mixed $input
 * @return array|WP_Error
 */
function wpagent_exec_delete_media( $input ) {
	$input         = is_array( $input ) ? $input : array();
	$attachment_id = (int) ( $input['attachment_id'] ?? 0 );
	$force         = rest_sanitize_boolean( $input['force'] ?? false );
	if ( ! current_user_can( 'delete_post', $attachment_id ) ) {
		return new WP_Error( 'wpagent_forbidden', __( 'Keine Berechtigung.', 'wp-agent-companion' ), array( 'status' => 403 ) );
	}
	$attachment = get_post( $attachment_id );
	if ( ! $attachment ) {
		return new WP_Error( 'wpagent_forbidden', __( 'Keine Berechtigung.', 'wp-agent-companion' ), array( 'status' => 403 ) );
	}
	if ( 'attachment' !== $attachment->post_type ) {
		return new WP_Error( 'wpagent_no_media', __( 'Medienbeitrag nicht gefunden.', 'wp-agent-companion' ), array( 'status' => 404 ) );
	}
	if ( $force ) {
		return new WP_Error( 'wpagent_permanent_delete_unavailable', __( 'Endgültiges Remote-Löschen von Medien ist nicht verfügbar. Verschiebe das Medium 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_attachment_expected_hash', __( 'expected_state_hash muss der vollständige state_hash aus list-media sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$lock = wpagent_update_post_acquire_lock( $attachment_id );
	if ( is_wp_error( $lock ) ) {
		return $lock;
	}
	try {
		$current = wpagent_attachment_alt_current( $attachment_id );
		if ( is_wp_error( $current ) ) {
			return new WP_Error( 'wpagent_forbidden', __( 'Keine Berechtigung.', 'wp-agent-companion' ), array( 'status' => 403 ) );
		}
		if ( ! current_user_can( 'delete_post', $attachment_id ) ) {
			return new WP_Error( 'wpagent_forbidden', __( 'Keine Berechtigung.', 'wp-agent-companion' ), array( 'status' => 403 ) );
		}
		$previous_hash = $current['snapshot']['state_hash'];
		if ( ! hash_equals( $expected_state_hash, $previous_hash ) ) {
			return new WP_Error( 'wpagent_attachment_conflict', __( 'Das Medium wurde seit dem Lesen verändert. Lies es 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( $attachment_id, $lock ) ) {
			return new WP_Error( 'wpagent_attachment_busy', __( 'Die exklusive Mediensperre ging vor dem Schreiben verloren.', 'wp-agent-companion' ), array( 'status' => 409 ) );
		}
		if ( 'trash' === $current['attachment']->post_status ) {
			$fresh = wpagent_attachment_alt_current( $attachment_id );
			if ( is_wp_error( $fresh ) || ! hash_equals( $expected_state_hash, is_array( $fresh ) ? $fresh['snapshot']['state_hash'] : '' ) || ! wpagent_update_post_lock_is_owned( $attachment_id, $lock ) ) {
				return new WP_Error( 'wpagent_attachment_conflict', __( 'Das Medium änderte sich während der No-op-Prüfung.', 'wp-agent-companion' ), array( 'status' => 409 ) );
			}
			return array( 'attachment_id' => $attachment_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_media_delete_candidate_hash( $current['attachment'], $current['snapshot']['values'] );
		$trashed        = wp_trash_post( $attachment_id );
		if ( ! $trashed || is_wp_error( $trashed ) ) {
			return wpagent_media_delete_fail_after_uncertain_trash( $attachment_id, $current, $candidate_hash, $lock );
		}
		$fresh = wpagent_attachment_alt_current( $attachment_id );
		if ( is_wp_error( $fresh ) || ! wpagent_media_delete_matches_trash( $fresh, $candidate_hash ) || ! wpagent_update_post_lock_is_owned( $attachment_id, $lock ) ) {
			return wpagent_media_delete_recovery_required( $attachment_id, $previous_hash, is_array( $fresh ) ? $fresh : null, 'trash_readback_or_lock_failed' );
		}
		return array( 'attachment_id' => $attachment_id, 'forced' => false, 'trashed' => true, 'deleted' => false, 'verified' => true, 'previous_state_hash' => $previous_hash, 'state_hash' => $fresh['snapshot']['state_hash'] );
	} finally {
		wpagent_update_post_release_lock( $attachment_id, $lock );
	}
}
