<?php
/**
 * Hide Admin Bar Module
 *
 * @package HideAdminBar
 * @since 1.0.0
 */

namespace HideAdminBar;

use WP_PowerSuite\Core\AbstractModule;

class Module extends AbstractModule {

	private const MODULE_ID = 'hide-admin-bar';
	private const MODULE_VERSION = '1.3.0';

	private ?array $settings_cache = null;

	public function getId(): string {
		return self::MODULE_ID;
	}

	public function getName(): string {
		return __( 'Hide Admin Bar', 'wp-powersuite' );
	}

	public function getVersion(): string {
		return self::MODULE_VERSION;
	}

	public function getDescription(): string {
		return __( 'Hides the front-end admin bar for chosen roles while they browse your site.', 'wp-powersuite' );
	}

	public function getContext(): string|array {
		return 'frontend';
	}

	protected function registerHooks(): void {
		add_filter( 'show_admin_bar', [ $this, 'hideAdminBar' ], 999 );
	}

	public function hideAdminBar( bool $show ): bool {
		if ( is_admin() || ! is_user_logged_in() ) {
			return $show;
		}

		$user = wp_get_current_user();
		if ( ! $user || ! $user->exists() || empty( $user->roles ) ) {
			return $show;
		}

		$settings      = $this->getSettings();
		$roles_to_hide = $settings['roles'];

		if ( empty( $roles_to_hide ) ) {
			return $show;
		}

		$user_roles = (array) $user->roles;

		if ( ! empty( $settings['always_show_for_admins'] )
			&& in_array( 'administrator', $user_roles, true )
		) {
			return true;
		}

		foreach ( $user_roles as $role ) {
			if ( in_array( $role, $roles_to_hide, true ) ) {
				return false;
			}
		}

		return true;
	}

	/**
	 * @param array<string, mixed> $raw Raw stored settings.
	 * @return array{roles: string[], always_show_for_admins: bool}
	 */
	public static function normalizeSettings( array $raw ): array {
		$defaults = ( new self() )->getDefaultSettings();
		$settings = array_merge( $defaults, $raw );

		$roles_raw = $settings['roles'] ?? [];
		$roles     = [];

		if ( is_array( $roles_raw ) && $roles_raw !== [] ) {
			if ( array_is_list( $roles_raw ) ) {
				$roles = array_map( 'sanitize_key', array_filter( $roles_raw, 'is_string' ) );
			} else {
				foreach ( $roles_raw as $role_key => $value ) {
					if ( ! empty( $value ) && is_string( $role_key ) ) {
						$roles[] = sanitize_key( $role_key );
					}
				}
			}
		}

		if ( $roles === [] ) {
			foreach ( $settings as $key => $value ) {
				if ( strpos( $key, 'roles' ) === 0 && strlen( $key ) > 5 && ! empty( $value ) ) {
					$role_key = substr( $key, 5 );
					if ( $role_key !== '' ) {
						$roles[] = sanitize_key( $role_key );
					}
				}
			}
		}

		if ( ! function_exists( 'wp_roles' ) ) {
			require_once ABSPATH . 'wp-admin/includes/user.php';
		}

		$roles_obj   = wp_roles();
		$valid_roles = is_object( $roles_obj ) && isset( $roles_obj->roles ) ? array_keys( $roles_obj->roles ) : [];
		$roles       = array_values(
			array_unique(
				array_filter(
					$roles,
					static function ( string $slug ) use ( $valid_roles ): bool {
						return $slug !== '' && ( $valid_roles === [] || in_array( $slug, $valid_roles, true ) );
					}
				)
			)
		);

		return [
			'roles'                  => $roles,
			'always_show_for_admins' => ! empty( $settings['always_show_for_admins'] ),
		];
	}

	private function getSettings(): array {
		if ( $this->settings_cache !== null ) {
			return $this->settings_cache;
		}

		$raw = $this->moduleSettings()->all( [] );
		if ( ! is_array( $raw ) ) {
			$raw = [];
		}

		$this->settings_cache = self::normalizeSettings( $raw );

		return $this->settings_cache;
	}

	public function getDefaultSettings(): array {
		return [
			'roles'                  => [ 'subscriber' ],
			'always_show_for_admins' => false,
		];
	}
}
