<?php
/**
 * Module registry REST routes.
 *
 * @package MenuVerse
 */

namespace WPXero\MenuVerse\Rest;

defined( 'ABSPATH' ) || exit;

/**
 * Exposes the module registry to the dashboard.
 */
final class Modules_Controller extends Rest_Controller {

	/**
	 * Registers routes.
	 *
	 * @return void
	 */
	public function register_routes() {
		register_rest_route(
			self::REST_NAMESPACE,
			'/modules',
			array(
				array(
					'methods'             => \WP_REST_Server::READABLE,
					'callback'            => array( $this, 'get_modules' ),
					'permission_callback' => array( $this, 'permission_check' ),
				),
			)
		);

		register_rest_route(
			self::REST_NAMESPACE,
			'/modules/(?P<id>[a-z][a-z0-9_]*)/state',
			array(
				array(
					'methods'             => \WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'update_state' ),
					'permission_callback' => array( $this, 'permission_check' ),
					'args'                => array(
						'id'      => array(
							'type'     => 'string',
							'required' => true,
						),
						'enabled' => array(
							'type'     => 'boolean',
							'required' => true,
						),
					),
				),
			)
		);
	}

	/**
	 * Returns every registered module definition.
	 *
	 * @return \WP_REST_Response
	 */
	public function get_modules() {
		return rest_ensure_response(
			array(
				'modules'      => $this->plugin()->modules()->definitions(),
				'globalSchema' => $this->plugin()->settings()->global_schema(),
			)
		);
	}

	/**
	 * Enables or disables a module.
	 *
	 * @param \WP_REST_Request $request Request object.
	 * @return \WP_REST_Response|\WP_Error
	 */
	public function update_state( \WP_REST_Request $request ) {
		$module_id = (string) $request->get_param( 'id' );

		if ( ! $this->plugin()->modules()->has( $module_id ) ) {
			return new \WP_Error(
				'menuverse_unknown_module',
				__( 'Unknown module.', 'menuverse' ),
				array( 'status' => 404 )
			);
		}

		// The dashboard does not offer the switch for a module that has not
		// shipped, so reaching here means something else asked. Turning it on
		// would write a flag the registry ignores anyway; refusing says why.
		if ( ! $this->plugin()->modules()->is_available( $module_id ) ) {
			return new \WP_Error(
				'menuverse_module_unavailable',
				__( 'That menu is not ready yet, so it cannot be switched on.', 'menuverse' ),
				array( 'status' => 400 )
			);
		}

		$result = $this->plugin()->settings()->set_module_enabled( $module_id, (bool) $request->get_param( 'enabled' ) );

		if ( is_wp_error( $result ) ) {
			return $result;
		}

		return rest_ensure_response(
			array(
				'id'       => $module_id,
				'enabled'  => ! empty( $result['enabled'] ),
				'settings' => $result,
			)
		);
	}
}
