<?php

/**
 * @package     Joomlab
 * @subpackage  com_jladmin
 * @copyright   Copyright (C) 2025 Open Source Matters, Inc. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

define('_JEXEC', 1);

session_start();
error_reporting(E_ALL);
ini_set('display_errors', 1);

use Joomla\CMS\Uri\Uri;
use Joomla\CMS\User\UserHelper;
use Joomla\Database\DatabaseDriver;
use Joomla\Database\DatabaseFactory;
use Joomla\Filesystem\File;
use Joomla\Filesystem\Folder;
use Joomla\Filesystem\Path;
use Joomla\Registry\Registry;

$dataSQLFile = __DIR__ . '/data.sql';

if (!is_file($dataSQLFile)) {
    throw new RuntimeException('SQL file not found: ' . $dataSQLFile);
}

$cwd = dirname(__DIR__);

require_once $cwd . '/includes/defines.php';
require_once $cwd . '/libraries/bootstrap.php';

$configFile = JPATH_CONFIGURATION . '/configuration.php';

if (!is_file($configFile)) {
    throw new RuntimeException('Configuration file not found: ' . $configFile);
}

ob_start();
require_once $configFile;
ob_end_clean();

$conf       = new JConfig();
$getSession = function ($key, $default = null) {
    return $_SESSION['JLAdminRestore'][$key] ?? $default;
};

$setSession = function ($key, $value) {
    if (!isset($_SESSION['JLAdminRestore'])) {
        $_SESSION['JLAdminRestore'] = [];
    }

    if (null === $value) {
        unset($_SESSION['JLAdminRestore'][$key]);
    } else {
        $_SESSION['JLAdminRestore'][$key] = $value;
    }
};

$clearSession = function () {
    unset($_SESSION['JLAdminRestore']);
};

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $dbHost     = trim($_POST['dbHost'] ?? '');
    $dbUser     = trim($_POST['dbUser'] ?? '');
    $dbPassword = trim($_POST['dbPassword'] ?? '');
    $dbName     = trim($_POST['dbName'] ?? '');
    $dbPrefix   = trim($_POST['dbPrefix'] ?? '');
    $cleanup    = (int)($_POST['cleanup'] ?? '0');
    $su         = trim($_POST['su'] ?? '');
    $suPwd      = trim($_POST['suPwd'] ?? '');
    $hasError   = false;

    $setSession('cleanup', $cleanup);
    foreach (['dbHost' => 'Host', 'dbUser' => 'User', 'dbPassword' => 'Password', 'dbName' => 'Database Name', 'dbPrefix' => 'Prefix'] as $key => $label) {
        $value = $$key;

        if (is_string($value)) {
            $setSession($key, $value);
        }

        if (!is_string($value) || empty($value)) {
            $setSession($key . 'Msg', $label . ' cannot be empty.');
            $hasError = true;
        } else {
            $setSession($key . 'Msg', null);

            if ('dbPrefix' === $key
                && (strlen($dbPrefix) < 6 || is_numeric($dbPrefix[0]) || !str_ends_with($dbPrefix, '_'))
            ) {
                $hasError = true;
                $setSession($key . 'Msg',
                    'The database prefix must be a string of at least 6 characters, starting with a letter and ending with an underscore (_). The string must also contain at least one numeric character.');
            }
        }
    }

    if (is_string($su) && !empty($su)) {
        $setSession('su', $su);

        if (strlen($su) < 4) {
            $hasError = true;
            $setSession('suMsg', 'Username must be at least 4 characters long.');
        } elseif (empty($suPwd)) {
            $hasError = true;
            $setSession('suPwdMsg', 'User password can\'t be empty.');
        }
    }

    if ($hasError) {
        header('location: ' . $_SERVER['REQUEST_URI']);
        exit;
    }

    $sysErrors = [];

    // Handle restore
    if (function_exists('ini_set') && function_exists('ini_get')) {
        ini_set('memory_limit', '-1');
        ini_set('output_buffering', 'off');
        ini_set('zlib.output_compression', 'Off');

        if (function_exists('set_time_limit')) {
            set_time_limit(0);
        }
    }

    try {
        $conf->host     = $dbHost;
        $conf->user     = $dbUser;
        $conf->password = $dbPassword;
        $conf->dbprefix = $dbPrefix;
        $conf->db       = $dbName;

        // Attempt to write the configuration file as a PHP class named JConfig.
        $configuration = (new Registry($conf))->toString('PHP', ['class' => 'JConfig', 'closingtag' => false]);

        // Write the config

        if ((Path::isOwner($configFile) && !Path::setPermissions($configFile, '0644')) || !File::write($configFile, $configuration)) {
            throw new RuntimeException('Cannot write to configuration file, permission denied!');
        }

        // Attempt to make the file unwriteable.
        if (Path::isOwner($configFile)) {
            Path::setPermissions($configFile, '0444');
        }

        $options = [
            'driver'   => $conf->dbtype,
            'host'     => $conf->host,
            'user'     => $conf->user,
            'password' => $conf->password,
            // 'database' => $conf->db,
            'prefix'   => $conf->dbprefix,
            'select'   => false,
        ];

        // Enable utf8mb4 connections for mysql adapters
        if (strtolower($options['driver']) === 'mysqli') {
            $options['utf8mb4'] = true;
        }

        if (strtolower($options['driver']) === 'mysql') {
            $options['charset'] = 'utf8mb4';
        }

        if (!empty($conf->dbencryption)) {
            $options['ssl'] = [
                'enable'             => true,
                'verify_server_cert' => (bool)$conf->dbsslverifyservercert,
            ];

            foreach (['cipher', 'ca', 'key', 'cert'] as $value) {
                $confVal = trim($conf->{'dbssl' . $value} ?? '');

                if ($confVal !== '') {
                    $options['ssl'][$value] = $confVal;
                }
            }
        }

        try {
            $dbFactory = new DatabaseFactory();
            $db        = $dbFactory->getDriver($options['driver'], $options);

            if ($cleanup) {
                $db->setQuery('DROP DATABASE IF EXISTS ' . $db->quoteName($conf->db))
                    ->execute();
            }

            $db->setQuery('CREATE DATABASE IF NOT EXISTS ' . $db->quoteName($conf->db))
                ->execute();
            $db->select($conf->db);
            $sqlData = array_merge(
                ['SET FOREIGN_KEY_CHECKS = 0;'],
                DatabaseDriver::splitSql(file_get_contents($dataSQLFile)),
                ['SET FOREIGN_KEY_CHECKS = 1;'],
            );

            foreach ($sqlData as $sql) {
                try {
                    $db->setQuery($sql)
                        ->execute();
                } catch (Throwable $e) {
                    throw new RuntimeException($e->getMessage() . ' SQL: ' . str_replace('#__', $options['prefix'], $sql));
                }
            }

            if ($su) {
                $query = $db->createQuery()
                    ->select('u.id')
                    ->from($db->quoteName('#__users', 'u'))
                    ->join('INNER', $db->quoteName('#__user_usergroup_map', 'u2'), 'u2.user_id = u.id')
                    ->where('u2.group_id = 8');

                if ($suId = $db->setQuery($query)->loadResult()) {
                    $query->clear()
                        ->update($db->quoteName('#__users'))
                        ->set($db->quoteName('username') . ' = :username')
                        ->set($db->quoteName('password') . ' = :password')
                        ->where($db->quoteName('id') . ' = :id')
                        ->bind(':username', $su)
                        ->bind(':password', UserHelper::hashPassword($suPwd))
                        ->bind(':id', $suId);
                    $db->setQuery($query)
                        ->execute();
                }
            }

            if (empty($sysErrors)) {
                $sysDirs = [
                    JPATH_ROOT . '/tmp',
                    JPATH_CACHE,
                    JPATH_ADMINISTRATOR . '/logs',
                ];

                foreach ($sysDirs as $sysDir) {
                    try {
                        if (is_dir($sysDir)) {
                            Folder::delete($sysDir);
                        }

                        Folder::create($sysDir);
                    } catch (Throwable $e) {
                    }
                }

                // Remove installation folder
                try {
                    Folder::delete(JPATH_INSTALLATION);
                    clearstatcache(true, JPATH_INSTALLATION . '/index.php');
                } catch (Throwable $e) {
                    $sysErrors[] = 'Can not remove the installation folder automatically. Please try to removing the installation folder manually';
                    $sysErrors[] = $e->getMessage();
                }

                $clearSession();
            }
        } catch (Throwable $e) {
            $sysErrors[] = $e->getMessage();
        }
    } catch (Throwable $e) {
        $sysErrors[] = $e->getMessage();
    }

    if ($sysErrors) {
        $setSession('sysErrors', array_unique($sysErrors));
    }

    header('location: ' . preg_replace('#/installation/?.*$#', '', preg_quote(Uri::root(true), '#')));
    exit;
}

$generatePrefix = function () {
    $randomArray               = str_split(bin2hex(random_bytes(3))); // 6 hex chars = 3 bytes
    $randomIndex               = array_rand($randomArray);
    $randomArray[$randomIndex] = '';
    $dbPrefix                  = implode('', $randomArray);

    if (!preg_match('/\d/', $dbPrefix)) {
        $randomIndex               = array_rand($randomArray);
        $randomArray[$randomIndex] = substr(str_shuffle('0123456789'), 0, 1);
        $dbPrefix                  = implode('', $randomArray);
    }

    return $dbPrefix;
};

$dbPrefix = $generatePrefix();

while (is_numeric($dbPrefix[0])) {
    $dbPrefix = $generatePrefix();
}

$dbTypeString = match ($conf->dbtype) {
    'mysql' => 'MySQL (PDO)',
    'mysqli' => 'MySQLi',
    default => ucfirst($conf->dbtype),
};

$dbEncryption = match ($conf->dbencryption) {
    1 => 'One-way authentication',
    2 => 'Two-way authentication',
    default => 'Default (server controlled)',
};

?>

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Restore for <?php echo $conf->sitename; ?></title>
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/uikit@3.23.7/dist/css/uikit.min.css"/>
        <script src="https://cdn.jsdelivr.net/npm/uikit@3.23.7/dist/js/uikit.min.js"></script>
        <script src="<?php echo Uri::root(true); ?>/../media/system/js/joomla-core-loader.js"></script>

    </head>
    <body style="background-color: #f0f4fb; min-height: 100vh">
    <div class="uk-container uk-container-small uk-card-body">
        <div class="uk-card uk-card-default uk-margin-large-top">
            <div class="uk-card-body">
                <h3>Database connection</h3>
                <div class="uk-text-meta">
                    <ul class="uk-list uk-list-disc">
                        <li>Restore for Joomla! site: <strong><?php echo $conf->sitename; ?></strong></li>
                        <li>Database type: <strong><?php echo $dbTypeString; ?></strong></li>
                        <li>Connection Encryption: <strong><?php echo $dbEncryption; ?></strong></li>
                    </ul>
                </div>
                <form method="post" action="<?php echo $_SERVER['REQUEST_URI']; ?>" class="uk-form-stacked" id="restore-form">
                    <?php if ($errors = $getSession('sysErrors', [])): ?>
                        <div class="uk-alert uk-alert-danger">
                            <?php echo implode('<br>', $errors); ?>
                        </div>
                    <?php endif; ?>
                    <div class="uk-margin">
                        <label class="uk-form-label" for="db-host">Host(*)</label>
                        <div class="uk-form-controls">
                            <input class="uk-input" id="db-host" name="dbHost" type="text" value="<?php echo $getSession('dbHost', 'localhost'); ?>">
                            <?php if ($dbHostMsg = $getSession('dbHostMsg')): ?>
                                <div class="uk-text-danger uk-text-small">
                                    <?php echo $dbHostMsg; ?>
                                </div>
                            <?php endif; ?>
                        </div>
                    </div>
                    <div class="uk-margin">
                        <label class="uk-form-label" for="db-user">User(*)</label>
                        <div class="uk-form-controls">
                            <input class="uk-input" id="db-user" name="dbUser" type="text" value="<?php echo $getSession('dbUser', ''); ?>">
                            <?php if ($dbUserMsg = $getSession('dbUserMsg')): ?>
                                <div class="uk-text-danger uk-text-small">
                                    <?php echo $dbUserMsg; ?>
                                </div>
                            <?php endif; ?>
                        </div>
                    </div>
                    <div class="uk-margin">
                        <label class="uk-form-label" for="db-password">Password(*)</label>
                        <div class="uk-form-controls">
                            <input class="uk-input" id="db-password" name="dbPassword" type="password" autocomplete="new-password" value="<?php echo $getSession('dbPassword', ''); ?>">
                            <?php if ($dbPasswordMsg = $getSession('dbPasswordMsg')): ?>
                                <div class="uk-text-danger uk-text-small">
                                    <?php echo $dbPasswordMsg; ?>
                                </div>
                            <?php endif; ?>
                        </div>
                    </div>
                    <div class="uk-margin">
                        <label class="uk-form-label" for="db-name">Database name(*)</label>
                        <div class="uk-form-controls">
                            <input class="uk-input" id="db-name" name="dbName" type="text" value="<?php echo $getSession('dbName', ''); ?>">
                            <?php if ($dbNameMsg = $getSession('dbNameMsg')): ?>
                                <div class="uk-text-danger uk-text-small">
                                    <?php echo $dbNameMsg; ?>
                                </div>
                            <?php endif; ?>
                        </div>
                    </div>
                    <div class="uk-margin">
                        <label class="uk-form-label" for="db-prefix">Database Tables Prefix(*)</label>
                        <div class="uk-form-controls">
                            <input class="uk-input" id="db-prefix" name="dbPrefix" type="text" value="<?php echo $getSession('dbPrefix', $dbPrefix . '_'); ?>">
                            <?php if ($dbPrefixMsg = $getSession('dbPrefixMsg')): ?>
                                <div class="uk-text-danger uk-text-small">
                                    <?php echo $dbPrefixMsg; ?>
                                </div>
                            <?php endif; ?>
                        </div>
                    </div>
                    <div class="uk-margin">
                        <label class="uk-form-label" for="db-prefix">Clean up the database before restoring?</label>
                        <div class="uk-form-controls">
                            <?php
                            $choices = ['No', 'Yes'];
                            $cleanup = $getSession('cleanup', 0);
                            ?>
                            <div>
                                <?php foreach ($choices as $i => $choice): ?>
                                    <label class="uk-margin-small-right">
                                        <input
                                                class="uk-radio"
                                                name="cleanup"
                                                type="radio"
                                                value="<?php echo $i; ?>"
                                            <?php echo $cleanup == $i ? ' checked' : ''; ?>
                                        >
                                        <?php echo $choice; ?>
                                    </label>
                                <?php endforeach; ?>
                            </div>
                            <div class="uk-text-meta">This will drop the current database and re-create a new one before restoring.</div>
                        </div>
                    </div>
                    <div class="uk-margin">
                        <label class="uk-form-label" for="su">New super username</label>
                        <div class="uk-form-controls">
                            <input class="uk-input" id="su" name="su" type="text" value="<?php echo $getSession('su', ''); ?>" placeholder="Default to current super user">
                            <?php if ($suMsg = $getSession('suMsg')): ?>
                                <div class="uk-text-small uk-text-danger"><?php echo $suMsg; ?></div>
                            <?php endif; ?>
                        </div>
                    </div>

                    <div class="uk-margin">
                        <label class="uk-form-label" for="su-pwd">New super password</label>
                        <div class="uk-form-controls">
                            <input class="uk-input" id="su-pwd" name="suPwd" type="password" value="<?php echo $getSession('suPwd', ''); ?>">
                            <?php if ($suPwdMsg = $getSession('suPwdMsg')): ?>
                                <div class="uk-text-danger uk-text-small">
                                    <?php echo $suPwdMsg; ?>
                                </div>
                            <?php endif; ?>
                        </div>
                    </div>

                    <div class="uk-alert">
                        Create a new super user. If provided, the system will overwrite the current super user in the database. Note that if you choose to create a new super user, you must also set a
                        new password.
                    </div>

                    <div class="uk-text-center">
                        <button class="uk-button uk-button-primary" id="btn-restore" type="submit">
                            Restore now
                        </button>
                    </div>
                </form>
            </div>
        </div>
    </div>
    <script>
        document.addEventListener('DOMContentLoaded', function () {
            document.getElementById('restore-form').addEventListener('submit', function (e) {
                const loader = document.createElement('joomla-core-loader');
                this.appendChild(loader);
            });
        });
    </script>
    </body>
    </html>

<?php

$setSession('sysErrors', null);

