<?php

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

namespace Joomla\Component\Installer\Administrator\Model;

use Exception;
use Joomla\CMS\Form\Form;
use Joomla\CMS\MVC\Model\AdminModel;
use Joomla\CMS\Object\CMSObject;
use Joomla\Component\Installer\Administrator\Helper\InstallerHelper;
use Joomla\Database\ParameterType;

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

/**
 * Item Model for an update site.
 *
 * @since  4.0.0
 */
class UpdatesiteModel extends AdminModel
{
    /**
     * The type alias for this content type.
     *
     * @var    string
     * @since  4.0.0
     */
    public $typeAlias = 'com_installer.updatesite';

    /**
     * Method to get the row form.
     *
     * @param   array    $data      Data for the form.
     * @param   boolean  $loadData  True if the form is to load its own data (default case), false if not.
     *
     * @return  Form|boolean  A Form object on success, false on failure
     *
     * @throws  Exception
     *
     * @since   4.0.0
     */
    public function getForm($data = [], $loadData = true)
    {
        // Get the form.
        $form = $this->loadForm('com_installer.updatesite', 'updatesite', ['control' => 'jform', 'load_data' => $loadData]);

        if (empty($form)) {
            return false;
        }

        return $form;
    }
    /**
     * Method to get the data that should be injected in the form.
     *
     * @return  mixed  The data for the form.
     *
     * @since   4.0.0
     */
    protected function loadFormData()
    {
        $data = $this->getItem();
        $this->preprocessData('com_installer.updatesite', $data);

        return $data;
    }

    /**
     * Method to get a single record.
     *
     * @param   integer  $pk  The id of the primary key.
     *
     * @return  CMSObject|boolean  Object on success, false on failure.
     *
     * @since   4.0.0
     */
    public function getItem($pk = null)
    {
        $item = parent::getItem($pk);

        $db           = $this->getDatabase();
        $updateSiteId = (int) $item->get('update_site_id');
        $query        = $db->getQuery(true)
            ->select(
                $db->quoteName(
                    [
                        'update_sites.extra_query',
                        'extensions.type',
                        'extensions.element',
                        'extensions.folder',
                        'extensions.client_id',
                        'extensions.checked_out'
                    ]
                )
            )
            ->from($db->quoteName('#__update_sites', 'update_sites'))
            ->join(
                'INNER',
                $db->quoteName('#__update_sites_extensions', 'update_sites_extensions'),
                $db->quoteName('update_sites_extensions.update_site_id') . ' = ' . $db->quoteName('update_sites.update_site_id')
            )
            ->join(
                'INNER',
                $db->quoteName('#__extensions', 'extensions'),
                $db->quoteName('extensions.extension_id') . ' = ' . $db->quoteName('update_sites_extensions.extension_id')
            )
            ->where($db->quoteName('update_sites.update_site_id') . ' = :updatesiteid')
            ->bind(':updatesiteid', $updateSiteId, ParameterType::INTEGER);

        $db->setQuery($query);
        $extension = new CMSObject($db->loadAssoc());

        $downloadKey = InstallerHelper::getDownloadKey($extension);

        $item->set('extra_query', $downloadKey['value'] ?? '');
        $item->set('downloadIdPrefix', $downloadKey['prefix'] ?? '');
        $item->set('downloadIdSuffix', $downloadKey['suffix'] ?? '');

        return $item;
    }

    /**
     * Method to save the form data.
     *
     * @param   array  $data  The form data.
     *
     * @return  boolean  True on success, False on error.
     *
     * @since   4.0.0
     */
    public function save($data): bool
    {
        // Apply the extra_query. Always empty when saving a free extension's update site.
        if (isset($data['extra_query'])) {
            $data['extra_query'] = $data['downloadIdPrefix'] . $data['extra_query'] . $data['downloadIdSuffix'];
        }

        // Force Joomla to recheck for updates
        $data['last_check_timestamp'] = 0;

        $result = parent::save($data);

        if (!$result) {
            return $result;
        }

        // Delete update records forcing Joomla to fetch them again, applying the new extra_query.
        $db = $this->getDatabase();
        $query = $db->getQuery(true)
            ->delete($db->quoteName('#__updates'))
            ->where($db->quoteName('update_site_id') . ' = :updateSiteId');
        $query->bind(':updateSiteId', $data['update_site_id'], ParameterType::INTEGER);

        try {
            $db->setQuery($query)->execute();
        } catch (Exception $e) {
            // No problem if this fails for any reason.
        }

        return true;
    }
}
