<?php

/**
 * @package     Joomla.Administrator
 * @subpackage  com_config
 *
 * @copyright   (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

namespace Joomla\Component\Config\Administrator\Controller;

use Joomla\CMS\Application\CMSApplication;
use Joomla\CMS\Application\CMSWebApplicationInterface;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Controller\BaseController;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\CMS\Response\JsonResponse;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Session\Session;
use Joomla\Input\Input;

// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects

/**
 * Controller for global configuration
 *
 * @since  1.5
 */
class ApplicationController extends BaseController
{
    /**
     * Constructor.
     *
     * @param   array                 $config   An optional associative array of configuration settings.
     *                                          Recognized key values include 'name', 'default_task', 'model_path', and
     *                                          'view_path' (this list is not meant to be comprehensive).
     * @param   ?MVCFactoryInterface  $factory  The factory.
     * @param   ?CMSApplication       $app      The Application for the dispatcher
     * @param   ?Input                $input    Input
     *
     * @since   3.0
     */
    public function __construct($config = [], ?MVCFactoryInterface $factory = null, $app = null, $input = null)
    {
        parent::__construct($config, $factory, $app, $input);

        // Map the apply task to the save method.
        $this->registerTask('apply', 'save');
    }

    /**
     * Cancel operation.
     *
     * @return  void
     *
     * @since   3.0.0
     */
    public function cancel()
    {
        $this->setRedirect(Route::_('index.php?option=com_cpanel'));
    }

    /**
     * Saves the form
     *
     * @return  void|boolean  Void on success. Boolean false on fail.
     *
     * @since  4.0.0
     */
    public function save()
    {
        // Check for request forgeries.
        $this->checkToken();

        // Check if the user is authorized to do this.
        if (!$this->app->getIdentity()->authorise('core.admin')) {
            $this->setRedirect('index.php', Text::_('JERROR_ALERTNOAUTHOR'), 'error');

            return false;
        }

        $this->app->setUserState('com_config.config.global.data', null);

        /** @var \Joomla\Component\Config\Administrator\Model\ApplicationModel $model */
        $model = $this->getModel('Application', 'Administrator');

        $data  = $this->input->post->get('jform', [], 'array');

        // Complete data array if needed
        $oldData = $model->getData();
        $data    = array_replace($oldData, $data);

        // Get request type
        $saveFormat = $this->app->getDocument()->getType();

        // Handle service requests
        if ($saveFormat == 'json') {
            $form   = $model->getForm();
            $return = $model->validate($form, $data);

            if ($return === false) {
                $this->app->setHeader('Status', 422, true);

                return false;
            }

            return $model->save($return);
        }

        // Must load after serving service-requests
        $form = $model->getForm();

        // Validate the posted data.
        $return = $model->validate($form, $data);

        // Check for validation errors.
        if ($return === false) {
            // Get the validation messages.
            $errors = $model->getErrors();

            // Push up to three validation messages out to the user.
            for ($i = 0, $n = \count($errors); $i < $n && $i < 3; $i++) {
                if ($errors[$i] instanceof \Exception) {
                    $this->app->enqueueMessage($errors[$i]->getMessage(), CMSWebApplicationInterface::MSG_ERROR);
                } else {
                    $this->app->enqueueMessage($errors[$i], CMSWebApplicationInterface::MSG_ERROR);
                }
            }

            // Save the posted data in the session.
            $this->app->setUserState('com_config.config.global.data', $data);

            // Redirect back to the edit screen.
            $this->setRedirect(Route::_('index.php?option=com_config', false));

            return false;
        }

        // Validate database connection data.
        $data   = $return;
        $return = $model->validateDbConnection($data);

        // Check for validation errors.
        if ($return === false) {
            /*
             * The validateDbConnection method enqueued all messages for us.
             */

            // Save the posted data in the session.
            $this->app->setUserState('com_config.config.global.data', $data);

            // Redirect back to the edit screen.
            $this->setRedirect(Route::_('index.php?option=com_config', false));

            return false;
        }

        // Save the validated data in the session.
        $this->app->setUserState('com_config.config.global.data', $return);

        // Attempt to save the configuration.
        $data   = $return;
        $return = $model->save($data);

        // Check the return value.
        if ($return === false) {
            /*
             * The save method enqueued all messages for us, so we just need to redirect back.
             */

            // Save failed, go back to the screen and display a notice.
            $this->setRedirect(Route::_('index.php?option=com_config', false));

            return false;
        }

        // Set the success message.
        $this->app->enqueueMessage(Text::_('COM_CONFIG_SAVE_SUCCESS'), 'message');

        // Set the redirect based on the task.
        switch ($this->input->getCmd('task')) {
            case 'apply':
                $this->setRedirect(Route::_('index.php?option=com_config', false));
                break;

            case 'save':
            default:
                $this->setRedirect(Route::_('index.php', false));
                break;
        }
    }

    /**
     * Method to remove root in global configuration.
     *
     * @return  boolean
     *
     * @since   3.2
     */
    public function removeroot()
    {
        // Check for request forgeries.
        if (!Session::checkToken('get')) {
            $this->setRedirect('index.php', Text::_('JINVALID_TOKEN'), 'error');

            return false;
        }

        // Check if the user is authorized to do this.
        if (!$this->app->getIdentity()->authorise('core.admin')) {
            $this->setRedirect('index.php', Text::_('JERROR_ALERTNOAUTHOR'), 'error');

            return false;
        }

        // Initialise model.

        /** @var \Joomla\Component\Config\Administrator\Model\ApplicationModel $model */
        $model = $this->getModel('Application', 'Administrator');

        // Attempt to save the configuration and remove root.
        try {
            $model->removeroot();
        } catch (\RuntimeException $e) {
            // Save failed, go back to the screen and display a notice.
            $this->setRedirect('index.php', Text::_('JERROR_SAVE_FAILED', $e->getMessage()), 'error');

            return false;
        }

        // Set the redirect based on the task.
        $this->setRedirect(Route::_('index.php'), Text::_('COM_CONFIG_SAVE_SUCCESS'));

        return true;
    }

    /**
     * Method to send the test mail.
     *
     * @return  void
     *
     * @since   3.5
     */
    public function sendtestmail()
    {
        // Send json mime type.
        $this->app->mimeType = 'application/json';
        $this->app->setHeader('Content-Type', $this->app->mimeType . '; charset=' . $this->app->charSet);
        $this->app->sendHeaders();

        // Check if user token is valid.
        if (!Session::checkToken()) {
            $this->app->enqueueMessage(Text::_('JINVALID_TOKEN'), 'error');
            echo new JsonResponse();
            $this->app->close();
        }

        // Check if the user is authorized to do this.
        if (!$this->app->getIdentity()->authorise('core.admin')) {
            $this->app->enqueueMessage(Text::_('JERROR_ALERTNOAUTHOR'), 'error');
            echo new JsonResponse();
            $this->app->close();
        }

        /** @var \Joomla\Component\Config\Administrator\Model\ApplicationModel $model */
        $model = $this->getModel('Application', 'Administrator');

        echo new JsonResponse($model->sendTestMail());

        $this->app->close();
    }

    /**
     * Method to GET permission value and give it to the model for storing in the database.
     *
     * @return  void
     *
     * @since   3.5
     */
    public function store()
    {
        // Send json mime type.
        $this->app->mimeType = 'application/json';
        $this->app->setHeader('Content-Type', $this->app->mimeType . '; charset=' . $this->app->charSet);
        $this->app->sendHeaders();

        // Check if user token is valid.
        if (!Session::checkToken('get')) {
            $this->app->enqueueMessage(Text::_('JINVALID_TOKEN'), 'error');
            echo new JsonResponse();
            $this->app->close();
        }

        /** @var \Joomla\Component\Config\Administrator\Model\ApplicationModel $model */
        $model = $this->getModel('Application', 'Administrator');
        echo new JsonResponse($model->storePermissions());
        $this->app->close();
    }
}
