<?php
/** Fluent Forms create, update, duplicate and delete abilities. */

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

/** @return array<string,mixed> */
function wpagent_fluent_forms_write_properties_schema(): array {
	return array(
		'title' => array( 'type' => 'string', 'minLength' => 1, 'maxLength' => 255 ),
		'status' => array( 'type' => 'string', 'enum' => array( 'published', 'unpublished' ) ),
		'submit_label' => array( 'type' => 'string', 'minLength' => 1, 'maxLength' => 255 ),
	);
}

/** @return array<string,mixed> */
function wpagent_fluent_forms_write_output_schema(): array {
	return wpagent_forms_public_object_schema( array( 'form' => wpagent_fluent_forms_form_output_schema(), 'verified' => array( 'type' => 'boolean' ) ), array( 'form', 'verified' ) );
}

/** @param mixed $form @return array{form:array<string,mixed>,verified:bool}|WP_Error */
function wpagent_fluent_forms_readback( object $service, int $form_id, $form ) {
	try {
		$fresh = $service->find( $form_id );
	} catch ( Throwable $error ) {
		return new WP_Error( 'wpagent_fluent_forms_readback_failed', __( 'Das Fluent-Forms-Formular wurde gespeichert, konnte aber nicht erneut gelesen werden.', 'wp-agent-companion' ), array( 'status' => 500 ) );
	}
	$expected = wpagent_fluent_forms_form_payload( $form );
	$actual   = wpagent_fluent_forms_form_payload( $fresh );
	$verified = $expected['id'] === $actual['id']
		&& $expected['title'] === $actual['title']
		&& $expected['status'] === $actual['status']
		&& wp_json_encode( $expected['form_fields'] ) === wp_json_encode( $actual['form_fields'] );
	$payload = wpagent_fluent_forms_public_form_payload( $fresh );
	return is_wp_error( $payload ) ? $payload : array( 'form' => $payload, 'verified' => $verified );
}

/** @param array<string,mixed> $attributes @param mixed $current @return array<string,mixed> */
function wpagent_fluent_forms_expected_payload( array $attributes, $current ): array {
	$expected = wpagent_fluent_forms_form_payload( $current );
	if ( array_key_exists( 'title', $attributes ) ) {
		$expected['title'] = sanitize_text_field( (string) $attributes['title'] );
	}
	if ( array_key_exists( 'status', $attributes ) ) {
		$expected['status'] = sanitize_key( (string) $attributes['status'] );
	}
	if ( array_key_exists( 'formFields', $attributes ) ) {
		$expected['form_fields'] = wpagent_fluent_forms_json_object( $attributes['formFields'] );
	}
	return $expected;
}

/** @param mixed $value @return mixed */
function wpagent_fluent_forms_canonical_candidate_value( $value ) {
	return wpagent_fluent_forms_canonicalize_state( $value );
}

/** @param mixed $form */
function wpagent_fluent_forms_candidate_hash( $form ): string {
	$state   = wpagent_fluent_forms_canonical_candidate_value( wpagent_fluent_forms_model_array( $form ) );
	$encoded = wp_json_encode( $state, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE );
	return hash( 'sha256', false === $encoded ? serialize( $state ) : $encoded );
}

/** @param array<string,mixed> $expected @param mixed $current */
function wpagent_fluent_forms_expected_candidate_hash( $current, array $expected ): string {
	$candidate = wpagent_fluent_forms_model_array( $current );
	foreach ( array( 'id', 'title', 'status' ) as $key ) {
		if ( array_key_exists( $key, $expected ) ) {
			$candidate[ $key ] = $expected[ $key ];
		}
	}
	if ( array_key_exists( 'form_fields', $expected ) ) {
		$encoded = wp_json_encode( $expected['form_fields'] );
		if ( false !== $encoded ) {
			$candidate['form_fields'] = $encoded;
		}
	}
	return wpagent_fluent_forms_candidate_hash( $candidate );
}

function wpagent_fluent_forms_delete_owned_candidate( object $service, int $form_id, string $candidate_hash ): bool {
	// Fluent Forms has no conditional delete. A fresh hash cannot serialize a
	// native editor write between this check and the provider delete.
	return false;
}

function wpagent_fluent_forms_recovery_required( int $form_id ): WP_Error {
	return new WP_Error( 'wpagent_fluent_forms_recovery_required', __( 'Die Fluent-Forms-Änderung könnte teilweise gespeichert worden sein. Der aktuelle Zustand muss vor einem weiteren Schreibversuch manuell geprüft werden.', 'wp-agent-companion' ), array( 'status' => 409, 'recovery_required' => true, 'form_id' => $form_id ) );
}

/**
 * Field writers own an independently bounded form_fields snapshot and retain
 * their established provider-specific recovery contract. Form-level updates
 * deliberately never call this helper because they cannot prove that a full
 * snapshot still belongs to them after a partial provider write.
 *
 * @param array<string,mixed> $snapshot
 */
function wpagent_fluent_forms_restore_snapshot( object $service, array $snapshot ): bool {
	// A snapshot restore is another unconditioned provider update and could
	// overwrite a native editor change. Preserve the observed state instead.
	return false;
}

/** @param array<string,mixed> $input @param mixed $current @return array<string,mixed>|WP_Error */
function wpagent_fluent_forms_update_attributes( array $input, $current, bool $allow_trusted_fields = false ) {
	$current = wpagent_fluent_forms_form_payload( $current );
	$allowed = $allow_trusted_fields ? array( 'title', 'status', 'submit_label', 'form_fields' ) : array( 'title', 'status', 'submit_label' );
	$changes = array_intersect_key( $input, array_flip( $allowed ) );
	if ( ! $changes ) {
		return new WP_Error( 'wpagent_no_fields', __( 'Keine zu aktualisierende Formulareigenschaft übergeben.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$title = array_key_exists( 'title', $changes ) ? trim( (string) $changes['title'] ) : $current['title'];
	if ( '' === $title ) {
		return new WP_Error( 'wpagent_fluent_forms_title_required', __( 'Der Formulartitel darf nicht leer sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$attributes = array(
		'form_id' => $current['id'], 'title' => $title,
		'status' => array_key_exists( 'status', $changes ) ? (string) $changes['status'] : $current['status'],
	);
	if ( array_key_exists( 'form_fields', $changes ) || array_key_exists( 'submit_label', $changes ) ) {
		$form_fields = array_key_exists( 'form_fields', $changes ) ? $changes['form_fields'] : $current['form_fields'];
		if ( array_key_exists( 'submit_label', $changes ) ) {
			$submit_label = sanitize_text_field( trim( (string) $changes['submit_label'] ) );
			if ( '' === $submit_label ) {
				return new WP_Error( 'wpagent_fluent_forms_submit_label_required', __( 'Die Beschriftung der Absende-Schaltfläche darf nicht leer sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
			}
			if ( ! isset( $form_fields['submitButton'] ) || ! is_array( $form_fields['submitButton'] ) ) {
				return new WP_Error( 'wpagent_fluent_forms_bad_fields', __( 'Die gespeicherte Fluent-Forms-Schaltflächenstruktur ist ungültig.', 'wp-agent-companion' ), array( 'status' => 500 ) );
			}
			$form_fields['submitButton']['settings']['button_ui']['text'] = $submit_label;
		}
		$encoded = wpagent_fluent_forms_encode_fields( $form_fields );
		if ( is_wp_error( $encoded ) ) {
			return $encoded;
		}
		$attributes['formFields'] = $encoded;
	}
	return $attributes;
}

function wpagent_ability_create_fluent_form(): array {
	return array(
		'label' => __( 'Fluent-Forms-Formular erstellen', 'wp-agent-companion' ),
		'description' => __( 'Erstellt ein leeres Fluent-Forms-Formular über den nativen FormService, setzt Titel, Status und die Absende-Beschriftung und verifiziert das Ergebnis per Read-back. Felder werden anschließend über die sichere Feld-Ability angelegt.', 'wp-agent-companion' ),
		'category' => 'wp-agent',
		'input_schema' => array( 'type' => 'object', 'additionalProperties' => false, 'properties' => wpagent_fluent_forms_write_properties_schema(), 'required' => array( 'title' ) ),
		'output_schema' => wpagent_fluent_forms_write_output_schema(),
		'execute_callback' => 'wpagent_exec_create_fluent_form',
		'permission_callback' => 'wpagent_perm_fluent_forms_manage',
		'meta' => array( 'show_in_rest' => true, 'annotations' => array( 'readonly' => false, 'destructive' => false, 'idempotent' => false ) ),
	);
}

/** @param mixed $input @return array|WP_Error */
function wpagent_exec_create_fluent_form( $input ) {
	return wpagent_exec_create_fluent_form_internal( $input, false );
}

/** @param mixed $input @return array|WP_Error */
function wpagent_exec_create_fluent_form_internal( $input, bool $allow_trusted_fields ) {
	$input = is_array( $input ) ? $input : array();
	if ( ! wpagent_perm_fluent_forms_manage() ) {
		return new WP_Error( 'wpagent_forbidden', __( 'Keine Berechtigung zum Erstellen von Fluent-Forms-Formularen.', 'wp-agent-companion' ), array( 'status' => 403 ) );
	}
	if ( ! $allow_trusted_fields ) {
		unset( $input['form_fields'] );
	}
	$title = trim( (string) ( $input['title'] ?? '' ) );
	if ( '' === $title ) {
		return new WP_Error( 'wpagent_fluent_forms_title_required', __( 'Ein nicht leerer Formulartitel ist erforderlich.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$service = wpagent_fluent_forms_service();
	if ( is_wp_error( $service ) ) {
		return $service;
	}
	try {
		$created = $service->store( array( 'title' => $title, 'predefined' => 'blank_form', 'type' => 'form' ) );
	} catch ( Throwable $error ) {
		return new WP_Error( 'wpagent_fluent_forms_create_failed', __( 'Das Fluent-Forms-Formular konnte nicht erstellt werden.', 'wp-agent-companion' ), array( 'status' => 500 ) );
	}
	$created_data = wpagent_fluent_forms_model_array( $created );
	$form_id      = absint( $created_data['id'] ?? 0 );
	if ( $form_id <= 0 ) {
		return new WP_Error( 'wpagent_fluent_forms_create_failed', __( 'Das Fluent-Forms-Formular konnte nicht erstellt werden.', 'wp-agent-companion' ), array( 'status' => 500 ) );
	}
	$created_hash = wpagent_fluent_forms_candidate_hash( $created );
	$attributes = wpagent_fluent_forms_update_attributes( array_merge( array( 'title' => $title ), $input ), $created, $allow_trusted_fields );
	if ( is_wp_error( $attributes ) ) {
		if ( ! wpagent_fluent_forms_delete_owned_candidate( $service, $form_id, $created_hash ) ) {
			return wpagent_fluent_forms_recovery_required( $form_id );
		}
		return $attributes;
	}
	$expected = wpagent_fluent_forms_expected_payload( $attributes, $created );
	$expected_hash = wpagent_fluent_forms_expected_candidate_hash( $created, $expected );
	try {
		$service->update( $attributes );
	} catch ( Throwable $error ) {
		if ( ! wpagent_fluent_forms_delete_owned_candidate( $service, $form_id, $expected_hash ) ) {
			return wpagent_fluent_forms_recovery_required( $form_id );
		}
		return new WP_Error( 'wpagent_fluent_forms_create_failed', __( 'Das Fluent-Forms-Formular konnte nicht vollständig erstellt werden.', 'wp-agent-companion' ), array( 'status' => 500 ) );
	}
	$readback = wpagent_fluent_forms_readback( $service, $form_id, $expected );
	if ( is_wp_error( $readback ) || true !== $readback['verified'] ) {
		if ( ! wpagent_fluent_forms_delete_owned_candidate( $service, $form_id, $expected_hash ) ) {
			return wpagent_fluent_forms_recovery_required( $form_id );
		}
		return new WP_Error( 'wpagent_fluent_forms_create_unverified', __( 'Das Fluent-Forms-Formular wich nach dem Speichern vom erwarteten Zustand ab und wurde entfernt.', 'wp-agent-companion' ), array( 'status' => 500 ) );
	}
	return $readback;
}

function wpagent_ability_update_fluent_form(): array {
	$properties                  = array_merge( array( 'form_id' => array( 'type' => 'integer', 'minimum' => 1 ) ), wpagent_fluent_forms_write_properties_schema() );
	$properties['expected_hash'] = array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' );
	return array(
		'label' => __( 'Fluent-Forms-Formular aktualisieren', 'wp-agent-companion' ),
		'description' => __( 'Prüft eine Formularänderung gegen den vollständigen aktuellen Formular-Hash. Das Speichern bleibt ohne atomare Fluent-Forms-Compare-and-Update-Operation manuell.', 'wp-agent-companion' ),
		'category' => 'wp-agent',
		'input_schema' => array( 'type' => 'object', 'additionalProperties' => false, 'properties' => $properties, 'required' => array( 'form_id', 'expected_hash' ) ),
		'output_schema' => wpagent_fluent_forms_write_output_schema(),
		'execute_callback' => 'wpagent_exec_update_fluent_form',
		'permission_callback' => 'wpagent_perm_fluent_forms_manage',
		'meta' => array( 'show_in_rest' => true, 'annotations' => array( 'readonly' => false, 'destructive' => false, 'idempotent' => false, 'manual_only' => true ) ),
	);
}

/** @param mixed $input @return array|WP_Error */
function wpagent_exec_update_fluent_form( $input ) {
	$input = is_array( $input ) ? $input : array();
	$form_id       = absint( $input['form_id'] ?? 0 );
	$expected_hash = wpagent_fluent_forms_validate_fields_hash( $input['expected_hash'] ?? '' );
	if ( is_wp_error( $expected_hash ) ) {
		return $expected_hash;
	}
	$lock = wpagent_fluent_forms_fields_acquire_lock( $form_id );
	if ( is_wp_error( $lock ) ) {
		return $lock;
	}
	try {
		if ( ! wpagent_fluent_forms_fields_lock_is_owned( $form_id, $lock ) ) {
			return new WP_Error( 'wpagent_fluent_forms_lock_lost', __( 'Die Sperre für dieses Fluent-Forms-Formular ging verloren. Lies den Zustand erneut.', 'wp-agent-companion' ), array( 'status' => 409 ) );
		}
		$authorized = wpagent_fluent_forms_get_authorized_form( $input );
		if ( is_wp_error( $authorized ) ) {
			return $authorized;
		}
		$current_hash = wpagent_fluent_forms_full_state_hash( $authorized['form'] );
		if ( ! hash_equals( $current_hash, $expected_hash ) ) {
			return new WP_Error( 'wpagent_fluent_forms_conflict', __( 'Das Fluent-Forms-Formular wurde seit dem Lesen verändert.', 'wp-agent-companion' ), array( 'status' => 409, 'current_hash' => $current_hash ) );
		}
		$attributes = wpagent_fluent_forms_update_attributes( $input, $authorized['form'] );
		if ( is_wp_error( $attributes ) ) {
			return $attributes;
		}
		return new WP_Error( 'wpagent_fluent_forms_update_manual_only', __( 'Fluent Forms bietet keine atomare Compare-and-Update-Operation. Diese Formularänderung muss in WordPress manuell vorgenommen werden, damit parallele Editor-Änderungen nicht überschrieben werden.', 'wp-agent-companion' ), array( 'status' => 409, 'form_id' => $form_id, 'current_hash' => $current_hash ) );
	} finally {
		wpagent_fluent_forms_fields_release_lock( $form_id, $lock );
	}
}

/** @param array<string,mixed> $input @param array{service:object,form:mixed}|null $authorized @return array|WP_Error */
function wpagent_exec_update_fluent_form_unlocked( array $input, ?array $authorized = null ) {
	$authorized = $authorized ?? wpagent_fluent_forms_get_authorized_form( $input );
	if ( is_wp_error( $authorized ) ) {
		return $authorized;
	}
	return new WP_Error( 'wpagent_fluent_forms_recovery_required', __( 'Für Fluent-Forms-Formularänderungen gibt es keine atomare Provider-Absicherung. Prüfe den aktuellen Zustand und ändere das Formular manuell.', 'wp-agent-companion' ), array( 'status' => 409, 'recovery_required' => true, 'form_id' => absint( wpagent_fluent_forms_model_array( $authorized['form'] )['id'] ?? 0 ) ) );
}

function wpagent_ability_duplicate_fluent_form(): array {
	return array(
		'label' => __( 'Fluent-Forms-Formular duplizieren', 'wp-agent-companion' ),
		'description' => __( 'Dupliziert ein Fluent-Forms-Formular mit seinen nativen Metadaten und Dateien und verifiziert eine optionale Umbenennung per Read-back. Nicht bestätigte Teiländerungen erfordern eine manuelle Prüfung.', 'wp-agent-companion' ),
		'category' => 'wp-agent',
		'input_schema' => array( 'type' => 'object', 'additionalProperties' => false, 'properties' => array( 'form_id' => array( 'type' => 'integer', 'minimum' => 1 ), 'title' => array( 'type' => 'string', 'minLength' => 1, 'maxLength' => 255 ) ), 'required' => array( 'form_id' ) ),
		'output_schema' => wpagent_fluent_forms_write_output_schema(),
		'execute_callback' => 'wpagent_exec_duplicate_fluent_form',
		'permission_callback' => 'wpagent_perm_fluent_forms_manage',
		'meta' => array( 'show_in_rest' => true, 'annotations' => array( 'readonly' => false, 'destructive' => false, 'idempotent' => false ) ),
	);
}

/** @param mixed $input @return array|WP_Error */
function wpagent_exec_duplicate_fluent_form( $input ) {
	$input   = is_array( $input ) ? $input : array();
	$form_id = absint( $input['form_id'] ?? 0 );
	$lock    = wpagent_fluent_forms_fields_acquire_lock( $form_id );
	if ( is_wp_error( $lock ) ) {
		return $lock;
	}
	try {
		$authorized = wpagent_fluent_forms_get_authorized_form( $input );
		if ( is_wp_error( $authorized ) ) {
			return $authorized;
		}
		$service = $authorized['service'];
		$source  = wpagent_fluent_forms_form_payload( $authorized['form'] );
		try {
			$copy = $service->duplicate( array( 'form_id' => $source['id'] ) );
		} catch ( Throwable $error ) {
			return new WP_Error( 'wpagent_fluent_forms_duplicate_failed', __( 'Das Fluent-Forms-Formular konnte nicht dupliziert werden.', 'wp-agent-companion' ), array( 'status' => 500 ) );
		}
		$copy_id = absint( wpagent_fluent_forms_model_array( $copy )['id'] ?? 0 );
		if ( $copy_id <= 0 ) {
			return new WP_Error( 'wpagent_fluent_forms_duplicate_failed', __( 'Das Fluent-Forms-Formular konnte nicht dupliziert werden.', 'wp-agent-companion' ), array( 'status' => 500 ) );
		}
		$candidate_hash = wpagent_fluent_forms_candidate_hash( $copy );
		$title = trim( (string) ( $input['title'] ?? '' ) );
		if ( '' !== $title ) {
			$rename_candidate          = wpagent_fluent_forms_form_payload( $copy );
			$rename_candidate['title'] = $title;
			$candidate_hash            = wpagent_fluent_forms_expected_candidate_hash( $copy, $rename_candidate );
			try {
				$copy = $service->update(
					array( 'form_id' => $copy_id, 'title' => $title, 'status' => wpagent_fluent_forms_form_payload( $copy )['status'] )
				);
			} catch ( Throwable $error ) {
				if ( ! wpagent_fluent_forms_delete_owned_candidate( $service, $copy_id, $candidate_hash ) ) {
					return wpagent_fluent_forms_recovery_required( $copy_id );
				}
				return new WP_Error( 'wpagent_fluent_forms_rename_failed', __( 'Die Formularkopie konnte nicht sicher benannt werden und wurde entfernt.', 'wp-agent-companion' ), array( 'status' => 500 ) );
			}
		}
		$readback = wpagent_fluent_forms_readback( $service, $copy_id, $copy );
		if ( is_wp_error( $readback ) ) {
			if ( ! wpagent_fluent_forms_delete_owned_candidate( $service, $copy_id, $candidate_hash ) ) {
				return wpagent_fluent_forms_recovery_required( $copy_id );
			}
			return new WP_Error( 'wpagent_fluent_forms_duplicate_unverified', __( 'Die Formularkopie konnte nicht verifiziert werden und wurde entfernt.', 'wp-agent-companion' ), array( 'status' => 500 ) );
		}
		try {
			$copy_payload = wpagent_fluent_forms_form_payload( $service->find( $copy_id ) );
		} catch ( Throwable $error ) {
			$copy_payload = array();
		}
		$readback['verified'] = $readback['verified']
			&& ( $copy_payload['id'] ?? 0 ) !== $source['id']
			&& ( $copy_payload['status'] ?? '' ) === $source['status']
			&& wp_json_encode( $copy_payload['form_fields'] ?? array() ) === wp_json_encode( $source['form_fields'] )
			&& ( '' === $title || ( $copy_payload['title'] ?? '' ) === $title );
		if ( true !== $readback['verified'] ) {
			if ( ! wpagent_fluent_forms_delete_owned_candidate( $service, $copy_id, $candidate_hash ) ) {
				return wpagent_fluent_forms_recovery_required( $copy_id );
			}
			return new WP_Error( 'wpagent_fluent_forms_duplicate_unverified', __( 'Die Formularkopie wich vom Quellformular ab und wurde entfernt.', 'wp-agent-companion' ), array( 'status' => 500 ) );
		}
		return $readback;
	} finally {
		wpagent_fluent_forms_fields_release_lock( $form_id, $lock );
	}
}

function wpagent_ability_delete_fluent_form(): array {
	return array(
		'label' => __( 'Fluent-Forms-Formular manuell löschen', 'wp-agent-companion' ),
		'description' => __( 'Die Fernlöschung bestehender Fluent-Forms-Formulare ist ohne atomare Provider-Prüfung nicht verfügbar. Lösche das Formular manuell in WordPress.', 'wp-agent-companion' ),
		'category' => 'wp-agent',
		'input_schema' => array( 'type' => 'object', 'additionalProperties' => false, 'properties' => array( 'form_id' => array( 'type' => 'integer', 'minimum' => 1 ), 'confirm' => array( 'type' => 'boolean' ) ), 'required' => array( 'form_id', 'confirm' ) ),
		'output_schema' => wpagent_forms_public_object_schema( array( 'form_id' => array( 'type' => 'integer', 'minimum' => 1 ), 'deleted' => array( 'type' => 'boolean' ) ), array( 'form_id', 'deleted' ) ),
		'execute_callback' => 'wpagent_exec_delete_fluent_form',
		'permission_callback' => 'wpagent_perm_fluent_forms_manage',
		'meta' => array( 'show_in_rest' => true, 'annotations' => array( 'readonly' => false, 'destructive' => true, 'idempotent' => false, 'manual_only' => true ) ),
	);
}

/** @param mixed $input @return array|WP_Error */
function wpagent_exec_delete_fluent_form( $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 ) );
	}
	$form_id = absint( $input['form_id'] ?? 0 );
	$lock    = wpagent_fluent_forms_fields_acquire_lock( $form_id );
	if ( is_wp_error( $lock ) ) {
		return $lock;
	}
	try {
		$authorized = wpagent_fluent_forms_get_authorized_form( $input );
		if ( is_wp_error( $authorized ) ) {
			return $authorized;
		}
		return new WP_Error( 'wpagent_fluent_forms_delete_manual_only', __( 'Das dauerhafte Löschen bestehender Fluent-Forms-Formulare kann ohne atomare Provider-Prüfung nicht sicher gegen parallele Änderungen abgesichert werden. Lösche das Formular in WordPress manuell.', 'wp-agent-companion' ), array( 'status' => 409, 'form_id' => $form_id ) );
	} finally {
		wpagent_fluent_forms_fields_release_lock( $form_id, $lock );
	}
}
