<?php
/**
 * @package   admintools
 * @copyright Copyright (c)2010-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Plugin\Task\AdminTools\Extension;

defined('_JEXEC') or die;

use Akeeba\Plugin\Task\AdminTools\Extension\SubTask\AutoImport;
use Akeeba\Plugin\Task\AdminTools\Extension\SubTask\CacheCleaner;
use Akeeba\Plugin\Task\AdminTools\Extension\SubTask\DeleteInactiveUsers;
use Akeeba\Plugin\Task\AdminTools\Extension\SubTask\Jupdate;
use Akeeba\Plugin\Task\AdminTools\Extension\SubTask\PhpFileChangeScanner;
use Akeeba\Plugin\Task\AdminTools\Extension\SubTask\RemoveOldLogEntries;
use Akeeba\Plugin\Task\AdminTools\Extension\SubTask\SessionCleaner;
use Akeeba\Plugin\Task\AdminTools\Extension\SubTask\SessionOptimizer;
use Akeeba\Plugin\Task\AdminTools\Extension\SubTask\TaskRegistryAware;
use Akeeba\Plugin\Task\AdminTools\Extension\SubTask\TempDirCleaner;
use Akeeba\Plugin\Task\AdminTools\Extension\Traits\LoadLanguageTrait;
use Exception;
use InvalidArgumentException;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\Filesystem\Path;
use Joomla\CMS\Form\Form;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\Component\Scheduler\Administrator\Traits\TaskPluginTrait;
use Joomla\Database\DatabaseAwareInterface;
use Joomla\Database\DatabaseAwareTrait;
use Joomla\Event\EventInterface;
use Joomla\Event\SubscriberInterface;

/**
 * Integration with Joomla Scheduled Tasks
 *
 * @since 7.1.2
 */
class AdminTools extends CMSPlugin implements SubscriberInterface, DatabaseAwareInterface
{
	use LoadLanguageTrait;
	use AutoImport;
	use CacheCleaner;
	use DatabaseAwareTrait;
	use DeleteInactiveUsers;
	use PhpFileChangeScanner;
	use RemoveOldLogEntries;
	use SessionCleaner;
	use SessionOptimizer;
	use TaskPluginTrait;
	use TaskRegistryAware;
	use TempDirCleaner;
	use Jupdate;

	private const TASKS_MAP = [
		'admintools.scan'                => [
			'langConstPrefix' => 'PLG_TASK_ADMINTOOLS_TASK_SCAN',
			'method'          => 'scan',
			'form'            => 'scanForm',
		],
		'admintools.removeOldLogEntries' => [
			'langConstPrefix' => 'PLG_TASK_ADMINTOOLS_TASK_REMOVEOLDLOGENTRIES',
			'method'          => 'removeOldLogEntries',
			'form'            => 'removeOldLogEntriesForm',
		],
		'admintools.SessionOptimizer'    => [
			'langConstPrefix' => 'PLG_TASK_ADMINTOOLS_TASK_SESSIONOPTIMIZER',
			'method'          => 'sessionOptimizer',
		],
		'admintools.sessionCleaner'      => [
			'langConstPrefix' => 'PLG_TASK_ADMINTOOLS_TASK_SESSIONCLEANER',
			'method'          => 'sessionCleaner',
		],
		'admintools.cacheCleaner'        => [
			'langConstPrefix' => 'PLG_TASK_ADMINTOOLS_TASK_CACHECLEANER',
			'method'          => 'cacheCleaner',
			'form'            => 'cacheCleanerForm',
		],
		'admintools.tempDirCleaner'      => [
			'langConstPrefix' => 'PLG_TASK_ADMINTOOLS_TASK_TEMPDIRCLEANER',
			'method'          => 'tempDirCleaner',
		],
		'admintools.deleteInactiveUsers' => [
			'langConstPrefix' => 'PLG_TASK_ADMINTOOLS_TASK_DELETEINACTIVEUSERS',
			'method'          => 'deleteInactiveUsers',
			'form'            => 'deleteInactiveUsersForm',
		],
		'admintools.autoImport'          => [
			'langConstPrefix' => 'PLG_TASK_ADMINTOOLS_TASK_AUTOIMPORT',
			'method'          => 'autoImport',
			'form'            => 'autoImportForm',
		],
		'admintools.jupdate'             => [
			'langConstPrefix' => 'PLG_TASK_ADMINTOOLS_TASK_JUPDATE',
			'method'          => 'jupdate',
			'form'            => 'jupdateForm',
		],
	];

	/**
	 * Affects constructor behavior. If true, language files will be loaded automatically.
	 *
	 * @var   boolean
	 * @since 7.1.2
	 */
	protected $autoloadLanguage = true;

	/**
	 * Returns an array of events this subscriber will listen to.
	 *
	 * This is mostly boilerplate code as per every built-in Task plugin in Joomla.
	 *
	 * @return  array
	 * @since   7.1.2
	 */
	public static function getSubscribedEvents(): array
	{
		// This task is disabled if the Akeeba Backup component is not installed or has been unpublished
		if (!ComponentHelper::isEnabled('com_admintools'))
		{
			return [];
		}

		return [
			'onTaskOptionsList'    => 'advertiseRoutines',
			'onExecuteTask'        => 'standardRoutineHandler',
			'onContentPrepareForm' => 'enhanceTaskItemForm',
		];
	}

	/**
	 * Enhance the task form with routine-specific fields from an XML file declared through the TASKS_MAP constant.
	 * If a plugin only supports the task form and does not need additional logic, this method can be mapped to the
	 * `onContentPrepareForm` event through {@see SubscriberInterface::getSubscribedEvents()} and will take care
	 * of injecting the fields without additional logic in the plugin class.
	 *
	 * @param   EventInterface|Form  $context  The onContentPrepareForm event or the Form object.
	 * @param   mixed                $data     The form data, required when $context is a {@see Form} instance.
	 *
	 * @return  boolean  True if the form was successfully enhanced or the context was not relevant.
	 *
	 * @throws  Exception
	 * @since   7.1.2
	 */
	public function enhanceTaskItemForm($context, $data = null): bool
	{
		if ($context instanceof EventInterface)
		{
			/** @var Form $form */
			[$form, $data] = array_values($context->getArguments());
		}
		elseif ($context instanceof Form)
		{
			$form = $context;
		}
		else
		{
			throw new InvalidArgumentException(
				sprintf(
					'Argument 0 of %1$s must be an instance of %2$s or %3$s',
					__METHOD__,
					EventInterface::class,
					Form::class
				)
			);
		}

		if ($form->getName() !== 'com_scheduler.task')
		{
			return true;
		}

		$routineId           = $this->getRoutineId($form, $data);
		$isSupported         = array_key_exists($routineId, self::TASKS_MAP);
		$enhancementFormName = self::TASKS_MAP[$routineId]['form'] ?? '';

		// Return if routine is not supported by the plugin or the routine does not have a form linked in TASKS_MAP.
		if (!$isSupported || strlen($enhancementFormName) === 0)
		{
			return true;
		}

		// We expect the form XML in "{PLUGIN_PATH}/forms/{FORM_NAME}.xml"
		$path                = JPATH_PLUGINS . '/' . $this->_type . '/' . $this->_name;
		$enhancementFormFile = $path . '/forms/' . $enhancementFormName . '.xml';

		try
		{
			$enhancementFormFile = Path::check($enhancementFormFile);
		}
		catch (Exception $e)
		{
			return false;
		}

		if (is_file($enhancementFormFile))
		{
			return $form->loadFile($enhancementFormFile);
		}

		return false;
	}

}