<?php
/**
 * Shared Contact Form 7 adapter helpers.
 *
 * All reads and writes go through Contact Form 7's public object API. Raw
 * post-meta writes are deliberately forbidden because they bypass its
 * sanitizers, lifecycle hooks and configuration validator.
 *
 * @package WPAgentCompanion
 */

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

function wpagent_cf7_available(): bool {
	return class_exists( 'WPCF7_ContactForm' ) && function_exists( 'wpcf7_contact_form' );
}

function wpagent_cf7_missing_error(): WP_Error {
	return new WP_Error(
		'wpagent_cf7_missing',
		__( 'Contact Form 7 ist nicht aktiv oder nicht vollständig geladen.', 'wp-agent-companion' ),
		array( 'status' => 400 )
	);
}

/** @param mixed $input */
function wpagent_perm_cf7_read( $input = null ): bool {
	return current_user_can( 'wpcf7_read_contact_forms' );
}

/** @param mixed $input */
function wpagent_perm_cf7_edit( $input = null ): bool {
	return current_user_can( 'wpcf7_edit_contact_forms' );
}

/**
 * @param mixed  $input
 * @param string $capability
 * @return WPCF7_ContactForm|WP_Error
 */
function wpagent_cf7_get_authorized_form( $input, string $capability ) {
	if ( ! wpagent_cf7_available() ) {
		return wpagent_cf7_missing_error();
	}
	$input   = is_array( $input ) ? $input : array();
	$form_id = (int) ( $input['form_id'] ?? 0 );
	if ( $form_id <= 0 ) {
		return new WP_Error( 'wpagent_bad_form_id', __( 'form_id muss eine positive Ganzzahl sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$form = wpcf7_contact_form( $form_id );
	if ( ! $form ) {
		return new WP_Error( 'wpagent_cf7_not_found', __( 'Contact-Form-7-Formular nicht gefunden.', 'wp-agent-companion' ), array( 'status' => 404 ) );
	}
	if ( ! current_user_can( $capability, $form_id ) ) {
		return new WP_Error( 'wpagent_forbidden', __( 'Keine Berechtigung für dieses Formular.', 'wp-agent-companion' ), array( 'status' => 403 ) );
	}
	return $form;
}

/** @return string|WP_Error */
function wpagent_cf7_public_string( $value, int $max_length, string $field, bool $allow_empty = true ) {
	return wpagent_forms_public_string( $value, $max_length, 'cf7', $field, $allow_empty );
}

/** @return array|WP_Error */
function wpagent_cf7_public_string_list( $value, string $field ) {
	if ( ! is_array( $value ) || ! array_is_list( $value ) ) {
		return wpagent_forms_public_output_error( 'cf7', $field );
	}
	$values = wpagent_forms_public_list( array_values( $value ), WPAGENT_FORMS_PUBLIC_MAX_OPTIONS, 'cf7', $field );
	if ( is_wp_error( $values ) ) {
		return $values;
	}
	$result = array();
	foreach ( $values as $index => $item ) {
		$text = wpagent_cf7_public_string( $item, WPAGENT_FORMS_PUBLIC_MAX_SHORT_TEXT, $field . '.' . $index );
		if ( is_wp_error( $text ) ) {
			return $text;
		}
		$result[] = $text;
	}
	return $result;
}

/** @return array<int,array<string,mixed>>|WP_Error */
function wpagent_cf7_fields( WPCF7_ContactForm $form ) {
	$raw_fields = $form->scan_form_tags();
	if ( ! is_array( $raw_fields ) || count( $raw_fields ) > WPAGENT_FORMS_PUBLIC_MAX_FIELDS ) {
		return wpagent_forms_public_output_error( 'cf7', 'fields' );
	}
	$fields = array();
	foreach ( $raw_fields as $index => $tag ) {
		if ( ! is_object( $tag ) ) {
			return wpagent_forms_public_output_error( 'cf7', 'fields.' . $index );
		}
		$row = array();
		foreach ( array( 'type', 'basetype', 'name' ) as $key ) {
			$row[ $key ] = wpagent_cf7_public_string( $tag->{$key} ?? '', 128, 'fields.' . $index . '.' . $key );
			if ( is_wp_error( $row[ $key ] ) ) {
				return $row[ $key ];
			}
		}
		foreach ( array( 'options', 'raw_values', 'labels', 'values' ) as $key ) {
			$row[ $key ] = wpagent_cf7_public_string_list( $tag->{$key} ?? array(), 'fields.' . $index . '.' . $key );
			if ( is_wp_error( $row[ $key ] ) ) {
				return $row[ $key ];
			}
		}
		$row['content'] = wpagent_cf7_public_string( $tag->content ?? '', WPAGENT_FORMS_PUBLIC_MAX_TEXT, 'fields.' . $index . '.content' );
		if ( is_wp_error( $row['content'] ) ) {
			return $row['content'];
		}
		$fields[] = $row;
	}
	return $fields;
}

/** @return array<int,array{code:string,message:string}>|WP_Error */
function wpagent_cf7_config_errors( WPCF7_ContactForm $form ) {
	if ( ! class_exists( 'WPCF7_ConfigValidator' ) || ! function_exists( 'wpcf7_validate_configuration' ) || ! wpcf7_validate_configuration() ) {
		return array();
	}
	$validator = new WPCF7_ConfigValidator( $form );
	$validator->validate();
	$errors = $validator->collect_error_messages( array( 'decodes_html_entities' => true ) );
	if ( ! is_array( $errors ) || count( $errors ) > WPAGENT_FORMS_PUBLIC_MAX_OPTIONS ) {
		return wpagent_forms_public_output_error( 'cf7', 'config_errors' );
	}
	$result = array();
	foreach ( $errors as $code => $message ) {
		if ( ! is_scalar( $message ) ) {
			return wpagent_forms_public_output_error( 'cf7', 'config_errors' );
		}
		$clean_code = wpagent_cf7_public_string( sanitize_key( (string) $code ) ?: 'configuration', 128, 'config_errors.code', false );
		$clean_message = wpagent_cf7_public_string( wp_strip_all_tags( (string) $message, true ), WPAGENT_FORMS_PUBLIC_MAX_SHORT_TEXT, 'config_errors.message', false );
		if ( is_wp_error( $clean_code ) || is_wp_error( $clean_message ) ) {
			return is_wp_error( $clean_code ) ? $clean_code : $clean_message;
		}
		$result[] = array( 'code' => $clean_code, 'message' => $clean_message );
	}
	return $result;
}

/** @return mixed */
function wpagent_cf7_canonicalize( $value ) {
	if ( ! is_array( $value ) ) {
		return $value;
	}
	if ( ! array_is_list( $value ) ) {
		ksort( $value, SORT_STRING );
	}
	foreach ( $value as $key => $item ) {
		$value[ $key ] = wpagent_cf7_canonicalize( $item );
	}
	return $value;
}

/** @return array{title:string,locale:string,properties:array<string,mixed>} */
function wpagent_cf7_logical_state( WPCF7_ContactForm $form ): array {
	return array(
		'title'      => (string) $form->title(),
		'locale'     => (string) $form->locale(),
		'properties' => $form->get_properties(),
	);
}

function wpagent_cf7_state_hash( WPCF7_ContactForm $form ): string {
	$state = wpagent_cf7_canonicalize( wpagent_cf7_logical_state( $form ) );
	return hash( 'sha256', (string) wp_json_encode( $state, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE ) );
}

/** @param mixed $value */
function wpagent_cf7_string_map( $value ): array {
	$result = array();
	foreach ( is_array( $value ) ? $value : array() as $key => $item ) {
		if ( is_string( $key ) && is_scalar( $item ) ) {
			$result[ $key ] = (string) $item;
		}
	}
	return $result;
}

/** @return array<string,string>|WP_Error */
function wpagent_cf7_bounded_messages( $value ) {
	if ( ! is_array( $value ) || array_is_list( $value ) ) {
		return wpagent_forms_public_output_error( 'cf7', 'messages' );
	}
	$allowed = array_keys( wpagent_cf7_messages_input_schema()['properties'] );
	if ( array_diff( array_keys( $value ), $allowed ) ) {
		return wpagent_forms_public_output_error( 'cf7', 'messages' );
	}
	$result = array();
	foreach ( $allowed as $key ) {
		$text = wpagent_cf7_public_string( $value[ $key ] ?? '', WPAGENT_CF7_MAX_MESSAGE_BYTES, 'messages.' . $key );
		if ( is_wp_error( $text ) ) {
			return $text;
		}
		$result[ $key ] = $text;
	}
	return $result;
}

/** @return array{reply_to:string,advanced:bool} */
function wpagent_cf7_safe_reply_to( string $headers ): array {
	$reply_to = '';
	$advanced = false;
	$seen     = false;
	foreach ( preg_split( '/\r\n|\r|\n/', $headers ) ?: array() as $line ) {
		$line = trim( $line );
		if ( '' === $line ) {
			continue;
		}
		if ( preg_match( '/^Reply-To\s*:\s*(.+)$/i', $line, $matches ) && ! $seen ) {
			$reply_to = trim( $matches[1] );
			$seen     = true;
			continue;
		}
		$advanced = true;
	}
	return array( 'reply_to' => $reply_to, 'advanced' => $advanced );
}

/** @param mixed $value @return array<string,mixed>|WP_Error */
function wpagent_cf7_safe_mail_payload( $value, bool $primary ) {
	if ( ! is_array( $value ) || array_is_list( $value ) ) {
		return wpagent_forms_public_output_error( 'cf7', $primary ? 'mail' : 'mail_2' );
	}
	$mail = $value;
	$raw_headers = $mail['additional_headers'] ?? '';
	$raw_attachments = $mail['attachments'] ?? '';
	if ( ! is_string( $raw_headers ) || strlen( $raw_headers ) > WPAGENT_FORMS_PUBLIC_MAX_TEXT || ! is_string( $raw_attachments ) || strlen( $raw_attachments ) > WPAGENT_FORMS_PUBLIC_MAX_TEXT ) {
		return wpagent_forms_public_output_error( 'cf7', $primary ? 'mail' : 'mail_2' );
	}
	$headers = wpagent_cf7_safe_reply_to( $raw_headers );
	$payload = array(
		'active'                   => $primary ? true : ! empty( $mail['active'] ),
		'subject'                  => wpagent_cf7_public_string( $mail['subject'] ?? '', WPAGENT_CF7_MAX_SUBJECT_BYTES, $primary ? 'mail.subject' : 'mail_2.subject' ),
		'sender'                   => wpagent_cf7_public_string( $mail['sender'] ?? '', WPAGENT_CF7_MAX_MAILBOX_BYTES, $primary ? 'mail.sender' : 'mail_2.sender' ),
		'recipient'                => wpagent_cf7_public_string( $mail['recipient'] ?? '', WPAGENT_CF7_MAX_MAILBOX_BYTES, $primary ? 'mail.recipient' : 'mail_2.recipient' ),
		'body'                     => wpagent_cf7_public_string( $mail['body'] ?? '', WPAGENT_CF7_MAX_BODY_BYTES, $primary ? 'mail.body' : 'mail_2.body' ),
		'reply_to'                 => wpagent_cf7_public_string( $headers['reply_to'], WPAGENT_CF7_MAX_MAILBOX_BYTES, $primary ? 'mail.reply_to' : 'mail_2.reply_to' ),
		'exclude_blank'             => ! empty( $mail['exclude_blank'] ),
		'format'                    => ! empty( $mail['use_html'] ) ? 'html' : 'plain',
		'attachments_present'       => '' !== trim( $raw_attachments ),
		'advanced_headers_present'  => $headers['advanced'],
	);
	foreach ( array( 'subject', 'sender', 'recipient', 'body', 'reply_to' ) as $key ) {
		if ( is_wp_error( $payload[ $key ] ) ) {
			return $payload[ $key ];
		}
	}
	return $payload;
}

/** @return array<string,mixed>|WP_Error */
function wpagent_cf7_bounded_form_payload( WPCF7_ContactForm $form ) {
	$properties = $form->get_properties();
	if ( ! is_array( $properties ) ) {
		return wpagent_forms_public_output_error( 'cf7', 'properties' );
	}
	$payload = array(
		'id'                          => (int) $form->id(),
		'hash'                        => wpagent_cf7_public_string( (string) $form->hash(), 128, 'hash' ),
		'state_hash'                  => wpagent_cf7_state_hash( $form ),
		'slug'                        => wpagent_cf7_public_string( (string) $form->name(), 200, 'slug' ),
		'title'                       => wpagent_cf7_public_string( (string) $form->title(), WPAGENT_CF7_MAX_TITLE_BYTES, 'title' ),
		'locale'                      => wpagent_cf7_public_string( (string) $form->locale(), 32, 'locale' ),
		'shortcode'                   => wpagent_cf7_public_string( (string) $form->shortcode(), 512, 'shortcode' ),
		'form'                        => wpagent_cf7_public_string( $properties['form'] ?? '', WPAGENT_CF7_MAX_FORM_BYTES, 'form' ),
		'fields'                      => wpagent_cf7_fields( $form ),
		'mail'                        => wpagent_cf7_safe_mail_payload( $properties['mail'] ?? array(), true ),
		'mail_2'                      => wpagent_cf7_safe_mail_payload( $properties['mail_2'] ?? array(), false ),
		'messages'                    => wpagent_cf7_bounded_messages( $properties['messages'] ?? array() ),
		'additional_settings_present' => '' !== trim( (string) ( $properties['additional_settings'] ?? '' ) ),
		'config_errors'               => wpagent_cf7_config_errors( $form ),
	);
	foreach ( $payload as $value ) {
		if ( is_wp_error( $value ) ) {
			return $value;
		}
	}
	return $payload;
}

/** @return array<string,mixed>|WP_Error */
function wpagent_cf7_form_payload( WPCF7_ContactForm $form ) {
	return wpagent_cf7_bounded_form_payload( $form );
}

/** @return array<string,mixed> */
function wpagent_cf7_form_list_item_schema(): array {
	return wpagent_forms_public_object_schema(
		array(
			'id' => array( 'type' => 'integer', 'minimum' => 1 ),
			'hash' => wpagent_forms_public_string_schema( 128 ),
			'state_hash' => wpagent_forms_public_hash_schema(),
			'slug' => wpagent_forms_public_string_schema( 200 ),
			'title' => wpagent_forms_public_string_schema( WPAGENT_CF7_MAX_TITLE_BYTES ),
			'locale' => wpagent_forms_public_string_schema( 32 ),
			'shortcode' => wpagent_forms_public_string_schema( 512 ),
		),
		array( 'id', 'hash', 'state_hash', 'slug', 'title', 'locale', 'shortcode' )
	);
}

/** @return array<string,mixed> */
function wpagent_cf7_safe_mail_output_schema(): array {
	return wpagent_forms_public_object_schema(
		array(
			'active' => array( 'type' => 'boolean' ), 'subject' => wpagent_forms_public_string_schema( WPAGENT_CF7_MAX_SUBJECT_BYTES ),
			'sender' => wpagent_forms_public_string_schema( WPAGENT_CF7_MAX_MAILBOX_BYTES ), 'recipient' => wpagent_forms_public_string_schema( WPAGENT_CF7_MAX_MAILBOX_BYTES ),
			'body' => wpagent_forms_public_string_schema( WPAGENT_CF7_MAX_BODY_BYTES ), 'reply_to' => wpagent_forms_public_string_schema( WPAGENT_CF7_MAX_MAILBOX_BYTES ),
			'exclude_blank' => array( 'type' => 'boolean' ), 'format' => array( 'type' => 'string', 'enum' => array( 'plain', 'html' ) ),
			'attachments_present' => array( 'type' => 'boolean' ), 'advanced_headers_present' => array( 'type' => 'boolean' ),
		),
		array( 'active', 'subject', 'sender', 'recipient', 'body', 'reply_to', 'exclude_blank', 'format', 'attachments_present', 'advanced_headers_present' )
	);
}

/** @return array<string,mixed> */
function wpagent_cf7_form_output_schema(): array {
	$field = wpagent_forms_public_object_schema(
		array(
			'type' => wpagent_forms_public_string_schema( 128 ), 'basetype' => wpagent_forms_public_string_schema( 128 ),
			'name' => wpagent_forms_public_string_schema( 128 ),
			'options' => wpagent_forms_public_list_schema( wpagent_forms_public_string_schema( WPAGENT_FORMS_PUBLIC_MAX_SHORT_TEXT ), WPAGENT_FORMS_PUBLIC_MAX_OPTIONS ),
			'raw_values' => wpagent_forms_public_list_schema( wpagent_forms_public_string_schema( WPAGENT_FORMS_PUBLIC_MAX_SHORT_TEXT ), WPAGENT_FORMS_PUBLIC_MAX_OPTIONS ),
			'labels' => wpagent_forms_public_list_schema( wpagent_forms_public_string_schema( WPAGENT_FORMS_PUBLIC_MAX_SHORT_TEXT ), WPAGENT_FORMS_PUBLIC_MAX_OPTIONS ),
			'values' => wpagent_forms_public_list_schema( wpagent_forms_public_string_schema( WPAGENT_FORMS_PUBLIC_MAX_SHORT_TEXT ), WPAGENT_FORMS_PUBLIC_MAX_OPTIONS ),
			'content' => wpagent_forms_public_string_schema( WPAGENT_FORMS_PUBLIC_MAX_TEXT ),
		),
		array( 'type', 'basetype', 'name', 'options', 'raw_values', 'labels', 'values', 'content' )
	);
	$messages = array();
	foreach ( array_keys( wpagent_cf7_messages_input_schema()['properties'] ) as $key ) {
		$messages[ $key ] = wpagent_forms_public_string_schema( WPAGENT_CF7_MAX_MESSAGE_BYTES );
	}
	return wpagent_forms_public_object_schema(
		array(
			'id' => array( 'type' => 'integer', 'minimum' => 1 ), 'hash' => wpagent_forms_public_string_schema( 128 ),
			'state_hash' => wpagent_forms_public_hash_schema(), 'slug' => wpagent_forms_public_string_schema( 200 ),
			'title' => wpagent_forms_public_string_schema( WPAGENT_CF7_MAX_TITLE_BYTES ), 'locale' => wpagent_forms_public_string_schema( 32 ),
			'shortcode' => wpagent_forms_public_string_schema( 512 ), 'form' => wpagent_forms_public_string_schema( WPAGENT_CF7_MAX_FORM_BYTES ),
			'fields' => wpagent_forms_public_list_schema( $field, WPAGENT_FORMS_PUBLIC_MAX_FIELDS ),
			'mail' => wpagent_cf7_safe_mail_output_schema(), 'mail_2' => wpagent_cf7_safe_mail_output_schema(),
			'messages' => wpagent_forms_public_object_schema( $messages, array_keys( $messages ) ),
			'additional_settings_present' => array( 'type' => 'boolean' ),
			'config_errors' => wpagent_forms_public_list_schema( wpagent_forms_public_object_schema( array( 'code' => wpagent_forms_public_string_schema( 128, true ), 'message' => wpagent_forms_public_string_schema( WPAGENT_FORMS_PUBLIC_MAX_SHORT_TEXT, true ) ), array( 'code', 'message' ) ), WPAGENT_FORMS_PUBLIC_MAX_OPTIONS ),
		),
		array( 'id', 'hash', 'state_hash', 'slug', 'title', 'locale', 'shortcode', 'form', 'fields', 'mail', 'mail_2', 'messages', 'additional_settings_present', 'config_errors' )
	);
}
