<?php

namespace UserRoleBodyClass;

use WP_PowerSuite\Core\AbstractModule;

class Module extends AbstractModule {

	private const MODULE_ID      = 'user-role-body-class';
	private const MODULE_VERSION = '1.0.3';

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

	public function getName(): string {
		return __( 'User Role Body Class', 'wp-powersuite' );
	}

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

	public function getDescription(): string {
		return __( 'Body classes per user role (and guests) for role-based styling on the front end and in admin.', 'wp-powersuite' );
	}

	public function getContext(): string|array {
		return [ 'frontend', 'admin' ];
	}

	protected function registerHooks(): void {
		if ( is_admin() ) {
			add_filter( 'admin_body_class', [ $this, 'addAdminRoleBodyClasses' ], 10, 1 );
		} else {
			add_filter( 'body_class', [ $this, 'addRoleBodyClasses' ], 10, 1 );
		}
	}

	public function addRoleBodyClasses( array $classes ): array {
		return self::mergeIntoArray( $classes, self::collectRoleClasses( true ) );
	}

	public function addAdminRoleBodyClasses( string $classes ): string {
		return self::appendToString( $classes, self::collectRoleClasses( false ) );
	}

	/**
	 * @return list<string>
	 */
	public static function collectRoleClasses( bool $include_guest ): array {
		if ( ! is_user_logged_in() ) {
			return $include_guest ? [ 'role-guest' ] : [];
		}

		$user = wp_get_current_user();
		if ( ! $user->exists() ) {
			return $include_guest ? [ 'role-guest' ] : [];
		}

		$out = [];
		foreach ( (array) $user->roles as $role ) {
			$role = sanitize_key( (string) $role );
			if ( $role === '' ) {
				continue;
			}

			$class = 'role-' . sanitize_html_class( $role, 'role' );
			if ( $class !== 'role-role' && ! in_array( $class, $out, true ) ) {
				$out[] = $class;
			}
		}

		return $out;
	}

	/**
	 * @param list<string> $classes
	 * @param list<string> $extra
	 * @return list<string>
	 */
	private static function mergeIntoArray( array $classes, array $extra ): array {
		foreach ( $extra as $class ) {
			if ( ! in_array( $class, $classes, true ) ) {
				$classes[] = $class;
			}
		}

		return $classes;
	}

	/**
	 * @param list<string> $extra
	 */
	private static function appendToString( string $classes, array $extra ): string {
		if ( $extra === [] ) {
			return $classes;
		}

		$existing = preg_split( '/\s+/', trim( $classes ) );
		$existing = is_array( $existing ) ? $existing : [];

		foreach ( $extra as $class ) {
			if ( ! in_array( $class, $existing, true ) ) {
				$classes .= ' ' . $class;
				$existing[] = $class;
			}
		}

		return $classes;
	}
}
