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

namespace Joomla\Plugin\Actionlog\AkeebaBackup\Extension;

defined('_JEXEC') || die;

use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\User\User;
use Joomla\Component\Actionlogs\Administrator\Plugin\ActionLogPlugin;
use Joomla\Event\Event;
use Joomla\Event\SubscriberInterface;
use ReflectionMethod;

class AkeebaBackup extends ActionLogPlugin implements SubscriberInterface
{
	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.1
	 */
	protected $autoloadLanguage = true;

	/**
	 * Application object.
	 *
	 * @var    \Joomla\CMS\Application\CMSApplication
	 * @since  3.7.0
	 */
	protected $app;

	private $defaultExtension = 'com_akeebabackup';

	/**
	 * Returns an array of events this subscriber will listen to.
	 *
	 * @return  array
	 *
	 * @since   9.0.0
	 */
	public static function getSubscribedEvents(): array
	{
		// Only subscribe events if the component is installed and enabled
		if (!ComponentHelper::isEnabled('com_akeebabackup'))
		{
			return [];
		}

		// Register all public onSomething methods as event handlers
		$events   = [];
		$refClass = new \ReflectionClass(__CLASS__);
		$methods  = $refClass->getMethods(ReflectionMethod::IS_PUBLIC);

		foreach ($methods as $method)
		{
			$name = $method->getName();

			if (substr($name, 0, 2) != 'on')
			{
				continue;
			}

			$events[$name] = $name;
		}

		return $events;
	}

	public function onContentAfterSave(Event $event)
	{
		$arguments = $event->getArguments();
		$context   = $arguments[0] ?? '';
		$table     = $arguments[1] ?? null;
		$isNew     = $arguments[2] ?? false;

		switch ($context)
		{
			// Akeeba Backup profiles
			case 'com_akeebabackup.profile':
				$extraData = [
					'title' => $table->description,
					'id'    => $table->getId(),
				];

				if ($isNew)
				{
					$this->logUserAction($extraData, 'COM_AKEEBABACKUP_LOGS_PROFILE_ADD');
				}
				else
				{
					$this->logUserAction($extraData, 'COM_AKEEBABACKUP_LOGS_PROFILE_EDIT');
				}
				break;

			// Akeeba Backup statistics (backup attempts)
			case 'com_akeebabackup.statistic':
				$extraData = [
					'id' => $table->getId(),
				];
				$this->logUserAction($extraData, 'COM_AKEEBABACKUP_LOGS_MANAGE_EDIT');

				break;
		}
	}

	public function onContentChangeState(Event $event)
	{
		$arguments = $event->getArguments();
		$context   = $arguments[0] ?? '';
		$pks       = $arguments[1] ?? [];
		$value     = $arguments[2] ?? 1;

		switch ($context)
		{
			// Akeeba Backup profiles
			case 'com_akeebabackup.profile':
				$languageKey = ($value == 0) ? 'COM_AKEEBABACKUP_LOGS_PROFILE_UNQUICK' : 'COM_AKEEBABACKUP_LOGS_PROFILE_QUICK';

				$this->logUserAction(implode(', ', $pks), $languageKey);
				break;

			// Akeeba Backup statistics (backup attempts)
			case 'com_akeebabackup.statistic':
				$languageKey = ($value == 0) ? 'COM_AKEEBABACKUP_LOGS_MANAGE_UNFREEZE' : 'COM_AKEEBABACKUP_LOGS_MANAGE_FREEZE';

				$this->logUserAction(implode(', ', $pks), $languageKey);
				break;
		}
	}

	public function onContentAfterDelete(Event $event)
	{
		$arguments = $event->getArguments();
		$context   = $arguments[0] ?? '';
		$table     = $arguments[1] ?? null;

		switch ($context)
		{
			// Akeeba Backup profiles
			case 'com_akeebabackup.profile':
				$this->logUserAction([
					'id' => $table->getId(),
				], 'COM_AKEEBABACKUP_LOGS_PROFILE_DELETE');
				break;

			// Akeeba Backup statistics (backup attempts)
			case 'com_akeebabackup.statistic':
				$this->logUserAction([
					'id' => $table->getId(),
				], 'COM_AKEEBABACKUP_LOGS_MANAGE_DELETE');
				break;
		}
	}

	public function onComAkeebabackupProfileControllerBeforeExport(Event $event)
	{
		$arguments = $event->getArguments();
		$id        = $arguments[1] ?? null;

		$this->logUserAction([
			'id' => $id,
		], 'COM_AKEEBABACKUP_LOGS_PROFILE_EXPORT');
	}

	public function onComAkeebabackupProfileControllerAfterImport(Event $event)
	{
		$arguments = $event->getArguments();
		$id        = $arguments[1] ?? null;

		$this->logUserAction([
			'id' => $id,
		], 'COM_AKEEBABACKUP_LOGS_PROFILE_IMPORT');
	}

	public function onComAkeebabackupModelStatisticAfterDeleteFiles(Event $event)
	{
		$arguments = $event->getArguments();
		$id        = $arguments[1] ?? null;

		$this->logUserAction([
			'id' => $id,
		], 'COM_AKEEBABACKUP_LOGS_MANAGE_DELETEFILES');
	}

	public function onComAkeebabackupManageControllerBeforeDownload(Event $event)
	{
		$arguments = $event->getArguments();
		$id        = $arguments[1] ?? null;
		$part      = $arguments[2] ?? null;

		$this->logUserAction([
			'id'   => $id,
			'part' => $part,
		], 'COM_AKEEBABACKUP_LOGS_MANAGE_DELETEFILES');
	}

	public function onComAkeebabackupConfigurationControllerAfterApply(Event $event)
	{
		$arguments = $event->getArguments();
		$id        = $arguments[1] ?? null;

		$this->logUserAction([
			'id' => $id,
		], 'COM_AKEEBABACKUP_LOGS_CONFIGURATION_EDIT');
	}

	public function onComAkeebabackupModelBackupStart(Event $event)
	{
		$arguments = $event->getArguments();
		$id        = $arguments[1] ?? null;
		$profile   = $arguments[2] ?? null;
		$this->logUserAction([
			'id'      => $id,
			'profile' => $profile,
		], 'COM_AKEEBABACKUP_LOGS_BACKUP_RUN');
	}

	public function onComAkeebabackupLogControllerDownload(Event $event)
	{
		$arguments = $event->getArguments();
		$tag       = $arguments[1] ?? null;

		if (is_null($tag))
		{
			$this->logUserAction([
				'title' => 'latest',
			], 'COM_AKEEBABACKUP_LOGS_LOG_DOWNLOAD_LATEST');

			return;
		}

		$this->logUserAction([
			'title' => $tag,
		], 'COM_AKEEBABACKUP_LOGS_LOG_DOWNLOAD');
	}

	public function onComAkeebabackupTransferControllerBeforeInitialiseUpload(Event $event)
	{
		$this->logUserAction([
			'title' => $this->app->getSession()->get('akeebabackup.transfer.url', null),
		], 'COM_AKEEBABACKUP_LOGS_TRANSFER_RUN');
	}

	public function onComAkeebabackupRemoteFilesControllerFetch(Event $event)
	{
		$arguments = $event->getArguments();
		$id        = $arguments[1] ?? null;

		$this->logUserAction([
			'id' => $id,
		], 'COM_AKEEBABACKUP_LOGS_REMOTEFILE_FETCH');
	}

	public function onComAkeebabackupRemoteFilesControllerDownload(Event $event)
	{
		$arguments = $event->getArguments();
		$id        = $arguments[1] ?? null;
		$part      = $arguments[2] ?? null;

		$this->logUserAction([
			'id'   => $id,
			'part' => $part,
		], 'COM_AKEEBABACKUP_LOGS_REMOTEFILE_DOWNLOAD');
	}

	public function onComAkeebabackupRemoteFilesControllerDelete(Event $event)
	{
		$arguments = $event->getArguments();
		$id        = $arguments[1] ?? null;

		$this->logUserAction([
			'id' => $id,
		], 'COM_AKEEBABACKUP_LOGS_REMOTEFILE_DELETE');
	}

	public function onComAkeebabackupUploadControllerStart(Event $event)
	{
		$arguments = $event->getArguments();
		$id        = $arguments[1] ?? null;

		$this->logUserAction([
			'id' => $id,
		], 'COM_AKEEBABACKUP_LOGS_UPLOADS_ADD');
	}

	public function onComAkeebabackupUploadControllerSuccessfulImport(Event $event)
	{
		$arguments = $event->getArguments();
		$id        = $arguments[1] ?? null;

		$this->logUserAction([
			'id' => $id,
		], 'COM_AKEEBABACKUP_LOGS_DISCOVER_IMPORT');
	}

	public function onComAkeebabackupS3importControllerSuccessfulImport(Event $event)
	{
		$arguments = $event->getArguments();
		$bucket    = $arguments[1] ?? null;
		$folder    = $arguments[2] ?? null;
		$file      = $arguments[3] ?? null;

		$path = $folder . ($folder == '' ? '' : '/') . $file;

		$this->logUserAction([
			'bucket' => $bucket,
			'path'   => $path,
		], 'COM_AKEEBABACKUP_LOGS_S3IMPORT_IMPORT');
	}

	/**
	 * Log a user action.
	 *
	 * This is a simple wrapper around self::addLog
	 *
	 * @param   string|array  $title               Language key for title or an array of additional data to record in
	 *                                             the audit log.
	 * @param   string        $messageLanguageKey  Language key describing the user action taken.
	 * @param   string|null   $context             The name of the extension being logged (default: use
	 *                                             $this->defaultExtension).
	 * @param   User|null     $user                User object taking this action (default: currently logged in user).
	 *
	 * @return  void
	 *
	 * @see     self::addLog
	 * @since   9.0.0
	 */
	private function logUserAction($title, string $messageLanguageKey, ?string $context = null, ?User $user = null): void
	{
		// Get the user if not defined
		$user = $user ?? $this->app->getIdentity();

		// No log for guests
		if (empty($user) || ($user->guest))
		{
			return;
		}

		// Default extension if none defined
		$context = $context ?? $this->defaultExtension;

		$message = [
			'username'    => $user->username,
			'accountlink' => 'index.php?option=com_users&task=user.edit&id=' . $user->id,
		];

		if (!is_array($title))
		{
			$title = [
				'title' => $title,
			];
		}

		$message = array_merge($message, $title);

		$this->addLog([$message], $messageLanguageKey, $context, $user->id);
	}
}