<?php
/** Verified Gravity Forms entry updates, status changes, and deletion. */

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

/** @return array<string,mixed> */
function wpagent_gravity_entry_write_output_schema(): array {
	return array(
		'type'                 => 'object',
		'additionalProperties' => false,
		'properties'           => array(
			'entry'    => wpagent_gravity_entry_output_schema(),
			'verified' => array( 'type' => 'boolean' ),
		),
	);
}

/** @param array<int,array{type:string,key:string,old:mixed}> $applied */
function wpagent_gravity_entry_rollback( int $entry_id, array $applied ): bool {
	$ok = true;
	foreach ( array_reverse( $applied ) as $change ) {
		$result = 'property' === $change['type']
			? GFAPI::update_entry_property( $entry_id, $change['key'], $change['old'] )
			: GFAPI::update_entry_field( $entry_id, $change['key'], $change['old'] );
		$ok = ! is_wp_error( $result ) && true === $result && $ok;
	}
	return $ok;
}

/** @param mixed $input @return array|WP_Error */
function wpagent_exec_update_gravity_entry( $input ) {
	if ( ! wpagent_gravity_entries_available( array( 'get_entry', 'get_field', 'update_entry_property', 'update_entry_field' ) ) ) {
		return wpagent_gravity_entries_missing_error();
	}
	$input = is_array( $input ) ? $input : array();
	$entry = wpagent_gravity_get_authorized_entry( $input, 'gravityforms_edit_entries' );
	if ( is_wp_error( $entry ) ) {
		return $entry;
	}
	if ( ! wpagent_gravity_entry_expected_version_matches( $input, $entry ) ) {
		return new WP_Error( 'wpagent_gravity_entry_conflict', __( 'Der Gravity-Forms-Eintrag wurde seit dem gelesenen Stand verändert.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	$properties = array();
	foreach ( array( 'is_read', 'is_starred' ) as $key ) {
		if ( array_key_exists( $key, $input ) ) {
			$properties[ $key ] = (bool) $input[ $key ];
		}
	}
	$field_updates = is_array( $input['field_updates'] ?? null ) ? $input['field_updates'] : array();
	if ( count( $field_updates ) > 100 ) {
		return new WP_Error( 'wpagent_gravity_entry_too_many_fields', __( 'Pro Aufruf können höchstens 100 Eintragsfelder geändert werden.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	if ( ! $properties && ! $field_updates ) {
		return new WP_Error( 'wpagent_no_fields', __( 'Keine zu aktualisierende Eintragseigenschaft übergeben.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$seen_fields = array();
	foreach ( $field_updates as $update ) {
		$field_id = is_array( $update ) ? (string) ( $update['field_id'] ?? '' ) : '';
		if ( ! is_array( $update ) || ! array_key_exists( 'value', $update ) || ! ( null === $update['value'] || is_scalar( $update['value'] ) ) || ! preg_match( '/^[1-9]\d*(?:\.\d+)?$/', $field_id ) || isset( $seen_fields[ $field_id ] ) ) {
			return new WP_Error( 'wpagent_gravity_entry_bad_field', __( 'Jede field_id muss eine eindeutige vorhandene numerische Feld- oder Input-ID sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		if ( false === GFAPI::get_field( absint( $entry['form_id'] ?? 0 ), $field_id ) ) {
			return new WP_Error( 'wpagent_gravity_entry_bad_field', __( 'Jede field_id muss eine eindeutige vorhandene numerische Feld- oder Input-ID sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		$seen_fields[ $field_id ] = true;
	}

	$lock = wpagent_companion_acquire_connection_lock();
	if ( is_wp_error( $lock ) ) {
		return $lock;
	}
	try {
		$fresh = GFAPI::get_entry( absint( $entry['id'] ?? 0 ) );
		if ( is_wp_error( $fresh ) || ! is_array( $fresh ) ) {
			return new WP_Error( 'wpagent_gravity_entry_not_found', __( 'Gravity-Forms-Eintrag nicht gefunden.', 'wp-agent-companion' ), array( 'status' => 404 ) );
		}
		if ( ! wpagent_gravity_entry_expected_version_matches( $input, $fresh ) ) {
			return new WP_Error( 'wpagent_gravity_entry_conflict', __( 'Der Gravity-Forms-Eintrag wurde seit dem gelesenen Stand verändert.', 'wp-agent-companion' ), array( 'status' => 409 ) );
		}
		$entry_id = absint( $fresh['id'] ?? 0 );
		$applied  = array();
		$expected = array();
		foreach ( $properties as $key => $value ) {
			$result = GFAPI::update_entry_property( $entry_id, $key, $value );
			if ( is_wp_error( $result ) || true !== $result ) {
				$rollback = wpagent_gravity_entry_rollback( $entry_id, $applied );
				return new WP_Error( 'wpagent_gravity_entry_update_failed', __( 'Der Gravity-Forms-Eintrag konnte nicht vollständig aktualisiert werden.', 'wp-agent-companion' ), array( 'status' => 500, 'rollback_succeeded' => $rollback ) );
			}
			$applied[]        = array( 'type' => 'property', 'key' => $key, 'old' => $fresh[ $key ] ?? null );
			$expected[ $key ] = $value;
		}
		foreach ( $field_updates as $update ) {
			$field_id = (string) $update['field_id'];
			$value    = $update['value'] ?? null;
			$result   = GFAPI::update_entry_field( $entry_id, $field_id, $value );
			if ( is_wp_error( $result ) || true !== $result ) {
				$rollback = wpagent_gravity_entry_rollback( $entry_id, $applied );
				return new WP_Error( 'wpagent_gravity_entry_update_failed', __( 'Der Gravity-Forms-Eintrag konnte nicht vollständig aktualisiert werden.', 'wp-agent-companion' ), array( 'status' => 500, 'rollback_succeeded' => $rollback ) );
			}
			$applied[]             = array( 'type' => 'field', 'key' => $field_id, 'old' => $fresh[ $field_id ] ?? null );
			$expected[ $field_id ] = $value;
		}
		$readback = GFAPI::get_entry( $entry_id );
		if ( is_wp_error( $readback ) || ! is_array( $readback ) || ! wpagent_gravity_subset_matches( $expected, $readback ) ) {
			$rollback = wpagent_gravity_entry_rollback( $entry_id, $applied );
			return new WP_Error( 'wpagent_gravity_entry_verify_failed', __( 'Die Gravity-Forms-Eintragsänderung konnte nicht verifiziert werden und wurde zurückgerollt.', 'wp-agent-companion' ), array( 'status' => 500, 'rollback_succeeded' => $rollback ) );
		}
		return array( 'entry' => wpagent_gravity_entry_payload( $readback, true ), 'verified' => true );
	} finally {
		wpagent_companion_release_connection_lock( $lock );
	}
}

function wpagent_ability_update_gravity_entry(): array {
	$value_schema = array( 'type' => array( 'string', 'integer', 'number', 'boolean', 'null' ) );
	return array(
		'label'               => __( 'Gravity-Forms-Eintrag aktualisieren', 'wp-agent-companion' ),
		'description'         => __( 'Aktualisiert Lesestatus, Markierung oder vorhandene Feldwerte über die öffentliche GFAPI, prüft Konflikte und rollt fehlgeschlagene Teiländerungen zurück.', 'wp-agent-companion' ),
		'category'            => 'wp-agent',
		'input_schema'        => array(
			'type'                 => 'object',
			'additionalProperties' => false,
			'properties'           => array(
				'entry_id'              => array( 'type' => 'integer', 'minimum' => 1 ),
				'expected_date_updated' => array( 'type' => 'string', 'maxLength' => 32 ),
				'is_read'               => array( 'type' => 'boolean' ),
				'is_starred'            => array( 'type' => 'boolean' ),
				'field_updates'         => array(
					'type'     => 'array',
					'minItems' => 1,
					'maxItems' => 100,
					'items'    => array(
						'type'                 => 'object',
						'additionalProperties' => false,
						'properties'           => array(
							'field_id' => array( 'type' => 'string', 'pattern' => '^[1-9]\\d*(?:\\.\\d+)?$' ),
							'value'    => $value_schema,
						),
						'required'             => array( 'field_id', 'value' ),
					),
				),
			),
			'required'             => array( 'entry_id' ),
		),
		'output_schema'       => wpagent_gravity_entry_write_output_schema(),
		'execute_callback'    => 'wpagent_exec_update_gravity_entry',
		'permission_callback' => 'wpagent_perm_gravity_entries_edit',
		'meta'                => array( 'show_in_rest' => true, 'annotations' => array( 'readonly' => false, 'destructive' => false, 'idempotent' => true ) ),
	);
}

function wpagent_ability_set_gravity_entry_status(): array {
	return array(
		'label'               => __( 'Gravity-Forms-Eintragsstatus setzen', 'wp-agent-companion' ),
		'description'         => __( 'Setzt einen Gravity-Forms-Eintrag auf aktiv, Spam oder Papierkorb und verifiziert das Ergebnis per Read-back.', 'wp-agent-companion' ),
		'category'            => 'wp-agent',
		'input_schema'        => array(
			'type'                 => 'object',
			'additionalProperties' => false,
			'properties'           => array(
				'entry_id'              => array( 'type' => 'integer', 'minimum' => 1 ),
				'status'                => array( 'type' => 'string', 'enum' => array( 'active', 'spam', 'trash' ) ),
				'expected_date_updated' => array( 'type' => 'string', 'maxLength' => 32 ),
			),
			'required'             => array( 'entry_id', 'status' ),
		),
		'output_schema'       => wpagent_gravity_entry_write_output_schema(),
		'execute_callback'    => 'wpagent_exec_set_gravity_entry_status',
		'permission_callback' => 'wpagent_perm_gravity_entries_edit',
		'meta'                => array( 'show_in_rest' => true, 'annotations' => array( 'readonly' => false, 'destructive' => true, 'idempotent' => true ) ),
	);
}

/** @param mixed $input @return array|WP_Error */
function wpagent_exec_set_gravity_entry_status( $input ) {
	if ( ! wpagent_gravity_entries_available( array( 'get_entry', 'update_entry_property' ) ) ) {
		return wpagent_gravity_entries_missing_error();
	}
	$input = is_array( $input ) ? $input : array();
	$entry = wpagent_gravity_get_authorized_entry( $input, 'gravityforms_edit_entries' );
	if ( is_wp_error( $entry ) ) {
		return $entry;
	}
	if ( ! wpagent_gravity_entry_expected_version_matches( $input, $entry ) ) {
		return new WP_Error( 'wpagent_gravity_entry_conflict', __( 'Der Gravity-Forms-Eintrag wurde seit dem gelesenen Stand verändert.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	$status = (string) ( $input['status'] ?? '' );
	if ( ! in_array( $status, array( 'active', 'spam', 'trash' ), true ) ) {
		return new WP_Error( 'wpagent_gravity_entry_bad_status', __( 'status muss active, spam oder trash sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$lock   = wpagent_companion_acquire_connection_lock();
	if ( is_wp_error( $lock ) ) {
		return $lock;
	}
	try {
		$fresh = GFAPI::get_entry( absint( $entry['id'] ?? 0 ) );
		if ( is_wp_error( $fresh ) || ! is_array( $fresh ) ) {
			return new WP_Error( 'wpagent_gravity_entry_not_found', __( 'Gravity-Forms-Eintrag nicht gefunden.', 'wp-agent-companion' ), array( 'status' => 404 ) );
		}
		if ( ! wpagent_gravity_entry_expected_version_matches( $input, $fresh ) ) {
			return new WP_Error( 'wpagent_gravity_entry_conflict', __( 'Der Gravity-Forms-Eintrag wurde seit dem gelesenen Stand verändert.', 'wp-agent-companion' ), array( 'status' => 409 ) );
		}
		$entry_id = absint( $fresh['id'] ?? 0 );
		$old      = (string) ( $fresh['status'] ?? '' );
		$result   = GFAPI::update_entry_property( $entry_id, 'status', $status );
		if ( is_wp_error( $result ) || true !== $result ) {
			return new WP_Error( 'wpagent_gravity_entry_status_failed', __( 'Der Gravity-Forms-Eintragsstatus konnte nicht geändert werden.', 'wp-agent-companion' ), array( 'status' => 500 ) );
		}
		$readback = GFAPI::get_entry( $entry_id );
		if ( is_wp_error( $readback ) || ! is_array( $readback ) || $status !== (string) ( $readback['status'] ?? '' ) ) {
			$rollback = GFAPI::update_entry_property( $entry_id, 'status', $old );
			return new WP_Error( 'wpagent_gravity_entry_verify_failed', __( 'Die Gravity-Forms-Eintragsänderung konnte nicht verifiziert werden und wurde zurückgerollt.', 'wp-agent-companion' ), array( 'status' => 500, 'rollback_succeeded' => ! is_wp_error( $rollback ) && true === $rollback ) );
		}
		return array( 'entry' => wpagent_gravity_entry_payload( $readback, true ), 'verified' => true );
	} finally {
		wpagent_companion_release_connection_lock( $lock );
	}
}

function wpagent_ability_delete_gravity_entry(): array {
	return array(
		'label'               => __( 'Gravity-Forms-Eintrag dauerhaft löschen', 'wp-agent-companion' ),
		'description'         => __( 'Löscht einen Gravity-Forms-Eintrag dauerhaft über GFAPI::delete_entry(). confirm=true ist zwingend erforderlich.', 'wp-agent-companion' ),
		'category'            => 'wp-agent',
		'input_schema'        => array(
			'type'                 => 'object',
			'additionalProperties' => false,
			'properties'           => array(
				'entry_id'              => array( 'type' => 'integer', 'minimum' => 1 ),
				'confirm'               => array( 'type' => 'boolean' ),
				'expected_date_updated' => array( 'type' => 'string', 'maxLength' => 32 ),
			),
			'required'             => array( 'entry_id', 'confirm' ),
		),
		'output_schema'       => array(
			'type'                 => 'object',
			'additionalProperties' => false,
			'properties'           => array( 'entry_id' => array( 'type' => 'integer' ), 'deleted' => array( 'type' => 'boolean' ) ),
		),
		'execute_callback'    => 'wpagent_exec_delete_gravity_entry',
		'permission_callback' => 'wpagent_perm_gravity_entries_delete',
		'meta'                => array( 'show_in_rest' => true, 'annotations' => array( 'readonly' => false, 'destructive' => true, 'idempotent' => false ) ),
	);
}

/** @param mixed $input @return array|WP_Error */
function wpagent_exec_delete_gravity_entry( $input ) {
	$input = is_array( $input ) ? $input : array();
	if ( true !== ( $input['confirm'] ?? false ) ) {
		return new WP_Error( 'wpagent_confirmation_required', __( 'Dauerhaftes Löschen erfordert confirm=true.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	if ( ! wpagent_gravity_entries_available( array( 'get_entry', 'delete_entry' ) ) ) {
		return wpagent_gravity_entries_missing_error();
	}
	$entry = wpagent_gravity_get_authorized_entry( $input, 'gravityforms_delete_entries' );
	if ( is_wp_error( $entry ) ) {
		return $entry;
	}
	if ( ! wpagent_gravity_entry_expected_version_matches( $input, $entry ) ) {
		return new WP_Error( 'wpagent_gravity_entry_conflict', __( 'Der Gravity-Forms-Eintrag wurde seit dem gelesenen Stand verändert.', 'wp-agent-companion' ), array( 'status' => 409 ) );
	}
	$lock = wpagent_companion_acquire_connection_lock();
	if ( is_wp_error( $lock ) ) {
		return $lock;
	}
	try {
		$fresh = GFAPI::get_entry( absint( $entry['id'] ?? 0 ) );
		if ( is_wp_error( $fresh ) || ! is_array( $fresh ) ) {
			return new WP_Error( 'wpagent_gravity_entry_not_found', __( 'Gravity-Forms-Eintrag nicht gefunden.', 'wp-agent-companion' ), array( 'status' => 404 ) );
		}
		if ( ! wpagent_gravity_entry_expected_version_matches( $input, $fresh ) ) {
			return new WP_Error( 'wpagent_gravity_entry_conflict', __( 'Der Gravity-Forms-Eintrag wurde seit dem gelesenen Stand verändert.', 'wp-agent-companion' ), array( 'status' => 409 ) );
		}
		$entry_id = absint( $fresh['id'] ?? 0 );
		$deleted  = GFAPI::delete_entry( $entry_id );
		if ( is_wp_error( $deleted ) ) {
			return $deleted;
		}
		if ( true !== $deleted ) {
			return new WP_Error( 'wpagent_gravity_entry_delete_failed', __( 'Der Gravity-Forms-Eintrag konnte nicht gelöscht werden.', 'wp-agent-companion' ), array( 'status' => 500 ) );
		}
		if ( ! is_wp_error( GFAPI::get_entry( $entry_id ) ) ) {
			return new WP_Error( 'wpagent_gravity_entry_delete_unverified', __( 'Gravity Forms meldete den Eintrag als gelöscht, die anschließende Prüfung konnte dies aber nicht bestätigen.', 'wp-agent-companion' ), array( 'status' => 500 ) );
		}
		return array( 'entry_id' => $entry_id, 'deleted' => true );
	} finally {
		wpagent_companion_release_connection_lock( $lock );
	}
}
