<?php
/**
 * Capability handling for MenuVerse administration screens and REST routes.
 *
 * @package MenuVerse
 */

namespace WPXero\MenuVerse;

defined( 'ABSPATH' ) || exit;

/**
 * Owns the dedicated management capability and its fallbacks.
 */
final class Capabilities {

	/**
	 * Dedicated management capability.
	 *
	 * @var string
	 */
	const MANAGE = 'menuverse_manage';

	/**
	 * Capability relied on when the dedicated one is unavailable.
	 *
	 * @var string
	 */
	const FALLBACK = 'manage_options';

	/**
	 * Returns the capability required to manage the plugin.
	 *
	 * @return string
	 */
	public static function manage() {
		/**
		 * Filters the capability required to manage MenuVerse.
		 *
		 * @since 1.0.0
		 *
		 * @param string $capability Capability name.
		 */
		$capability = apply_filters( 'menuverse_capability', self::MANAGE );

		return is_string( $capability ) && '' !== $capability ? $capability : self::MANAGE;
	}

	/**
	 * Checks whether the current user may manage the plugin.
	 *
	 * Falls back to the site administration capability when the dedicated
	 * capability has been stripped from every role by a role editor.
	 *
	 * @return bool
	 */
	public static function current_user_can_manage() {
		$capability = self::manage();

		if ( current_user_can( $capability ) ) {
			return true;
		}

		if ( self::MANAGE === $capability && ! self::capability_exists( $capability ) ) {
			return current_user_can( self::FALLBACK );
		}

		return false;
	}

	/**
	 * Grants the management capability to roles that administer the site.
	 *
	 * @return void
	 */
	public static function add_caps() {
		foreach ( wp_roles()->roles as $role_name => $role_data ) {
			$role = get_role( $role_name );

			if ( $role instanceof \WP_Role && $role->has_cap( self::FALLBACK ) ) {
				$role->add_cap( self::MANAGE );
			}
		}
	}

	/**
	 * Removes the management capability from every role.
	 *
	 * @return void
	 */
	public static function remove_caps() {
		foreach ( array_keys( wp_roles()->roles ) as $role_name ) {
			$role = get_role( $role_name );

			if ( $role instanceof \WP_Role ) {
				$role->remove_cap( self::MANAGE );
			}
		}
	}

	/**
	 * Determines whether any role currently holds a capability.
	 *
	 * @param string $capability Capability name.
	 * @return bool
	 */
	private static function capability_exists( $capability ) {
		foreach ( wp_roles()->roles as $role_data ) {
			if ( ! empty( $role_data['capabilities'][ $capability ] ) ) {
				return true;
			}
		}

		return false;
	}
}
