<?php
/**
 * @package   admintoolswp
 * @copyright Copyright (c)2017-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU GPL version 3 or later
 */

defined('ADMINTOOLSINC') or die;

use Akeeba\AdminTools\Admin\Helper\Language;
use Akeeba\AdminTools\Admin\Helper\Wordpress;

class AtsystemFeatureMonitorsuperusers extends AtsystemFeatureAbstract
{
	/** @var bool Is the current update considered safe (initiated via WP Admin UI)? */
	private $isSafeUpdate = false;

	/**
	 * Is this feature enabled?
	 *
	 * @return bool
	 */
	public function isEnabled()
	{
		return $this->cparams->getValue('monitorsuperusers', 0) == 1;
	}

	/**
	 * Register custom hooks
	 */
	public function onCustomHooks()
	{
		add_action('profile_update', [$this, 'onUserAfterSave'], 99, 1);
	}

	/**
	 * Check for new super users on every request
	 */
	public function onWordPressInit()
	{
		// Detect if we are on a user management page in the backend
		if (is_admin())
		{
			global $pagenow;

			if (in_array($pagenow, ['users.php', 'user-new.php', 'user-edit.php', 'profile.php']))
			{
				$this->isSafeUpdate = true;
			}
		}

		$this->checkNewSuperUsers();
	}

	/**
	 * Update the list of super users when a user is created or updated via the UI
	 *
	 * @param   int  $user_id
	 */
	public function onUserAfterSave($user_id)
	{
		if ($this->isSafeUpdate)
		{
			$this->updateSuperUsersList();
		}
	}

	/**
	 * Called before saving a user in the UI. Used to mark the update as safe.
	 *
	 * @param   WP_Error  $errors
	 * @param   bool      $update
	 * @param   WP_User   $user
	 */
	public function onUserBeforeSave(&$errors, $update, &$user)
	{
		$this->isSafeUpdate = true;
	}

	/**
	 * Prevent blocked users from authenticating
	 *
	 * @param   WP_Error|WP_User  $user
	 * @param   string            $username
	 * @param   string            $password
	 *
	 * @return  WP_User|WP_Error
	 */
	public function onUserAuthenticate($user, $username, $password)
	{
		if ($user instanceof WP_User)
		{
			$isBlocked = get_user_meta($user->ID, 'admintoolswp_blocked', true);

			if ($isBlocked)
			{
				return new WP_Error('admintoolswp_blocked', Language::_('COM_ADMINTOOLS_ERROR_USER_BLOCKED'));
			}
		}

		return $user;
	}

	/**
	 * Detects new super users and blocks them
	 */
	protected function checkNewSuperUsers()
	{
		$monitoredRoles = $this->cparams->getValue('monitorsuperusers_roles', ['administrator']);
		$monitoredRoles = is_array($monitoredRoles) ? $monitoredRoles : (empty($monitoredRoles) ? [] : [$monitoredRoles]);

		if (empty($monitoredRoles) && !is_multisite())
		{
			return;
		}

		$knownSuperUsers = $this->cparams->getValue('super_users', []);
		
		// If the list is empty, it might be the first run.
		// Let's populate it and return.
		if (empty($knownSuperUsers))
		{
			$this->updateSuperUsersList();

			return;
		}

		$currentSuperUsers = $this->getCurrentSuperUsers($monitoredRoles);

		$newSuperUsers = array_diff($currentSuperUsers, $knownSuperUsers);

		if (empty($newSuperUsers))
		{
			return;
		}

		$blockedUsersInfo = [];

		foreach ($newSuperUsers as $user_id)
		{
			$user = get_userdata($user_id);

			if (!$user)
			{
				continue;
			}

			// Block the user
			update_user_meta($user_id, 'admintoolswp_blocked', 1);

			$blockedUsersInfo[] = sprintf("%s (%s) - %s", $user->display_name, $user->user_login, $user->user_email);
		}

		if (!empty($blockedUsersInfo))
		{
			$this->sendNotificationEmail($blockedUsersInfo);
		}

		// Update the list of known super users to avoid repeated notifications
		$this->updateSuperUsersList();
	}

	/**
	 * Updates the stored list of super users
	 */
	protected function updateSuperUsersList()
	{
		$roles = $this->cparams->getValue('monitorsuperusers_roles', ['administrator']);
		$roles = is_array($roles) ? $roles : (empty($roles) ? [] : [$roles]);

		$currentSuperUsers = $this->getCurrentSuperUsers($roles);
		$this->cparams->setValue('super_users', $currentSuperUsers, true);
	}

	/**
	 * Gets the list of user IDs that have the monitored roles
	 *
	 * @param   array  $roles
	 *
	 * @return  array
	 */
	protected function getCurrentSuperUsers(array $roles)
	{
		$user_ids = [];

		if (!empty($roles))
		{
			$user_query = new WP_User_Query([
				'role__in' => $roles,
				'fields'   => 'ID',
			]);
			$user_ids = $user_query->get_results();
		}

		// Handle Super Admins in Multisite
		if (function_exists('is_multisite') && is_multisite())
		{
			$super_admins = get_super_admins();
			foreach ($super_admins as $login)
			{
				$user = get_user_by('login', $login);
				if ($user)
				{
					$user_ids[] = (int)$user->ID;
				}
			}
		}

		$user_ids = array_map('intval', $user_ids);
		$user_ids = array_unique($user_ids);
		sort($user_ids);

		return $user_ids;
	}

	/**
	 * Sends a notification email about the blocked new super users
	 *
	 * @param   array  $usersInfo
	 */
	protected function sendNotificationEmail(array $usersInfo)
	{
		$email = $this->cparams->getValue('monitorsuperusers_email', '');

		if (empty($email))
		{
			$email = $this->cparams->getValue('emailafteripautoban', '');
		}

		$recipients = [];

		if (empty($email))
		{
			// Get all active admins
			$admins = get_users(['role' => 'administrator']);
			foreach ($admins as $admin)
			{
				$recipients[] = $admin->user_email;
			}
		}
		else
		{
			$recipients = explode(',', $email);
		}

		$recipients = array_map('trim', $recipients);
		$recipients = array_unique(array_filter($recipients));

		if (empty($recipients))
		{
			return;
		}

		$subjectTemplate = Language::_('COM_ADMINTOOLS_LBL_MONITORSUPERUSERS_EMAIL_SUBJECT');
		$bodyTemplate    = Language::_('COM_ADMINTOOLS_LBL_MONITORSUPERUSERS_EMAIL_BODY');

		$sitename = get_option('blogname');
		$siteurl  = get_option('siteurl');
		$info     = implode("\n", $usersInfo);

		$subject = str_replace('[SITENAME]', $sitename, $subjectTemplate);
		$body    = str_replace('[SITENAME]', $sitename, $bodyTemplate);
		$body    = str_replace('[SITEURL]', $siteurl, $body);
		$body    = str_replace('[INFO]', $info, $body);

		Wordpress::sendEmail($recipients, $subject, $body, true, false);
	}
}
