<?php
/**
 * REST: Icon Libraries manifest search + webfont index.
 *
 * @package DiviSupreme
 */

declare(strict_types=1);

namespace DiviSupreme\Extensions\IconLibraries;

if ( ! defined( 'ABSPATH' ) ) {
	die( 'Direct access forbidden.' );
}

/**
 * Registers `/dsm/v1/icon-libraries/*` routes for VB lazy manifest loading.
 */
final class RestApiController {

	/**
	 * @return void
	 */
	public static function register(): void {
		add_action( 'rest_api_init', array( self::class, 'register_routes' ) );
	}

	/**
	 * @return void
	 */
	public static function register_routes(): void {
		register_rest_route(
			'dsm/v1',
			'/icon-libraries',
			array(
				array(
					'methods'             => \WP_REST_Server::READABLE,
					'callback'            => array( self::class, 'get_catalog' ),
					'permission_callback' => array( self::class, 'permission_callback' ),
				),
			)
		);

		register_rest_route(
			'dsm/v1',
			'/icon-libraries/(?P<library>[a-z0-9_-]+)/manifest',
			array(
				array(
					'methods'             => \WP_REST_Server::READABLE,
					'callback'            => array( self::class, 'get_manifest' ),
					'permission_callback' => array( self::class, 'permission_callback' ),
					'args'                => array(
						'library'  => array(
							'required'          => true,
							'sanitize_callback' => 'sanitize_key',
						),
						'q'        => array(
							'required'          => false,
							'sanitize_callback' => 'sanitize_text_field',
						),
						'offset'   => array(
							'required'          => false,
							'sanitize_callback' => 'absint',
							'default'           => 0,
						),
						'per_page' => array(
							'required'          => false,
							'sanitize_callback' => 'absint',
							'default'           => 60,
						),
						'all'      => array(
							'required'          => false,
							'sanitize_callback' => 'rest_sanitize_boolean',
							'default'           => false,
						),
					),
				),
			)
		);

		register_rest_route(
			'dsm/v1',
			'/icon-libraries/(?P<library>[a-z0-9_-]+)/webfont-index',
			array(
				array(
					'methods'             => \WP_REST_Server::READABLE,
					'callback'            => array( self::class, 'get_webfont_index' ),
					'permission_callback' => array( self::class, 'permission_callback' ),
					'args'                => array(
						'library' => array(
							'required'          => true,
							'sanitize_callback' => 'sanitize_key',
						),
					),
				),
			)
		);
	}

	/**
	 * @return bool
	 */
	public static function permission_callback(): bool {
		return current_user_can( 'edit_posts' );
	}

	/**
	 * @return \WP_REST_Response
	 */
	public static function get_catalog(): \WP_REST_Response {
		return new \WP_REST_Response(
			array(
				'libraries' => IconLibraryRegistry::get_public_catalog(),
			),
			200
		);
	}

	/**
	 * @param \WP_REST_Request $request Request.
	 * @return \WP_REST_Response|\WP_Error
	 */
	public static function get_manifest( \WP_REST_Request $request ) {
		$library_id = (string) $request->get_param( 'library' );

		if ( ! ExtensionSettings::is_library_enabled( $library_id ) ) {
			return new \WP_Error(
				'dsm_icon_library_disabled',
				esc_html__( 'Icon library is not enabled.', 'dsm-supreme-modules-pro-for-divi' ),
				array( 'status' => 403 )
			);
		}

		$library = IconLibraryRegistry::get( $library_id );

		if ( null === $library ) {
			return new \WP_Error(
				'dsm_icon_library_missing',
				esc_html__( 'Unknown icon library.', 'dsm-supreme-modules-pro-for-divi' ),
				array( 'status' => 404 )
			);
		}

		$query     = (string) ( $request->get_param( 'q' ) ?? '' );
		$fetch_all = rest_sanitize_boolean( $request->get_param( 'all' ) );
		$offset    = max( 0, (int) ( $request->get_param( 'offset' ) ?? 0 ) );
		$total     = $library->get_manifest_total( $query );

		if ( $fetch_all ) {
			$per_page = max( 1, $total );
			$offset   = 0;
		} else {
			$per_page = (int) ( $request->get_param( 'per_page' ) ?? 60 );
			$per_page = max( 1, min( 120, $per_page ) );
		}

		$slice = $library->get_manifest_slice( $offset, $per_page, $query );

		$mapped = array_map(
			static function ( array $entry ) use ( $library ): array {
				return IconLibraryRegistry::to_divi_icon_list_row( $library, $entry );
			},
			$slice
		);

		return new \WP_REST_Response(
			array(
				'library'  => $library_id,
				'icons'    => $mapped,
				'total'    => $total,
				'offset'   => $offset,
				'per_page' => $per_page,
				'has_more' => $fetch_all ? false : ( ( $offset + count( $mapped ) ) < $total ),
			),
			200
		);
	}

	/**
	 * @param \WP_REST_Request $request Request.
	 * @return \WP_REST_Response|\WP_Error
	 */
	public static function get_webfont_index( \WP_REST_Request $request ) {
		$library_id = (string) $request->get_param( 'library' );

		if ( ! ExtensionSettings::is_library_enabled( $library_id ) ) {
			return new \WP_Error(
				'dsm_icon_library_disabled',
				esc_html__( 'Icon library is not enabled.', 'dsm-supreme-modules-pro-for-divi' ),
				array( 'status' => 403 )
			);
		}

		$library = IconLibraryRegistry::get( $library_id );

		if ( null === $library ) {
			return new \WP_Error(
				'dsm_icon_library_missing',
				esc_html__( 'Unknown icon library.', 'dsm-supreme-modules-pro-for-divi' ),
				array( 'status' => 404 )
			);
		}

		if ( ! method_exists( $library, 'get_webfont_index' ) ) {
			return new \WP_Error(
				'dsm_icon_webfont_index_unavailable',
				esc_html__( 'Webfont index is not available for this library.', 'dsm-supreme-modules-pro-for-divi' ),
				array( 'status' => 404 )
			);
		}

		/** @var array<string, mixed> $index */
		$index  = $library->get_webfont_index();
		$filled = $index['filled'] ?? array();

		return new \WP_REST_Response(
			array(
				'library' => $library_id,
				'filled'  => is_array( $filled ) ? array_values( $filled ) : array(),
			),
			200
		);
	}
}
