<?php
/**
 * Custom Fields — Gutenberg block editor integration.
 *
 * @package CustomFields
 * @since 1.4.0
 */

namespace CustomFields;

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

/**
 * Registers block editor sidebar assets and REST helpers.
 */
final class BlockEditor {

	private Locations $locations;

	public function __construct( Locations $locations ) {
		$this->locations = $locations;
	}

	public function register(): void {
		add_action( 'enqueue_block_editor_assets', [ $this, 'enqueueAssets' ] );
		add_action( 'rest_api_init', [ $this, 'registerRestRoutes' ] );
		add_action( 'wpps_cf_groups_updated', [ $this, 'registerMetaOnUpdate' ] );
	}

	/**
	 * Re-register REST meta when field groups change during admin saves.
	 *
	 * @param array<string, array<string, mixed>> $all Updated groups map.
	 */
	public function registerMetaOnUpdate( array $all ): void {
		unset( $all );
		if ( ! did_action( 'init' ) ) {
			return;
		}

		$rest = new RestMeta( new Storage() );
		$rest->registerAll();
	}

	public function registerRestRoutes(): void {
		RelationalSearch::registerRoutes();

		register_rest_route(
			'wp-powersuite/v1',
			'/custom-fields/schema/(?P<post_type>[a-z0-9_-]+)',
			[
				'methods'             => 'GET',
				'callback'            => [ $this, 'restSchema' ],
				'permission_callback' => static function ( \WP_REST_Request $request ): bool {
					return self::canAccessSchema(
						sanitize_key( (string) $request->get_param( 'post_type' ) ),
						absint( $request->get_param( 'post_id' ) )
					);
				},
				'args'                => [
					'post_type' => [
						'type'              => 'string',
						'required'          => true,
						'sanitize_callback' => 'sanitize_key',
					],
					'post_id'   => [
						'type'              => 'integer',
						'default'           => 0,
						'sanitize_callback' => 'absint',
					],
				],
			]
		);
	}

	/**
	 * Schema is an editor helper: type-level edit_posts for a new post,
	 * edit_post on the specific post when values are requested.
	 */
	public static function canAccessSchema( string $post_type, int $post_id ): bool {
		$object = $post_type !== '' ? get_post_type_object( $post_type ) : null;
		if ( ! $object instanceof \WP_Post_Type ) {
			return false;
		}

		if ( ! current_user_can( $object->cap->edit_posts ) ) {
			return false;
		}

		if ( $post_id <= 0 ) {
			return true;
		}

		$post = get_post( $post_id );
		if ( ! $post instanceof \WP_Post || $post->post_type !== $post_type ) {
			return false;
		}

		return current_user_can( 'edit_post', $post_id );
	}

	/**
	 * @param \WP_REST_Request $request REST request.
	 * @return \WP_REST_Response
	 */
	public function restSchema( \WP_REST_Request $request ): \WP_REST_Response {
		$post_type = sanitize_key( (string) $request->get_param( 'post_type' ) );
		$post_id   = absint( $request->get_param( 'post_id' ) );

		if ( $post_type === '' || ! post_type_exists( $post_type ) ) {
			return new \WP_REST_Response( [ 'postType' => '', 'groups' => [] ], 404 );
		}

		if ( ! self::canAccessSchema( $post_type, $post_id ) ) {
			return new \WP_REST_Response( [ 'postType' => '', 'groups' => [] ], 403 );
		}

		return new \WP_REST_Response( EditorSchema::forPost( $post_id, $post_type ) );
	}

	public function enqueueAssets(): void {
		$screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null;
		if ( ! $screen || $screen->base !== 'post' || empty( $screen->post_type ) ) {
			return;
		}

		$post_type = (string) $screen->post_type;
		$post_id   = 0;
		if ( isset( $_GET['post'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
			$post_id = absint( wp_unslash( (string) $_GET['post'] ) );
		}

		$has_groups   = $this->locations->groupsForPost( $post_id, $post_type ) !== [];
		$has_sidebar  = EditorSchema::postTypeUsesGutenbergSidebar( $post_id, $post_type );
		$needs_assets = EditorSchema::postTypeUsesMetaBoxFields( $post_id, $post_type );

		if ( ! $has_groups || ( ! $has_sidebar && ! $needs_assets ) ) {
			return;
		}

		$base    = defined( 'WP_POWERSUITE_PLUGIN_URL' ) ? WP_POWERSUITE_PLUGIN_URL : '';
		$version = defined( 'WP_POWERSUITE_VERSION' ) ? WP_POWERSUITE_VERSION : '1.4.0';
		if ( $base === '' ) {
			return;
		}

		if ( $has_sidebar ) {
			wp_enqueue_media();
			wp_enqueue_style( 'wp-color-picker' );
		}

		if ( $needs_assets ) {
			$fields_script_path   = __DIR__ . '/../assets/cf-fields.js';
			$repeater_script_path = __DIR__ . '/../assets/cf-repeater.js';
			$fields_style_path    = __DIR__ . '/../assets/cf-admin.css';

			wp_enqueue_style(
				'wpps-cf-admin',
				wp_powersuite_module_asset_url( dirname( __DIR__ ) . '/module.php', 'assets/cf-admin.css' ),
				[ 'dashicons' ],
				is_readable( $fields_style_path ) ? (string) filemtime( $fields_style_path ) : $version
			);

			wp_enqueue_script(
				'wpps-cf-fields',
				wp_powersuite_module_asset_url( dirname( __DIR__ ) . '/module.php', 'assets/cf-fields.js' ),
				[ 'jquery', 'jquery-ui-sortable', 'wp-color-picker' ],
				is_readable( $fields_script_path ) ? (string) filemtime( $fields_script_path ) : $version,
				true
			);
			wp_localize_script(
				'wpps-cf-fields',
				'wppsCfFields',
				[
					'searchUrl' => rest_url( 'wp-powersuite/v1/custom-fields/search/' ),
					'createTermUrl' => rest_url( 'wp-powersuite/v1/custom-fields/terms' ),
					'oembedUrl' => rest_url( 'oembed/1.0/embed' ),
					'restNonce' => wp_create_nonce( 'wp_rest' ),
				]
			);
			wp_enqueue_script(
				'wpps-cf-conditional',
				wp_powersuite_module_asset_url( dirname( __DIR__ ) . '/module.php', 'assets/cf-conditional.js' ),
				[ 'jquery' ],
				$version,
				true
			);
			wp_enqueue_script(
				'wpps-cf-repeater',
				wp_powersuite_module_asset_url( dirname( __DIR__ ) . '/module.php', 'assets/cf-repeater.js' ),
				[ 'jquery' ],
				is_readable( $repeater_script_path ) ? (string) filemtime( $repeater_script_path ) : $version,
				true
			);
		}

		if ( ! $has_sidebar ) {
			return;
		}

		$schema = EditorSchema::forPost( $post_id, $post_type );
		$gutenberg_style_path = __DIR__ . '/../assets/cf-gutenberg.css';

		wp_enqueue_style(
			'wpps-cf-gutenberg',
			wp_powersuite_module_asset_url( dirname( __DIR__ ) . '/module.php', 'assets/cf-gutenberg.css' ),
			$needs_assets ? [ 'wpps-cf-admin' ] : [],
			is_readable( $gutenberg_style_path ) ? (string) filemtime( $gutenberg_style_path ) : $version
		);

		$script_path = __DIR__ . '/../assets/cf-gutenberg-sidebar.js';
		wp_enqueue_script(
			'wpps-cf-gutenberg-sidebar',
			wp_powersuite_module_asset_url( dirname( __DIR__ ) . '/module.php', 'assets/cf-gutenberg-sidebar.js' ),
			[
				'wp-plugins',
				'wp-edit-post',
				'wp-element',
				'wp-components',
				'wp-data',
				'wp-i18n',
				'wp-core-data',
				'jquery',
				'wp-color-picker',
			],
			is_readable( $script_path ) ? (string) filemtime( $script_path ) : $version,
			true
		);

		wp_localize_script(
			'wpps-cf-gutenberg-sidebar',
			'wppsCfEditor',
			[
				'schema'    => $schema,
				'restUrl'   => rest_url( 'wp-powersuite/v1/custom-fields/schema/' ),
				'searchUrl' => rest_url( 'wp-powersuite/v1/custom-fields/search/' ),
				'createTermUrl' => rest_url( 'wp-powersuite/v1/custom-fields/terms' ),
				'oembedUrl' => rest_url( 'oembed/1.0/embed' ),
				'restNonce' => wp_create_nonce( 'wp_rest' ),
				'strings'   => [
					'selectImage'    => __( 'Select image', 'wppowersuite-lite' ),
					'selectFile'     => __( 'Select file', 'wppowersuite-lite' ),
					'remove'         => __( 'Remove', 'wppowersuite-lite' ),
					'clearGallery'   => __( 'Clear all', 'wppowersuite-lite' ),
					'advancedFields' => __( 'Rich text, repeaters, and similar fields appear below the editor.', 'wppowersuite-lite' ),
					'noFields'       => __( 'No custom fields match this post.', 'wppowersuite-lite' ),
					'required'       => __( 'Required', 'wppowersuite-lite' ),
					'searchPosts'    => __( 'Search posts…', 'wppowersuite-lite' ),
					'searchTerms'    => __( 'Search terms…', 'wppowersuite-lite' ),
					'searchUsers'    => __( 'Search users…', 'wppowersuite-lite' ),
					'wysiwygNotice'  => __( 'Use the rich text editor below.', 'wppowersuite-lite' ),
					'oembedLoading'  => __( 'Loading preview…', 'wppowersuite-lite' ),
				],
			]
		);
	}

	/**
	 * Whether the block editor sidebar should replace meta boxes for a group.
	 *
	 * @param array<string, mixed> $group Group definition.
	 */
	public static function useSidebarForGroup( array $group ): bool {
		return EditorSchema::groupUsesGutenbergSidebar( $group );
	}
}
