<?php
function rsssl_disable_fields_pro( $fields )
{
    /**
     * If a feature is already enabled, but not by RSSSL, we can simply check for that feature, and if the option in RSSSL is active.
     * We set is as true, but disabled. Because our React interface only updates changed option, and this option never changes, this won't get set to true in the database.
     */

    $third_party_headers = RSSSL()->headers->get_detected_security_headers('thirdparty');
    $header_ids = array_column($third_party_headers, 'option_name');

    // Create lookup map: field_id => array index (handles non-sequential keys correctly)
    $field_id_map = array_combine(array_column($fields, 'id'), array_keys($fields));
    foreach ($fields as $index => $field) {
        $field_id = $field['id'];

        if (in_array($field_id, $header_ids, true)) {
            foreach ($third_party_headers as $data) {
                $detected_option = $data['option_name'];
                if ($field_id !== $detected_option) {
                    continue;
                }
                #disable this option, it's already enabled.
                $fields[$index]['disabled'] = true;
                if ($detected_option === 'csp_frame_ancestors') {
                    if (isset($field_id_map['csp_frame_ancestors_urls'])) {
                        $fields[$field_id_map['csp_frame_ancestors_urls']]['disabled'] = true;
                    }
                }

                #now try to set the value
                if ($field['type'] === 'checkbox') {
                    $fields[$index]['value'] = true;
                }

                if ($detected_option === 'content_security_policy') {
                    if (isset($field_id_map['csp_status'])) {
                        $fields[$field_id_map['csp_status']]['value'] = 'enforced-by-thirdparty';
                    }
                }

                if ($field['type'] === 'permissionspolicy') {
                    if (isset($field_id_map['enable_permissions_policy'])) {
                        $fields[$field_id_map['enable_permissions_policy']]['value'] = true;
                    }
                    $value = $data['value'];
                    $defaults = $field['default'];
                    $possible_values = ['*' => '(*)', '()' => '()', 'self' => '(self)'];
                    $override_value = $defaults;
                    foreach ($defaults as $default_key => $default_item) {
                        $type = $default_item['id'];
                        #set default to allow, in case not set
                        $override_value[$default_key]['value'] = '*';
                        foreach ($possible_values as $setting_value => $detect_value) {
                            $type_value = $type . '=' . $detect_value;
                            if (stripos($value, $type_value) !== false) {
                                $override_value[$default_key]['value'] = $setting_value;
                                $override_value[$default_key]['status'] = true;
                            }
                        }
                    }
                    $fields[$index]['value'] = $override_value;
                }

                if ($field['type'] === 'select') {
                    if (isset($field_id_map[$detected_option])) {
                        $select_field_index = $field_id_map[$detected_option];
                        if (isset($fields[$select_field_index]['options'])) {
                            foreach ($fields[$select_field_index]['options'] as $key => $label) {
                                //strip comment from the label
                                $label = trim(preg_replace('/\(.*?\)/', '', $label));
                                if (strtolower($label) === strtolower($data['value']) || strtolower($key) === strtolower($data['value'])) {
                                    $fields[$index]['value'] = $key;
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }

	    // Disable change_login_url + change_login_url_failure_url fields when wp-login.php is not available, and the option has not been set. We can then assume it's done by a different plugin
	    if ($field['id'] === 'change_login_url'
	    && !test_rsssl_wp_login_available()
	    && empty(rsssl_get_option('change_login_url'))
	    ) {
		    $fields[$index]['value'] = __("Login URL already changed by something else than Really Simple Security", "really-simple-ssl");
		    $fields[$index]['disabled'] = true;
	    }

	    if ($field['id'] === 'change_login_url_failure_url'
	        && !test_rsssl_wp_login_available()
	        && empty(rsssl_get_option('change_login_url'))) {
		    $fields[$index]['value'] = __("Login URL already changed by something else than Really Simple Security", "really-simple-ssl");
		    $fields[$index]['disabled'] = true;
	    }

	    $fields[$index] = rsssl_maybe_disable_pro_blocked_checkbox_field( $fields[$index] );

	    # Disable X-Frame-Options if frame ancestors is 'self'
	    if ( $field['id'] === 'x_frame_options' ) {

		    $frame_ancestors_value = rsssl_get_option( 'csp_frame_ancestors' );
		    $frame_ancestors_urls_value = rsssl_get_option( 'csp_frame_ancestors_urls' );

			# Always disable because it's controlled by frame-ancestors
		    $fields[ $index ]['disabled'] = true;

		    # Do not set X-Frame-Options when Frame Ancestor URLs are specified
		    if ( empty( $frame_ancestors_urls_value ) ) {
				switch ( $frame_ancestors_value ) {
					case 'disabled':
						# frame-ancestors → off - x-frame-options → off
						$fields[ $index ]['value'] = 'disabled';
						break;
					case 'none':
						# frame-ancestors → none - x-frame-options → DENY
						$fields[ $index ]['value'] = 'DENY';
						break;
					case 'self':
						# frame-ancestors → self - x-frame-options → SAMEORIGIN
						$fields[ $index ]['value'] = 'SAMEORIGIN';
						break;
					default:
						# frame-ancestors → self + url - x-frame-options → off
						$fields[ $index ]['disabled'] = true;
						$fields[ $index ]['value'] = 'disabled';
						break;
				}
			} else {
				$fields[ $index ]['value'] = 'disabled';
			}

		    add_filter( 'rsssl_option_x_frame_options', function( $value, $name ) use ( $fields, $index ) {
			    return override_x_frame_options( $value, $name, $fields, $index );
		    }, 10, 2 );
		}

		# Disable custom login URL option when using plain permalinks
	    if ( $field['id'] === 'change_login_url_enabled' ) {
		    if ( rsssl_plain_permalinks_enabled() ) {
			    $fields[ $index ]['disabled'] = true;
		    }
	    }


    }

	if ( get_option('rsssl_csp_max_size_exceeded') ) {
		//find csp_status, and set it to disabled
		if (isset($field_id_map['csp_status'])) {
			$fields[$field_id_map['csp_status']]['value'] = 'error';
		}
	}

	return $fields;

}

add_filter('rsssl_fields_values', 'rsssl_disable_fields_pro', 99, 1);

/**
 * Register Pro checkbox fields with shared blocked-field handling.
 * Keep field ids here so UI disabling, save prevention, and cache clearing stay in sync.
 * The block reason callback is required: it decides the current block state and
 * is reused by the generic save guard through rsssl_blocked_security_feature_callbacks.
 * Help config only controls how that same block reason is shown in the settings UI.
 *
 * Entries can include
 * - block_reason_callback returning an empty string or a blocker message.
 * - display_block_reason_callback for display-only checks that should defer expensive probes.
 * - clear_rest_api_accessible_cache to clear the REST API probe cache when this field is saved.
 * - help config shown when the field is blocked (label, title, optional condition_callback).
 */
function rsssl_get_pro_blocked_checkbox_fields( ?string $field_id = null ): array {
	$blocked_fields = apply_filters(
		'rsssl_pro_blocked_checkbox_fields',
		[
			'enable_passkey_login' => [
				'block_reason_callback'            => 'rsssl_get_passkey_login_enable_block_reason',
				'display_block_reason_callback'    => static function(): string {
					return rsssl_get_passkey_login_enable_block_reason( false );
				},
				'clear_rest_api_accessible_cache'  => true,
				'help'                             => [
					'label'              => 'warning',
					'title'              => __( 'REST API blocked', 'really-simple-ssl' ),
					'condition_callback' => static function( array $field, string $block_reason ): bool {
						return $block_reason !== ''
							&& rsssl_get_option( 'ssl_enabled' )
							&& rsssl_get_option( 'site_has_ssl' );
					},
				],
			],
		]
	);

	if ( ! is_array( $blocked_fields ) ) {
		return [];
	}

	if ( $field_id === null ) {
		return $blocked_fields;
	}

	return isset( $blocked_fields[ $field_id ] ) && is_array( $blocked_fields[ $field_id ] )
		? $blocked_fields[ $field_id ]
		: [];
}

function rsssl_add_pro_blocked_security_feature_callbacks( array $callbacks ): array {
	foreach ( rsssl_get_pro_blocked_checkbox_fields() as $field_id => $blocked_field ) {
		if ( ! is_array( $blocked_field ) ) {
			continue;
		}

		$block_reason_callback = $blocked_field['block_reason_callback'] ?? null;
		if ( is_string( $field_id ) && $block_reason_callback !== null ) {
			$callbacks[ $field_id ] = $block_reason_callback;
		}
	}

	return $callbacks;
}
add_filter( 'rsssl_blocked_security_feature_callbacks', 'rsssl_add_pro_blocked_security_feature_callbacks' );

function rsssl_add_pro_rest_api_accessible_cache_clear_fields( array $fields ): array {
	foreach ( rsssl_get_pro_blocked_checkbox_fields() as $field_id => $blocked_field ) {
		if ( ! is_array( $blocked_field ) ) {
			continue;
		}

		if ( is_string( $field_id ) && ! empty( $blocked_field['clear_rest_api_accessible_cache'] ) ) {
			$fields[] = $field_id;
		}
	}

	return $fields;
}
add_filter( 'rsssl_rest_api_accessible_cache_clear_fields', 'rsssl_add_pro_rest_api_accessible_cache_clear_fields' );

function rsssl_maybe_disable_pro_blocked_checkbox_field( array $field ): array {
	// rsssl_fields(false) returns config-only fields without values during save/setup paths.
	// Block callbacks can run expensive checks, so evaluate only hydrated fields.
	if (
		! isset( $field['id'] )
		|| ! is_string( $field['id'] )
		|| ! array_key_exists( 'value', $field )
		|| ( $field['type'] ?? '' ) !== 'checkbox'
		|| ! function_exists( 'rsssl_maybe_disable_blocked_checkbox_field' )
	) {
		return $field;
	}

	$blocked_field = rsssl_get_pro_blocked_checkbox_fields( $field['id'] );
	if ( $blocked_field === [] ) {
		return $field;
	}

	$block_reason_callback = $blocked_field['display_block_reason_callback']
		?? $blocked_field['block_reason_callback']
		?? null;
	if ( ! is_callable( $block_reason_callback ) ) {
		return $field;
	}

	$block_reason = (string) call_user_func( $block_reason_callback );
	$field = rsssl_maybe_add_pro_blocked_checkbox_field_help( $field, $blocked_field, $block_reason );

	return rsssl_maybe_disable_blocked_checkbox_field( $field, $block_reason );
}

function rsssl_maybe_add_pro_blocked_checkbox_field_help( array $field, array $blocked_field, string $block_reason ): array {
	if ( $block_reason === '' || empty( $blocked_field['help'] ) || ! is_array( $blocked_field['help'] ) ) {
		return $field;
	}

	$help = $blocked_field['help'];
	$condition_callback = $help['condition_callback'] ?? null;
	if (
		$condition_callback !== null
		&& ( ! is_callable( $condition_callback ) || ! call_user_func( $condition_callback, $field, $block_reason ) )
	) {
		return $field;
	}

	$field['help'] = [
		'label' => $help['label'] ?? 'warning',
		'title' => $help['title'] ?? '',
		'text'  => $block_reason,
	];

	return $field;
}

function override_x_frame_options( $value, $name, $fields, $x_frame_options_index ) {
	if ( $name === 'x_frame_options' ) {
		// Set the value from $fields
		$value = $fields[ $x_frame_options_index ]['value'];
	}
	return $value;
}
