<?php
/** Fluent Forms email-notification write abilities. */

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

/** @return string|WP_Error */
function wpagent_fluent_forms_notification_header( $value, string $field, int $max_length, bool $required = false ) {
	$text = is_string( $value ) ? trim( $value ) : '';
	if ( ( $required && '' === $text ) || strlen( $text ) > $max_length || preg_match( '/[\r\n\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/', $text ) ) {
		/* translators: %s: input field name. */
		return new WP_Error( 'wpagent_fluent_forms_notification_header', sprintf( __( '%s ist leer, zu lang oder enthält unzulässige Steuerzeichen.', 'wp-agent-companion' ), $field ), array( 'status' => 400 ) );
	}
	return sanitize_text_field( $text );
}

/** @return string|WP_Error */
function wpagent_fluent_forms_notification_addresses( $value, string $field, bool $required = false ) {
	$text = wpagent_fluent_forms_notification_header( $value, $field, 2000, $required );
	if ( is_wp_error( $text ) || '' === $text ) {
		return $text;
	}
	foreach ( array_map( 'trim', explode( ',', $text ) ) as $address ) {
		if ( ! is_email( $address ) && ! preg_match( '/^\{[A-Za-z0-9_.-]{1,190}\}$/', $address ) ) {
			/* translators: %s: input field name. */
			return new WP_Error( 'wpagent_fluent_forms_notification_email', sprintf( __( '%s enthält weder eine gültige E-Mail-Adresse noch einen einzelnen Fluent-Forms-Smartcode.', 'wp-agent-companion' ), $field ), array( 'status' => 400 ) );
		}
	}
	return $text;
}

/** @return string|WP_Error */
function wpagent_fluent_forms_notification_field_name( $value ) {
	$field = is_string( $value ) ? trim( $value ) : '';
	return preg_match( '/^[A-Za-z0-9_.\[\]-]{1,191}$/', $field )
		? $field
		: new WP_Error( 'wpagent_fluent_forms_notification_field', __( 'send_to.field muss ein gültiger Fluent-Forms-Feldname sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
}

/** @param array<string,mixed> $current @param array<string,mixed> $patch @return array<string,mixed>|WP_Error */
function wpagent_fluent_forms_prepare_notification( array $current, array $patch, bool $creating ) {
	$allowed = array( 'name', 'enabled', 'send_to', 'from_name', 'from_email', 'reply_to', 'bcc', 'subject', 'message', 'email_template' );
	if ( ! $patch || array_diff( array_keys( $patch ), $allowed ) ) {
		return new WP_Error( 'wpagent_fluent_forms_notification_fields', __( 'Übergebe mindestens ein unterstütztes Benachrichtigungsfeld.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$result = $current;
	if ( $creating ) {
		$result = array_merge(
			array(
				'name' => '', 'enabled' => false,
				'sendTo' => array( 'type' => 'email', 'email' => '', 'field' => '' ),
				'fromName' => '', 'fromEmail' => '', 'replyTo' => '', 'bcc' => '',
				'subject' => '', 'message' => '', 'email_template' => '',
				'conditionals' => array( 'status' => false, 'type' => 'all', 'conditions' => array() ),
			),
			$result
		);
	}
	if ( array_key_exists( 'name', $patch ) ) {
		$name = wpagent_fluent_forms_notification_header( $patch['name'], 'name', 255, true );
		if ( is_wp_error( $name ) ) return $name;
		$result['name'] = $name;
	}
	if ( array_key_exists( 'enabled', $patch ) ) {
		$result['enabled'] = rest_sanitize_boolean( $patch['enabled'] );
	}
	if ( array_key_exists( 'send_to', $patch ) ) {
		$send_to = is_array( $patch['send_to'] ) ? $patch['send_to'] : array();
		if ( array_diff( array_keys( $send_to ), array( 'type', 'email', 'field' ) ) ) {
			return new WP_Error( 'wpagent_fluent_forms_notification_recipient', __( 'send_to enthält ein unbekanntes Feld.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		$native = wpagent_fluent_forms_delivery_array( $result['sendTo'] ?? array() );
		if ( array_key_exists( 'type', $send_to ) ) {
			$type = is_string( $send_to['type'] ) ? $send_to['type'] : '';
			if ( ! in_array( $type, array( 'email', 'field' ), true ) ) {
				return new WP_Error( 'wpagent_fluent_forms_notification_recipient', __( 'send_to.type muss email oder field sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
			}
			$native['type'] = $type;
		}
		if ( array_key_exists( 'email', $send_to ) ) {
			$email = wpagent_fluent_forms_notification_addresses( $send_to['email'], 'send_to.email' );
			if ( is_wp_error( $email ) ) return $email;
			$native['email'] = $email;
		}
		if ( array_key_exists( 'field', $send_to ) ) {
			$field = wpagent_fluent_forms_notification_field_name( $send_to['field'] );
			if ( is_wp_error( $field ) ) return $field;
			$native['field'] = $field;
		}
		$result['sendTo'] = $native;
	}
	$field_map = array( 'from_name' => array( 'fromName', false ), 'from_email' => array( 'fromEmail', true ), 'reply_to' => array( 'replyTo', true ), 'bcc' => array( 'bcc', true ), 'subject' => array( 'subject', false ) );
	foreach ( $field_map as $public => $config ) {
		if ( ! array_key_exists( $public, $patch ) ) continue;
		$value = $config[1]
			? wpagent_fluent_forms_notification_addresses( $patch[ $public ], $public )
			: wpagent_fluent_forms_notification_header( $patch[ $public ], $public, 'subject' === $public ? 998 : 255, 'subject' === $public );
		if ( is_wp_error( $value ) ) return $value;
		$result[ $config[0] ] = $value;
	}
	if ( array_key_exists( 'message', $patch ) ) {
		$message = wpagent_fluent_forms_delivery_plain_message( $patch['message'], 'message', 200000 );
		if ( is_wp_error( $message ) ) return $message;
		$result['message'] = $message;
	}
	if ( array_key_exists( 'email_template', $patch ) ) {
		$template = is_string( $patch['email_template'] ) ? sanitize_key( $patch['email_template'] ) : '';
		if ( strlen( $template ) > 100 || $template !== (string) $patch['email_template'] ) {
			return new WP_Error( 'wpagent_fluent_forms_notification_template', __( 'email_template darf nur Kleinbuchstaben, Ziffern, Bindestriche und Unterstriche enthalten.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		$result['email_template'] = $template;
	}
	$name = wpagent_fluent_forms_notification_header( $result['name'] ?? '', 'name', 255, true );
	$subject = wpagent_fluent_forms_notification_header( $result['subject'] ?? '', 'subject', 998, true );
	if ( is_wp_error( $name ) ) return $name;
	if ( is_wp_error( $subject ) ) return $subject;
	if ( '' === trim( wp_strip_all_tags( (string) ( $result['message'] ?? '' ) ) ) ) {
		return new WP_Error( 'wpagent_fluent_forms_notification_message', __( 'message darf nicht leer sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$send_to = wpagent_fluent_forms_delivery_array( $result['sendTo'] ?? array() );
	if ( 'field' === ( $send_to['type'] ?? '' ) ) {
		$field = wpagent_fluent_forms_notification_field_name( $send_to['field'] ?? '' );
		if ( is_wp_error( $field ) ) return $field;
	} else {
		$email = wpagent_fluent_forms_notification_addresses( $send_to['email'] ?? '', 'send_to.email', true );
		if ( is_wp_error( $email ) ) return $email;
		$send_to['type'] = 'email';
	}
	$result['sendTo'] = $send_to;
	return $result;
}

/** @param object $service @return int|WP_Error */
function wpagent_fluent_forms_store_notification( object $service, int $form_id, int $notification_id, array $value ) {
	$encoded = wp_json_encode( $value );
	if ( false === $encoded || strlen( $encoded ) > 1048576 ) {
		return new WP_Error( 'wpagent_fluent_forms_notification_size', __( 'Die E-Mail-Benachrichtigung ist ungültig oder größer als 1 MiB.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	try {
		$result = $service->store( array( 'form_id' => $form_id, 'meta_key' => 'notifications', 'meta_id' => $notification_id, 'value' => $encoded ) );
	} catch ( Throwable $error ) {
		return new WP_Error( 'wpagent_fluent_forms_notification_save_failed', __( 'Die E-Mail-Benachrichtigung konnte nicht gespeichert werden.', 'wp-agent-companion' ), array( 'status' => 500 ) );
	}
	return absint( is_array( $result ) ? ( $result[0] ?? 0 ) : 0 );
}

/** @param array<string,mixed> $before */
function wpagent_fluent_forms_restore_notification( array $before, int $notification_id, ?array $value ): bool {
	try {
		if ( null === $value ) {
			$before['service']->remove( array( 'form_id' => $before['form_id'], 'meta_id' => $notification_id ) );
		} else {
			$restored_id = wpagent_fluent_forms_store_notification( $before['service'], $before['form_id'], $notification_id, $value );
			if ( is_wp_error( $restored_id ) || $notification_id !== $restored_id ) return false;
		}
	} catch ( Throwable $error ) {
		return false;
	}
	$fresh = wpagent_fluent_forms_delivery_state( $before['form_id'] );
	return ! is_wp_error( $fresh ) && hash_equals( $before['notifications_hash'], $fresh['notifications_hash'] );
}

/** @param array<string,mixed> $before */
function wpagent_fluent_forms_recover_failed_notification_store( array $before, int $notification_id ): bool {
	if ( $notification_id > 0 ) {
		return isset( $before['notification_records'][ $notification_id ] )
			&& wpagent_fluent_forms_restore_notification( $before, $notification_id, $before['notification_records'][ $notification_id ]['value'] );
	}
	$fresh = wpagent_fluent_forms_delivery_state( $before['form_id'] );
	if ( is_wp_error( $fresh ) ) {
		return false;
	}
	$new_ids = array_diff( array_keys( $fresh['notification_records'] ), array_keys( $before['notification_records'] ) );
	try {
		foreach ( $new_ids as $new_id ) {
			$before['service']->remove( array( 'form_id' => $before['form_id'], 'meta_id' => absint( $new_id ) ) );
		}
	} catch ( Throwable $error ) {
		return false;
	}
	$restored = wpagent_fluent_forms_delivery_state( $before['form_id'] );
	return ! is_wp_error( $restored ) && hash_equals( $before['notifications_hash'], $restored['notifications_hash'] );
}

/** @return array<string,mixed> */
function wpagent_fluent_forms_notification_input_schema(): array {
	return array(
		'type' => 'object', 'additionalProperties' => false, 'minProperties' => 1,
		'properties' => array(
			'name' => array( 'type' => 'string', 'minLength' => 1, 'maxLength' => 255 ),
			'enabled' => array( 'type' => 'boolean' ),
			'send_to' => array( 'type' => 'object', 'additionalProperties' => false, 'properties' => array(
				'type' => array( 'type' => 'string', 'enum' => array( 'email', 'field' ) ),
				'email' => array( 'type' => 'string', 'maxLength' => 2000 ),
				'field' => array( 'type' => 'string', 'maxLength' => 191 ),
			) ),
			'from_name' => array( 'type' => 'string', 'maxLength' => 255 ), 'from_email' => array( 'type' => 'string', 'maxLength' => 2000 ),
			'reply_to' => array( 'type' => 'string', 'maxLength' => 2000 ), 'bcc' => array( 'type' => 'string', 'maxLength' => 2000 ),
			'subject' => array( 'type' => 'string', 'minLength' => 1, 'maxLength' => 998 ),
			'message' => array( 'type' => 'string', 'minLength' => 1, 'maxLength' => 200000 ),
			'email_template' => array( 'type' => 'string', 'maxLength' => 100 ),
		),
	);
}

function wpagent_ability_upsert_fluent_form_notification(): array {
	return array(
		'label' => __( 'Fluent-Forms-E-Mail-Benachrichtigung speichern', 'wp-agent-companion' ),
		'description' => __( 'Erstellt oder aktualisiert genau eine E-Mail-Benachrichtigung. Andere und unbekannte Einstellungen bleiben erhalten. Header-Prüfung, Konflikt-Hash, Sperre, Read-back und Rollback sichern die Änderung.', 'wp-agent-companion' ),
		'category' => 'wp-agent',
		'input_schema' => array( 'type' => 'object', 'additionalProperties' => false, 'properties' => array(
			'form_id' => array( 'type' => 'integer', 'minimum' => 1 ), 'notification_id' => array( 'type' => 'integer', 'minimum' => 1 ),
			'expected_hash' => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ),
			'notification' => wpagent_fluent_forms_notification_input_schema(),
		), 'required' => array( 'form_id', 'expected_hash', 'notification' ) ),
		'output_schema' => array( 'type' => 'object', 'properties' => array(
			'form_id' => array( 'type' => 'integer' ), 'notification' => wpagent_fluent_forms_notification_schema(),
			'notifications_hash' => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ), 'verified' => array( 'type' => 'boolean' ),
		) ),
		'execute_callback' => 'wpagent_exec_upsert_fluent_form_notification',
		'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<string,mixed>|WP_Error */
function wpagent_exec_upsert_fluent_form_notification( $input ) {
	$input = is_array( $input ) ? $input : array();
	$form_id = absint( $input['form_id'] ?? 0 );
	$notification_id = absint( $input['notification_id'] ?? 0 );
	$expected_hash = wpagent_fluent_forms_delivery_expected_hash( $input['expected_hash'] ?? '' );
	if ( is_wp_error( $expected_hash ) ) return $expected_hash;
	$lock = wpagent_fluent_forms_delivery_acquire_lock( $form_id );
	if ( is_wp_error( $lock ) ) return $lock;
	try {
		$before = wpagent_fluent_forms_delivery_state( $form_id );
		if ( is_wp_error( $before ) ) return $before;
		if ( ! hash_equals( $before['notifications_hash'], $expected_hash ) ) {
			return new WP_Error( 'wpagent_fluent_forms_delivery_conflict', __( 'Die E-Mail-Benachrichtigungen wurden seit dem Lesen verändert.', 'wp-agent-companion' ), array( 'status' => 409, 'current_hash' => $before['notifications_hash'] ) );
		}
		$creating = 0 === $notification_id;
		if ( ! $creating && ! isset( $before['notification_records'][ $notification_id ] ) ) {
			return new WP_Error( 'wpagent_fluent_forms_notification_not_found', __( 'E-Mail-Benachrichtigung nicht gefunden.', 'wp-agent-companion' ), array( 'status' => 404 ) );
		}
		$current = $creating ? array() : $before['notification_records'][ $notification_id ]['value'];
		$prepared = wpagent_fluent_forms_prepare_notification( $current, is_array( $input['notification'] ?? null ) ? $input['notification'] : array(), $creating );
		if ( is_wp_error( $prepared ) ) return $prepared;
		$saved_id = wpagent_fluent_forms_store_notification( $before['service'], $form_id, $notification_id, $prepared );
		if ( is_wp_error( $saved_id ) || $saved_id <= 0 ) {
			$error = is_wp_error( $saved_id ) ? $saved_id : new WP_Error( 'wpagent_fluent_forms_notification_save_failed', __( 'Fluent Forms lieferte keine ID für die gespeicherte Benachrichtigung.', 'wp-agent-companion' ), array( 'status' => 500 ) );
			if ( ! wpagent_fluent_forms_recover_failed_notification_store( $before, $notification_id ) ) {
				return new WP_Error( 'wpagent_fluent_forms_delivery_rollback_failed', __( 'Der fehlgeschlagene Speicherversuch konnte die Benachrichtigungen verändert haben und der vorherige Zustand ließ sich nicht vollständig wiederherstellen. Prüfe das Formular sofort manuell.', 'wp-agent-companion' ), array( 'status' => 500 ) );
			}
			return $error;
		}
		$fresh = wpagent_fluent_forms_delivery_state( $form_id );
		$expected_notification = wpagent_fluent_forms_notification_payload( array( 'id' => $saved_id, 'value' => $prepared ) );
		$fresh_by_id = array();
		if ( ! is_wp_error( $fresh ) ) foreach ( $fresh['notifications'] as $notification ) $fresh_by_id[ $notification['id'] ] = $notification;
		$raw_verified = ! is_wp_error( $fresh )
			&& isset( $fresh['notification_records'][ $saved_id ] )
			&& hash_equals( wpagent_fluent_forms_delivery_hash( $prepared ), wpagent_fluent_forms_delivery_hash( $fresh['notification_records'][ $saved_id ]['value'] ) );
		if ( $raw_verified && isset( $fresh_by_id[ $saved_id ] ) && hash_equals( $expected_notification['hash'], $fresh_by_id[ $saved_id ]['hash'] ) ) {
			return array( 'form_id' => $form_id, 'notification' => $fresh_by_id[ $saved_id ], 'notifications_hash' => $fresh['notifications_hash'], 'verified' => true );
		}
		$old_value = $creating ? null : $current;
		if ( ! wpagent_fluent_forms_restore_notification( $before, $saved_id, $old_value ) ) {
			return new WP_Error( 'wpagent_fluent_forms_delivery_rollback_failed', __( 'Die Benachrichtigung konnte nicht verifiziert und der vorherige Zustand nicht vollständig wiederhergestellt werden. Prüfe das Formular sofort manuell.', 'wp-agent-companion' ), array( 'status' => 500 ) );
		}
		return new WP_Error( 'wpagent_fluent_forms_notification_unverified', __( 'Die Benachrichtigung wich nach dem Speichern ab und wurde zurückgerollt.', 'wp-agent-companion' ), array( 'status' => 500 ) );
	} finally {
		wpagent_fluent_forms_delivery_release_lock( $form_id, $lock );
	}
}

function wpagent_ability_delete_fluent_form_notification(): array {
	return array(
		'label' => __( 'Fluent-Forms-E-Mail-Benachrichtigung löschen', 'wp-agent-companion' ),
		'description' => __( 'Löscht genau eine E-Mail-Benachrichtigung nach Konfliktprüfung und ausdrücklicher Bestätigung. Andere Benachrichtigungen bleiben erhalten.', 'wp-agent-companion' ),
		'category' => 'wp-agent',
		'input_schema' => array( 'type' => 'object', 'additionalProperties' => false, 'properties' => array(
			'form_id' => array( 'type' => 'integer', 'minimum' => 1 ), 'notification_id' => array( 'type' => 'integer', 'minimum' => 1 ),
			'expected_hash' => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ), 'confirm' => array( 'type' => 'boolean' ),
		), 'required' => array( 'form_id', 'notification_id', 'expected_hash', 'confirm' ) ),
		'output_schema' => array( 'type' => 'object', 'properties' => array(
			'form_id' => array( 'type' => 'integer' ), 'notification_id' => array( 'type' => 'integer' ),
			'deleted' => array( 'type' => 'boolean' ), 'notifications_hash' => array( 'type' => 'string', 'pattern' => '^[a-f0-9]{64}$' ),
		) ),
		'execute_callback' => 'wpagent_exec_delete_fluent_form_notification',
		'permission_callback' => 'wpagent_perm_fluent_forms_manage',
		'meta' => array( 'show_in_rest' => true, 'annotations' => array( 'readonly' => false, 'destructive' => true, 'idempotent' => false ) ),
	);
}

/** @param mixed $input @return array<string,mixed>|WP_Error */
function wpagent_exec_delete_fluent_form_notification( $input ) {
	$input = is_array( $input ) ? $input : array();
	if ( true !== ( $input['confirm'] ?? false ) ) return new WP_Error( 'wpagent_confirmation_required', __( 'Das Löschen einer E-Mail-Benachrichtigung erfordert confirm=true.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	$form_id = absint( $input['form_id'] ?? 0 );
	$notification_id = absint( $input['notification_id'] ?? 0 );
	$expected_hash = wpagent_fluent_forms_delivery_expected_hash( $input['expected_hash'] ?? '' );
	if ( is_wp_error( $expected_hash ) ) return $expected_hash;
	$lock = wpagent_fluent_forms_delivery_acquire_lock( $form_id );
	if ( is_wp_error( $lock ) ) return $lock;
	try {
		$before = wpagent_fluent_forms_delivery_state( $form_id );
		if ( is_wp_error( $before ) ) return $before;
		if ( ! hash_equals( $before['notifications_hash'], $expected_hash ) ) return new WP_Error( 'wpagent_fluent_forms_delivery_conflict', __( 'Die E-Mail-Benachrichtigungen wurden seit dem Lesen verändert.', 'wp-agent-companion' ), array( 'status' => 409, 'current_hash' => $before['notifications_hash'] ) );
		if ( ! isset( $before['notification_records'][ $notification_id ] ) ) return new WP_Error( 'wpagent_fluent_forms_notification_not_found', __( 'E-Mail-Benachrichtigung nicht gefunden.', 'wp-agent-companion' ), array( 'status' => 404 ) );
		try {
			$before['service']->remove( array( 'form_id' => $form_id, 'meta_id' => $notification_id ) );
		} catch ( Throwable $error ) {
			if ( ! wpagent_fluent_forms_restore_notification( $before, $notification_id, $before['notification_records'][ $notification_id ]['value'] ) ) {
				return new WP_Error( 'wpagent_fluent_forms_delivery_rollback_failed', __( 'Der fehlgeschlagene Löschversuch konnte die Benachrichtigung entfernt haben und der vorherige Zustand ließ sich nicht vollständig wiederherstellen. Prüfe das Formular sofort manuell.', 'wp-agent-companion' ), array( 'status' => 500 ) );
			}
			return new WP_Error( 'wpagent_fluent_forms_notification_delete_failed', __( 'Die E-Mail-Benachrichtigung konnte nicht gelöscht werden. Der vorherige Zustand wurde bestätigt.', 'wp-agent-companion' ), array( 'status' => 500 ) );
		}
		$fresh = wpagent_fluent_forms_delivery_state( $form_id );
		if ( ! is_wp_error( $fresh ) && ! isset( $fresh['notification_records'][ $notification_id ] ) ) {
			return array( 'form_id' => $form_id, 'notification_id' => $notification_id, 'deleted' => true, 'notifications_hash' => $fresh['notifications_hash'] );
		}
		if ( ! wpagent_fluent_forms_restore_notification( $before, $notification_id, $before['notification_records'][ $notification_id ]['value'] ) ) {
			return new WP_Error( 'wpagent_fluent_forms_delivery_rollback_failed', __( 'Das Löschen konnte nicht verifiziert und die Benachrichtigung nicht mit derselben ID wiederhergestellt werden. Prüfe das Formular sofort manuell.', 'wp-agent-companion' ), array( 'status' => 500 ) );
		}
		return new WP_Error( 'wpagent_fluent_forms_notification_delete_unverified', __( 'Das Löschen konnte nicht verifiziert werden und wurde zurückgerollt.', 'wp-agent-companion' ), array( 'status' => 500 ) );
	} finally {
		wpagent_fluent_forms_delivery_release_lock( $form_id, $lock );
	}
}
