<?php
/**
 * Shared Fluent Forms adapter helpers.
 *
 * Form reads and writes use Fluent Forms' FormService. Permissions go through
 * its own ACL so per-form manager scopes remain effective. Unknown model and
 * form-meta properties are never returned because add-ons may store secrets.
 *
 * @package WPAgentCompanion
 */

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

define( 'WPAGENT_COMPANION_OPT_FLUENT_FORMS_GRANTS', 'wp_agent_companion_fluent_forms_capability_grants' );

/** @return string[] */
function wpagent_fluent_forms_required_capabilities(): array {
	return array( 'fluentform_dashboard_access', 'fluentform_forms_manager' );
}

/** @return array<int,string[]> */
function wpagent_fluent_forms_capability_grants(): array {
	$stored = get_option( WPAGENT_COMPANION_OPT_FLUENT_FORMS_GRANTS, array() );
	$grants = array();
	foreach ( is_array( $stored ) ? $stored : array() as $user_id => $capabilities ) {
		$user_id = absint( $user_id );
		if ( ! $user_id || ! is_array( $capabilities ) ) {
			continue;
		}
		$allowed = array_values( array_intersect( wpagent_fluent_forms_required_capabilities(), array_map( 'sanitize_key', $capabilities ) ) );
		if ( $allowed ) {
			$grants[ $user_id ] = $allowed;
		}
	}
	return array_slice( $grants, 0, 200, true );
}

/** @param array<int,string[]> $grants */
function wpagent_fluent_forms_store_capability_grants( array $grants ): bool {
	if ( $grants ) {
		update_option( WPAGENT_COMPANION_OPT_FLUENT_FORMS_GRANTS, $grants, false );
	} else {
		delete_option( WPAGENT_COMPANION_OPT_FLUENT_FORMS_GRANTS );
	}
	return wpagent_fluent_forms_capability_grants() === $grants;
}

/** @return array{enabled:bool,capabilities:string[],tracked:string[]}|WP_Error */
function wpagent_fluent_forms_user_access( int $user_id ) {
	$user = get_user_by( 'id', $user_id );
	if ( ! $user instanceof WP_User || ! wpagent_companion_is_safe_connection_user( $user ) ) {
		return new WP_Error( 'wpagent_fluent_forms_unsafe_user', __( 'Wähle einen Redakteur ohne Administrator- oder Super-Administratorrechte.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$capabilities = array_values(
		array_filter(
			wpagent_fluent_forms_required_capabilities(),
			static fn( string $capability ): bool => user_can( $user, $capability )
		)
	);
	$grants = wpagent_fluent_forms_capability_grants();
	return array(
		'enabled'      => count( $capabilities ) === count( wpagent_fluent_forms_required_capabilities() ),
		'capabilities' => $capabilities,
		'tracked'      => $grants[ $user_id ] ?? array(),
	);
}

/** @return array{enabled:bool,capabilities:string[],tracked:string[]}|WP_Error */
function wpagent_fluent_forms_set_user_access( int $user_id, bool $enabled ) {
	$user = get_user_by( 'id', $user_id );
	if ( ! $user instanceof WP_User || ! wpagent_companion_is_safe_connection_user( $user ) ) {
		return new WP_Error( 'wpagent_fluent_forms_unsafe_user', __( 'Wähle einen Redakteur ohne Administrator- oder Super-Administratorrechte.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	if ( $enabled && ! wpagent_fluent_forms_available() ) {
		return wpagent_fluent_forms_missing_error();
	}
	$lock = wpagent_companion_acquire_connection_lock();
	if ( is_wp_error( $lock ) ) {
		return $lock;
	}

	try {
		$grants          = wpagent_fluent_forms_capability_grants();
		$original_grants = $grants;
		$tracked         = $grants[ $user_id ] ?? array();
		$newly_added     = array();
		if ( $enabled ) {
			foreach ( wpagent_fluent_forms_required_capabilities() as $capability ) {
				if ( in_array( $capability, $tracked, true ) ) {
					$user->add_cap( $capability );
					continue;
				}
				if ( ! user_can( $user, $capability ) ) {
					$user->add_cap( $capability );
					$tracked[]     = $capability;
					$newly_added[] = $capability;
				}
			}
			$tracked = array_values( array_unique( $tracked ) );
			if ( $tracked ) {
				$grants[ $user_id ] = $tracked;
			} else {
				unset( $grants[ $user_id ] );
			}
			if ( ! wpagent_fluent_forms_store_capability_grants( $grants ) ) {
				foreach ( $newly_added as $capability ) {
					$user->remove_cap( $capability );
				}
				wpagent_fluent_forms_store_capability_grants( $original_grants );
				clean_user_cache( $user_id );
				return new WP_Error( 'wpagent_fluent_forms_grant_store_failed', __( 'Die Fluent-Forms-Rechte konnten nicht sicher gespeichert werden.', 'wp-agent-companion' ), array( 'status' => 500 ) );
			}
		} else {
			foreach ( $tracked as $capability ) {
				$user->remove_cap( $capability );
			}
			clean_user_cache( $user_id );
			$fresh_user = get_user_by( 'id', $user_id );
			$remaining  = $fresh_user instanceof WP_User
				? array_values( array_intersect( $tracked, array_keys( array_filter( (array) $fresh_user->caps ) ) ) )
				: $tracked;
			if ( $remaining ) {
				foreach ( $tracked as $capability ) {
					$user->add_cap( $capability );
				}
				clean_user_cache( $user_id );
				return new WP_Error( 'wpagent_fluent_forms_grant_remove_failed', __( 'Die von wpagently ergänzten Fluent-Forms-Rechte konnten nicht vollständig entfernt werden.', 'wp-agent-companion' ), array( 'status' => 500 ) );
			}
			unset( $grants[ $user_id ] );
			if ( ! wpagent_fluent_forms_store_capability_grants( $grants ) ) {
				foreach ( $tracked as $capability ) {
					$user->add_cap( $capability );
				}
				clean_user_cache( $user_id );
				return new WP_Error( 'wpagent_fluent_forms_grant_store_failed', __( 'Die Fluent-Forms-Rechte konnten nicht sicher gespeichert werden.', 'wp-agent-companion' ), array( 'status' => 500 ) );
			}
		}
		clean_user_cache( $user_id );
		$access = wpagent_fluent_forms_user_access( $user_id );
		if ( $enabled && ( is_wp_error( $access ) || ! $access['enabled'] ) ) {
			foreach ( $newly_added as $capability ) {
				$user->remove_cap( $capability );
			}
			wpagent_fluent_forms_store_capability_grants( $original_grants );
			clean_user_cache( $user_id );
			return is_wp_error( $access ) ? $access : new WP_Error( 'wpagent_fluent_forms_grant_failed', __( 'Die Fluent-Forms-Rechte konnten nicht vollständig aktiviert werden.', 'wp-agent-companion' ), array( 'status' => 500 ) );
		}
		return $access;
	} finally {
		wpagent_companion_release_connection_lock( $lock );
	}
}

function wpagent_fluent_forms_available(): bool {
	return class_exists( 'FluentForm\\App\\Services\\Form\\FormService' )
		&& class_exists( 'FluentForm\\App\\Modules\\Acl\\Acl' );
}

function wpagent_fluent_forms_missing_error(): WP_Error {
	return new WP_Error(
		'wpagent_fluent_forms_missing',
		__( 'Fluent Forms ist nicht aktiv oder seine native Formular-API ist nicht verfügbar.', 'wp-agent-companion' ),
		array( 'status' => 400 )
	);
}

function wpagent_fluent_forms_has_permission( string $permission, int $form_id = 0 ): bool {
	if ( ! wpagent_fluent_forms_available() ) {
		return false;
	}
	try {
		return (bool) \FluentForm\App\Modules\Acl\Acl::hasPermission( $permission, $form_id > 0 ? $form_id : false );
	} catch ( Throwable $error ) {
		return false;
	}
}

/** @param mixed $input */
function wpagent_perm_fluent_forms_list( $input = null ): bool {
	return wpagent_fluent_forms_has_permission( 'fluentform_dashboard_access' );
}

/** @param mixed $input */
function wpagent_perm_fluent_forms_manage( $input = null ): bool {
	return wpagent_fluent_forms_has_permission( 'fluentform_forms_manager' );
}

/** @return \FluentForm\App\Services\Form\FormService|WP_Error */
function wpagent_fluent_forms_service() {
	if ( ! wpagent_fluent_forms_available() ) {
		return wpagent_fluent_forms_missing_error();
	}
	try {
		return new \FluentForm\App\Services\Form\FormService();
	} catch ( Throwable $error ) {
		return new WP_Error( 'wpagent_fluent_forms_api_failed', __( 'Die Fluent-Forms-API konnte nicht initialisiert werden.', 'wp-agent-companion' ), array( 'status' => 500 ) );
	}
}

/** @param mixed $form @return array<string,mixed> */
function wpagent_fluent_forms_model_array( $form ): array {
	if ( is_array( $form ) ) {
		return $form;
	}
	if ( is_object( $form ) && is_callable( array( $form, 'toArray' ) ) ) {
		$value = $form->toArray();
		return is_array( $value ) ? $value : array();
	}
	return array();
}

/** @param mixed $value @return array<string,mixed> */
function wpagent_fluent_forms_json_object( $value ): array {
	if ( is_array( $value ) ) {
		return $value;
	}
	if ( ! is_string( $value ) || '' === trim( $value ) ) {
		return array();
	}
	$decoded = json_decode( $value, true );
	return is_array( $decoded ) ? $decoded : array();
}

/** @param mixed $form @return array<string,mixed> */
function wpagent_fluent_forms_form_payload( $form ): array {
	$data = wpagent_fluent_forms_model_array( $form );
	$id   = absint( $data['id'] ?? 0 );
	return array(
		'provider'    => 'fluent-forms',
		'id'          => $id,
		'title'       => sanitize_text_field( (string) ( $data['title'] ?? '' ) ),
		'status'      => sanitize_key( (string) ( $data['status'] ?? '' ) ),
		'type'        => sanitize_key( (string) ( $data['type'] ?? 'form' ) ),
		'has_payment' => ! empty( $data['has_payment'] ),
		'created_at'  => sanitize_text_field( (string) ( $data['created_at'] ?? '' ) ),
		'updated_at'  => sanitize_text_field( (string) ( $data['updated_at'] ?? '' ) ),
		'shortcode'   => sprintf( '[fluentform id="%d"]', $id ),
		'form_fields' => wpagent_fluent_forms_json_object( $data['form_fields'] ?? array() ),
	);
}

/** @param mixed $form @return array<string,mixed> */
function wpagent_fluent_forms_public_form_payload( $form ): array {
	$payload     = wpagent_fluent_forms_form_payload( $form );
	$form_fields = $payload['form_fields'];
	unset( $payload['form_fields'] );
	$payload['field_count'] = is_array( $form_fields['fields'] ?? null ) ? count( $form_fields['fields'] ) : 0;
	$encoded                = wp_json_encode( $form_fields );
	$payload['fields_hash'] = hash( 'sha256', false === $encoded ? '' : $encoded );
	return $payload;
}

/** @param mixed $input @return array{service:object,form:mixed}|WP_Error */
function wpagent_fluent_forms_get_authorized_form( $input ) {
	$input   = is_array( $input ) ? $input : array();
	$form_id = absint( $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 ) );
	}
	if ( ! wpagent_fluent_forms_has_permission( 'fluentform_forms_manager', $form_id ) ) {
		return new WP_Error( 'wpagent_forbidden', __( 'Keine Berechtigung für dieses Fluent-Forms-Formular.', 'wp-agent-companion' ), array( 'status' => 403 ) );
	}
	$service = wpagent_fluent_forms_service();
	if ( is_wp_error( $service ) ) {
		return $service;
	}
	try {
		$form = $service->find( $form_id );
	} catch ( Throwable $error ) {
		return new WP_Error( 'wpagent_fluent_form_not_found', __( 'Fluent-Forms-Formular nicht gefunden.', 'wp-agent-companion' ), array( 'status' => 404 ) );
	}
	if ( ! wpagent_fluent_forms_model_array( $form ) ) {
		return new WP_Error( 'wpagent_fluent_form_not_found', __( 'Fluent-Forms-Formular nicht gefunden.', 'wp-agent-companion' ), array( 'status' => 404 ) );
	}
	return array( 'service' => $service, 'form' => $form );
}

/** @return array<string,mixed> */
function wpagent_fluent_forms_form_output_schema(): array {
	return array(
		'type'       => 'object',
		'properties' => array(
			'provider' => array( 'type' => 'string' ), 'id' => array( 'type' => 'integer' ),
			'title' => array( 'type' => 'string' ), 'status' => array( 'type' => 'string' ),
			'type' => array( 'type' => 'string' ), 'has_payment' => array( 'type' => 'boolean' ),
			'created_at' => array( 'type' => 'string' ), 'updated_at' => array( 'type' => 'string' ),
			'shortcode' => array( 'type' => 'string' ), 'field_count' => array( 'type' => 'integer' ),
			'fields_hash' => array( 'type' => 'string' ),
		),
	);
}

/** @param mixed $fields @return string|WP_Error */
function wpagent_fluent_forms_encode_fields( $fields ) {
	if ( ! is_array( $fields ) || ! isset( $fields['fields'], $fields['submitButton'] ) || ! is_array( $fields['fields'] ) || ! is_array( $fields['submitButton'] ) ) {
		return new WP_Error( 'wpagent_fluent_forms_bad_fields', __( 'form_fields benötigt die Objekte fields und submitButton.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$encoded = wp_json_encode( $fields );
	if ( false === $encoded || strlen( $encoded ) > 1048576 ) {
		return new WP_Error( 'wpagent_fluent_forms_bad_fields', __( 'form_fields ist ungültig oder größer als 1 MiB.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	return $encoded;
}
