<?php
/**
 * Settings REST routes.
 *
 * @package MenuVerse
 */

namespace WPXero\MenuVerse\Rest;

defined( 'ABSPATH' ) || exit;

/**
 * Reads and writes settings, validated server side against module schemas.
 */
final class Settings_Controller extends Rest_Controller {

	/**
	 * Registers routes.
	 *
	 * @return void
	 */
	public function register_routes() {
		register_rest_route(
			self::REST_NAMESPACE,
			'/settings',
			array(
				array(
					'methods'             => \WP_REST_Server::READABLE,
					'callback'            => array( $this, 'get_settings' ),
					'permission_callback' => array( $this, 'permission_check' ),
				),
				array(
					'methods'             => \WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'update_settings' ),
					'permission_callback' => array( $this, 'permission_check' ),
					'args'                => array(
						'global'  => array(
							'type'     => 'object',
							'required' => false,
						),
						'modules' => array(
							'type'     => 'object',
							'required' => false,
						),
					),
				),
			)
		);

		register_rest_route(
			self::REST_NAMESPACE,
			'/settings/(?P<module>[a-z][a-z0-9_]*)',
			array(
				array(
					'methods'             => \WP_REST_Server::READABLE,
					'callback'            => array( $this, 'get_module_settings' ),
					'permission_callback' => array( $this, 'permission_check' ),
				),
				array(
					'methods'             => \WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'update_module_settings' ),
					'permission_callback' => array( $this, 'permission_check' ),
					'args'                => array(
						'settings' => array(
							'type'     => 'object',
							'required' => true,
						),
					),
				),
			)
		);
	}

	/**
	 * Returns the full settings tree.
	 *
	 * @return \WP_REST_Response
	 */
	public function get_settings() {
		return rest_ensure_response( $this->plugin()->settings()->all() );
	}

	/**
	 * Writes a partial settings payload.
	 *
	 * @param \WP_REST_Request $request Request object.
	 * @return \WP_REST_Response|\WP_Error
	 */
	public function update_settings( \WP_REST_Request $request ) {
		$settings = $this->plugin()->settings();
		$global   = $request->get_param( 'global' );
		$modules  = $request->get_param( 'modules' );

		if ( is_array( $global ) ) {
			$result = $settings->update_global( $global );

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

		if ( is_array( $modules ) ) {
			foreach ( $modules as $module_id => $module_settings ) {
				if ( ! is_array( $module_settings ) ) {
					continue;
				}

				$result = $settings->update_module( (string) $module_id, $module_settings );

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

		return rest_ensure_response( $settings->all() );
	}

	/**
	 * Returns one module's settings and schema.
	 *
	 * @param \WP_REST_Request $request Request object.
	 * @return \WP_REST_Response|\WP_Error
	 */
	public function get_module_settings( \WP_REST_Request $request ) {
		$module_id = (string) $request->get_param( 'module' );

		if ( 'global' === $module_id ) {
			return rest_ensure_response(
				array(
					'id'       => 'global',
					'settings' => $this->plugin()->settings()->all()['global'],
					'schema'   => $this->plugin()->settings()->global_schema(),
				)
			);
		}

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

		return rest_ensure_response(
			array(
				'id'       => $module_id,
				'settings' => $this->plugin()->settings()->get_module( $module_id ),
				'schema'   => $this->plugin()->modules()->schema( $module_id ),
			)
		);
	}

	/**
	 * Writes one module's settings.
	 *
	 * @param \WP_REST_Request $request Request object.
	 * @return \WP_REST_Response|\WP_Error
	 */
	public function update_module_settings( \WP_REST_Request $request ) {
		$module_id = (string) $request->get_param( 'module' );
		$payload   = (array) $request->get_param( 'settings' );

		$result = 'global' === $module_id
			? $this->plugin()->settings()->update_global( $payload )
			: $this->plugin()->settings()->update_module( $module_id, $payload );

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

		return rest_ensure_response(
			array(
				'id'       => $module_id,
				'settings' => $result,
			)
		);
	}
}
