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

namespace Akeeba\Component\AkeebaBackup\Administrator\Model;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ModelExclusionFilterTrait;
use Akeeba\Engine\Factory;
use Exception;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Model\BaseModel;

#[\AllowDynamicProperties]
class MultipledatabasesModel extends BaseModel
{
	use ModelExclusionFilterTrait;

	/**
	 * Returns an array containing a list of database definitions
	 *
	 * @return  array  Array of definitions; The key contains the internal root name, the data is the database
	 *                 configuration data
	 */
	public function get_databases(): array
	{
		// Get database inclusion filters
		$filter = Factory::getFilterObject('multidb');

		return $filter->getInclusions('db');
	}

	/**
	 * Checks if a filter is already applied
	 *
	 * @param   array  $newFilter  Indexed array containing the filter data
	 *
	 * @return  bool    True if the filter already exists
	 * @since   7.5.0
	 */
	public function filterExists(array $newFilter): bool
	{
		// Sanity checks
		if (!isset($newFilter['host']) || !isset($newFilter['database']) || !isset($newFilter['prefix']))
		{
			return false;
		}

		$filters = $this->get_databases();

		foreach ($filters as $filter)
		{
			// If I have a filter with the same host, db name and table prefix, it means that they're the same
			if (
				($newFilter['host'] == $filter['host']) &&
				($newFilter['database'] == $filter['database']) &&
				($newFilter['prefix'] == $filter['prefix'])
			)
			{
				return true;
			}
		}

		return false;
	}

	/**
	 * Delete a database definition
	 *
	 * @param   string  $root  The name of the database root key to remove
	 *
	 * @return  bool  True on success
	 */
	public function remove($root)
	{
		$ret = $this->applyExclusionFilter('multidb', $root, null, 'remove');

		return $ret['success'];
	}

	/**
	 * Creates a new database definition
	 *
	 * @param   string  $root  The name of the database root key
	 * @param   array   $data  The connection information
	 *
	 * @return  array
	 */
	public function setFilter($root, $data)
	{
		$ret = $this->applyExclusionFilter('multidb', $root, $data, 'set');

		return $ret;
	}

	/**
	 * Tests the connectivity to a database
	 *
	 * @param   array  $data  The connection information
	 *
	 * @return  array  Status array: 'status' is true on success, 'message' contains any error message while connecting
	 *                 to the database
	 */
	public function test($data)
	{
		try
		{
			$db      = Factory::getDatabase($data);
			$success = $db->getErrorNum() <= 0;
			$error   = $db->getErrorMsg();
		}
		catch (Exception $e)
		{
			$success = false;
			$error   = $e->getMessage();
		}

		if (
			empty($data['driver']) || empty($data['host']) || empty($data['user']) || empty($data['password'])
			|| empty($data['database'])
		)
		{
			return [
				'status'  => false,
				'message' => Text::_('COM_AKEEBABACKUP_MULTIDB_ERR_MISSINGINFO'),
			];
		}

		return [
			'status'  => $success,
			'message' => $error,
		];
	}

	/**
	 * Handles a request coming in through AJAX. Basically, this is a simple proxy to the model methods.
	 *
	 * @return  array
	 */
	public function doAjax()
	{
		$action = $this->getState('action');
		$verb   = array_key_exists('verb', $action) ? $action['verb'] : null;

		$ret_array = [];

		switch ($verb)
		{
			// Set a filter (used by the editor)
			case 'set':
				$ret_array = $this->setFilter($action['root'], $action['data']);
				break;

			// Remove a filter (used by the editor)
			case 'remove':
				$ret_array = ['success' => $this->remove($action['root'])];
				break;

			// Test connection (used by the editor)
			case 'test':
				$ret_array = $this->test($action['data']);
				break;
		}

		return $ret_array;
	}
}