<?php
/**
 * Green Submissions — Web Installer
 * Submission Manager by Glenn Lyvers, provided freely through greensubmissions.com
 *
 * Walks a new site owner through:
 *   Step 1 — server requirements check
 *   Step 2 — database + site identity (writes ../config.php, imports schema.sql)
 *   Step 3 — first administrator account
 *   Done  — next steps, and a reminder to DELETE this /install folder.
 *
 * Safety: refuses to run once ../config.php exists, so it cannot be used to
 * clobber a live install. Delete the /install folder after installing anyway.
 */

declare(strict_types=1);
session_start();

$ROOT       = dirname(__DIR__);
$CONFIG     = $ROOT . '/config.php';
$SCHEMA     = __DIR__ . '/schema.sql';
$installed  = file_exists($CONFIG);
$step       = isset($_GET['step']) ? (string)$_GET['step'] : '1';
$errors     = [];
$out        = '';

if (empty($_SESSION['gs_csrf'])) {
    $_SESSION['gs_csrf'] = bin2hex(random_bytes(32));
}
function csrf_ok(): bool {
    return isset($_POST['csrf']) && hash_equals($_SESSION['gs_csrf'], (string)$_POST['csrf']);
}
function h($s): string {
    return htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8');
}

/* --------------------------------------------------------------------------
 * Requirements
 * ------------------------------------------------------------------------ */
function gs_requirements(string $ROOT): array {
    $reqs = [];
    $reqs[] = ['PHP 8.0 or newer', version_compare(PHP_VERSION, '8.0.0', '>='), 'You are running PHP ' . PHP_VERSION];
    $reqs[] = ['PDO MySQL extension (pdo_mysql)', extension_loaded('pdo_mysql'), 'Required for all database access'];
    $reqs[] = ['cURL extension', extension_loaded('curl'), 'Required for PayPal and Cloudflare Turnstile'];
    $reqs[] = ['GD extension', extension_loaded('gd'), 'Required for the built-in image captcha'];
    $reqs[] = ['Multibyte string extension (mbstring)', extension_loaded('mbstring'), 'Required for safe text handling'];
    $reqs[] = ['OpenSSL extension', extension_loaded('openssl'), 'Required for SMTP (SSL/TLS) email'];
    $reqs[] = ['App folder is writable (to create config.php)', is_writable($ROOT), $ROOT];
    $reqs[] = ['attachments/ folder is writable', is_writable($ROOT . '/attachments'), 'Uploaded submissions are stored here'];
    $reqs[] = ['guidelines_content.html is writable', is_writable($ROOT . '/guidelines_content.html'), 'So admins can edit guidelines from the Editorial Suite'];
    return $reqs;
}
$requirements = gs_requirements($ROOT);
$reqs_ok = !in_array(false, array_column($requirements, 1), true);

/* --------------------------------------------------------------------------
 * Step 2 submit: database + site identity
 * ------------------------------------------------------------------------ */
if (!$installed && $_SERVER['REQUEST_METHOD'] === 'POST' && $step === '2') {
    if (!csrf_ok()) {
        $errors[] = 'Invalid request token. Please try again.';
    } else {
        $dbhost = trim((string)($_POST['dbhost'] ?? 'localhost'));
        $dbname = trim((string)($_POST['dbname'] ?? ''));
        $dbuser = trim((string)($_POST['dbuser'] ?? ''));
        $dbpass = (string)($_POST['dbpass'] ?? '');
        $sname  = trim((string)($_POST['site_name'] ?? ''));
        $surl   = rtrim(trim((string)($_POST['site_url'] ?? '')), '/');
        $shome  = rtrim(trim((string)($_POST['site_home'] ?? '')), '/');
        $stag   = trim((string)($_POST['site_tagline'] ?? ''));
        $tskey  = trim((string)($_POST['ts_sitekey'] ?? ''));
        $tssec  = trim((string)($_POST['ts_secret'] ?? ''));

        if ($dbname === '' || $dbuser === '') $errors[] = 'Database name and user are required.';
        if ($sname === '')                    $errors[] = 'Site name is required.';
        if ($surl === '' || !preg_match('~^https?://~i', $surl)) $errors[] = 'Site URL must start with http:// or https://';
        if ($shome === '') $shome = $surl;
        if (($tskey === '') !== ($tssec === '')) $errors[] = 'Enter BOTH Turnstile keys, or leave both blank.';

        // Try the database connection.
        $pdo = null;
        if (!$errors) {
            try {
                $pdo = new PDO("mysql:host=$dbhost;dbname=$dbname;charset=utf8mb4", $dbuser, $dbpass);
                $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            } catch (PDOException $e) {
                $errors[] = 'Could not connect to the database: ' . h($e->getMessage());
            }
        }

        // Import the schema.
        if (!$errors && $pdo) {
            try {
                $sql = (string)file_get_contents($SCHEMA);
                if ($sql === '') throw new RuntimeException('schema.sql is missing or empty.');
                // Strip "--" comment lines, then run each ;-terminated statement.
                $sql = preg_replace('/^\s*--.*$/m', '', $sql);
                foreach (array_filter(array_map('trim', preg_split('/;\s*\n/', $sql))) as $statement) {
                    if ($statement === '') continue;
                    $pdo->exec($statement);
                }
            } catch (Throwable $e) {
                $errors[] = 'Schema import failed: ' . h($e->getMessage());
            }
        }

        // Write config.php.
        if (!$errors) {
            $esc = static fn(string $v): string => str_replace(["\\", "'"], ["\\\\", "\\'"], $v);
            $cfg = "<?php\n"
                . "/* Green Submissions configuration — generated by the installer on " . date('Y-m-d H:i') . ".\n"
                . " * Submission Manager by Glenn Lyvers, provided freely through greensubmissions.com */\n\n"
                . "define('DBHOST', '" . $esc($dbhost) . "');\n"
                . "define('DBUSER', '" . $esc($dbuser) . "');\n"
                . "define('DBPASS', '" . $esc($dbpass) . "');\n"
                . "define('DBNAME', '" . $esc($dbname) . "');\n\n"
                . "try {\n"
                . "    \$pdo = new PDO(\"mysql:host=\" . DBHOST . \";dbname=\" . DBNAME . \";charset=utf8mb4\", DBUSER, DBPASS);\n"
                . "    \$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);\n"
                . "} catch (PDOException \$e) {\n"
                . "    error_log('DB connection failed (config.php): ' . \$e->getMessage());\n"
                . "    http_response_code(503);\n"
                . "    die(\"The site is temporarily unavailable. Please try again shortly.\");\n"
                . "}\n\n"
                . "\$site_url      = '" . $esc($surl) . "';\n"
                . "\$site_name     = '" . $esc($sname) . "';\n"
                . "\$site_home_url = '" . $esc($shome) . "';\n"
                . "\$site_tagline  = '" . $esc($stag) . "';\n\n"
                . "// Cloudflare Turnstile (optional). Blank = built-in image captcha.\n"
                . "define('TURNSTILE_SITEKEY', '" . $esc($tskey) . "');\n"
                . "define('TURNSTILE_SECRET', '" . $esc($tssec) . "');\n";
            if (@file_put_contents($CONFIG, $cfg) === false) {
                $errors[] = 'Could not write config.php. Create it by hand from config-sample.php with these values, then continue to step 3.';
            } else {
                @chmod($CONFIG, 0644);
                header('Location: index.php?step=3');
                exit;
            }
        }
    }
}

/* --------------------------------------------------------------------------
 * Step 3 submit: first administrator
 * ------------------------------------------------------------------------ */
$admin_done = false;
if ($_SERVER['REQUEST_METHOD'] === 'POST' && $step === '3') {
    if (!csrf_ok()) {
        $errors[] = 'Invalid request token. Please try again.';
    } elseif (!file_exists($CONFIG)) {
        $errors[] = 'config.php not found — complete step 2 first.';
    } else {
        require $CONFIG; // provides $pdo
        $fn = trim((string)($_POST['first_name'] ?? ''));
        $ln = trim((string)($_POST['last_name'] ?? ''));
        $em = trim((string)($_POST['email'] ?? ''));
        $pw = (string)($_POST['password'] ?? '');
        $p2 = (string)($_POST['password2'] ?? '');

        if ($fn === '' || $ln === '') $errors[] = 'First and last name are required.';
        if (!filter_var($em, FILTER_VALIDATE_EMAIL)) $errors[] = 'A valid email address is required.';
        if (strlen($pw) < 8 || !preg_match('/[A-Z]/', $pw) || !preg_match('/[a-z]/', $pw) || !preg_match('/[0-9]/', $pw)) {
            $errors[] = 'Password must be at least 8 characters with upper- and lowercase letters and a number.';
        }
        if ($pw !== $p2) $errors[] = 'The passwords do not match.';

        if (!$errors) {
            try {
                // Only ever create the FIRST account this way.
                $count = (int)$pdo->query('SELECT COUNT(*) FROM sm_editors')->fetchColumn();
                if ($count > 0) {
                    $errors[] = 'A staff account already exists. Log in to the Editorial Suite to add more staff.';
                } else {
                    $ins = $pdo->prepare("INSERT INTO sm_editors
                        (first_name, last_name, email, password, user_type, date_added, phone, address)
                        VALUES (:fn, :ln, :em, :pw, 'superadmin', NOW(), '', '')");
                    $ins->execute([
                        ':fn' => $fn, ':ln' => $ln, ':em' => $em,
                        ':pw' => password_hash($pw, PASSWORD_DEFAULT),
                    ]);
                    $admin_done = true;
                }
            } catch (Throwable $e) {
                $errors[] = 'Could not create the account: ' . h($e->getMessage());
            }
        }
    }
    if ($admin_done) {
        header('Location: index.php?step=done');
        exit;
    }
}
?><!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Green Submissions · Installer</title>
<style>
  :root { --ink:#1d2b23; --green:#2e6b45; --green-deep:#1f4c31; --paper:#f6f5ef; --rule:#d9d5c8; --err:#a33; }
  * { box-sizing: border-box; }
  body { margin:0; font-family: Georgia, 'Times New Roman', serif; background: var(--paper); color: var(--ink); }
  header.bar { background: var(--green-deep); color: #f2efe4; padding: 26px 20px; text-align: center; }
  header.bar h1 { margin:0; font-weight: 400; letter-spacing: 1px; font-size: 26px; }
  header.bar .sub { font-size: 13px; opacity: .85; margin-top: 6px; font-style: italic; }
  .wrap { max-width: 720px; margin: 32px auto 64px; padding: 0 20px; }
  .steps { display:flex; gap:8px; margin: 0 0 24px; font-family: Verdana, sans-serif; font-size: 11px; letter-spacing: .08em; text-transform: uppercase; }
  .steps span { flex:1; text-align:center; padding: 8px 4px; background:#e8e5d8; border-radius: 3px; color:#777; }
  .steps span.on { background: var(--green); color:#fff; }
  .card { background:#fff; border:1px solid var(--rule); border-top: 3px solid var(--green); padding: 26px 30px; box-shadow: 0 10px 24px -18px rgba(0,0,0,.25); }
  h2 { margin: 0 0 14px; font-weight: 400; }
  table.req { width:100%; border-collapse: collapse; font-size: 15px; }
  table.req td { padding: 8px 6px; border-bottom: 1px solid #eee; }
  .ok  { color: #2e6b45; font-weight: bold; }
  .bad { color: var(--err); font-weight: bold; }
  label { display:block; font-family: Verdana, sans-serif; font-size: 11px; letter-spacing: .08em; text-transform: uppercase; color:#555; margin: 14px 0 4px; }
  input[type=text], input[type=password], input[type=email] { width:100%; padding: 9px 10px; border:1px solid #c9c3b8; border-radius:3px; font-family: Georgia, serif; font-size: 15px; background:#fdfcf9; }
  .hint { font-size: 12.5px; color:#777; font-style: italic; margin: 3px 0 0; }
  .btn { display:inline-block; margin-top: 22px; padding: 11px 28px; background: var(--green); color:#fff; border:0; border-radius:3px; font-family: Verdana, sans-serif; font-size: 13px; letter-spacing:.06em; cursor:pointer; text-decoration: none; }
  .btn:hover { background: var(--green-deep); }
  .errs { background:#fbeaea; border:1px solid #e0b4b4; border-left: 3px solid var(--err); padding: 12px 16px; margin: 0 0 18px; font-size: 14.5px; }
  .note { background:#eef3ec; border:1px solid #cfdccb; border-left:3px solid var(--green); padding: 12px 16px; margin: 18px 0 0; font-size: 14px; }
  .warn { background:#fdf4e2; border:1px solid #e8d3a0; border-left:3px solid #b08542; padding: 12px 16px; margin: 18px 0 0; font-size: 14px; }
  footer { text-align:center; font-size: 12.5px; color:#888; margin: 40px 0 24px; }
  footer a { color: var(--green-deep); }
  code { background:#f0ede2; padding: 1px 5px; border-radius:2px; font-size: 13px; }
</style>
</head>
<body>
<header class="bar">
  <h1>Green Submissions</h1>
  <div class="sub">Submission Manager by Glenn Lyvers · greensubmissions.com</div>
</header>
<div class="wrap">

<?php if ($installed && $step !== '3' && $step !== 'done'): ?>
  <div class="card">
    <h2>Already installed</h2>
    <p>A <code>config.php</code> already exists, so the installer has been disabled to protect your live site.</p>
    <p>If staff accounts haven't been created yet, you may still <a href="index.php?step=3">create the first administrator</a>.</p>
    <p>To re-install from scratch: delete <code>config.php</code>, drop the database tables, and reload this page.</p>
    <div class="warn"><b>Important:</b> when you're done, delete the entire <code>/install</code> folder from your server.</div>
  </div>

<?php elseif ($step === '1'): ?>
  <div class="steps"><span class="on">1 · Requirements</span><span>2 · Database &amp; Site</span><span>3 · Administrator</span><span>Finish</span></div>
  <div class="card">
    <h2>Server requirements</h2>
    <table class="req">
      <?php foreach ($requirements as [$label, $pass, $hint]): ?>
        <tr>
          <td><?= h($label) ?><div class="hint"><?= h($hint) ?></div></td>
          <td style="text-align:right;" class="<?= $pass ? 'ok' : 'bad' ?>"><?= $pass ? '✓ OK' : '✗ FAILED' ?></td>
        </tr>
      <?php endforeach; ?>
    </table>
    <?php if ($reqs_ok): ?>
      <a class="btn" href="index.php?step=2">Continue →</a>
    <?php else: ?>
      <div class="warn">Fix the failed items above, then reload this page. On shared hosting, PHP extensions can usually be enabled in cPanel under <b>Select PHP Version</b>. Folder permissions of <code>755</code> (or <code>775</code>) normally suffice.</div>
    <?php endif; ?>
  </div>

<?php elseif ($step === '2'): ?>
  <div class="steps"><span>1 · Requirements</span><span class="on">2 · Database &amp; Site</span><span>3 · Administrator</span><span>Finish</span></div>
  <div class="card">
    <h2>Database &amp; site identity</h2>
    <?php if ($errors): ?><div class="errs"><?= implode('<br>', $errors) ?></div><?php endif; ?>
    <form method="post" action="index.php?step=2" autocomplete="off">
      <input type="hidden" name="csrf" value="<?= h($_SESSION['gs_csrf']) ?>">

      <label>MySQL host</label>
      <input type="text" name="dbhost" value="<?= h($_POST['dbhost'] ?? 'localhost') ?>">
      <p class="hint">Almost always <code>localhost</code> on shared hosting.</p>

      <label>Database name</label>
      <input type="text" name="dbname" value="<?= h($_POST['dbname'] ?? '') ?>" required>

      <label>Database user</label>
      <input type="text" name="dbuser" value="<?= h($_POST['dbuser'] ?? '') ?>" required>

      <label>Database password</label>
      <input type="password" name="dbpass" value="">

      <hr style="border:0; border-top:1px solid var(--rule); margin:26px 0 6px;">

      <label>Journal / press name</label>
      <input type="text" name="site_name" value="<?= h($_POST['site_name'] ?? '') ?>" placeholder="e.g. The Riverbank Review" required>

      <label>URL of this app</label>
      <input type="text" name="site_url" value="<?= h($_POST['site_url'] ?? ('https://' . ($_SERVER['HTTP_HOST'] ?? 'example.com') . rtrim(dirname(dirname($_SERVER['REQUEST_URI'] ?? '/')), '/\\'))) ?>" required>
      <p class="hint">The folder this software lives in, no trailing slash. Used in emails and PayPal return links.</p>

      <label>Your main website (masthead link)</label>
      <input type="text" name="site_home" value="<?= h($_POST['site_home'] ?? '') ?>" placeholder="Leave blank to use the app URL">

      <label>Tagline (optional)</label>
      <input type="text" name="site_tagline" value="<?= h($_POST['site_tagline'] ?? '') ?>" placeholder="e.g. A Literary Journal · Established 2020">

      <hr style="border:0; border-top:1px solid var(--rule); margin:26px 0 6px;">

      <label>Cloudflare Turnstile site key (optional)</label>
      <input type="text" name="ts_sitekey" value="<?= h($_POST['ts_sitekey'] ?? '') ?>">
      <label>Cloudflare Turnstile secret key (optional)</label>
      <input type="text" name="ts_secret" value="<?= h($_POST['ts_secret'] ?? '') ?>">
      <p class="hint">Free bot protection — get keys at dash.cloudflare.com → Turnstile. Leave blank to use the built-in image captcha.</p>

      <button class="btn" type="submit">Install database &amp; write config →</button>
    </form>
  </div>

<?php elseif ($step === '3'): ?>
  <div class="steps"><span>1 · Requirements</span><span>2 · Database &amp; Site</span><span class="on">3 · Administrator</span><span>Finish</span></div>
  <div class="card">
    <h2>Create the first administrator</h2>
    <p>This account gets the <b>Super Administrator</b> role: full access to the Editorial Suite, including staff management.</p>
    <?php if ($errors): ?><div class="errs"><?= implode('<br>', $errors) ?></div><?php endif; ?>
    <form method="post" action="index.php?step=3" autocomplete="off">
      <input type="hidden" name="csrf" value="<?= h($_SESSION['gs_csrf']) ?>">
      <label>First name</label>
      <input type="text" name="first_name" value="<?= h($_POST['first_name'] ?? '') ?>" required>
      <label>Last name</label>
      <input type="text" name="last_name" value="<?= h($_POST['last_name'] ?? '') ?>" required>
      <label>Email (this is your login)</label>
      <input type="email" name="email" value="<?= h($_POST['email'] ?? '') ?>" required>
      <label>Password</label>
      <input type="password" name="password" required>
      <p class="hint">At least 8 characters, with upper- and lowercase letters and a number.</p>
      <label>Repeat password</label>
      <input type="password" name="password2" required>
      <button class="btn" type="submit">Create administrator →</button>
    </form>
  </div>

<?php elseif ($step === 'done'): ?>
  <div class="steps"><span>1 · Requirements</span><span>2 · Database &amp; Site</span><span>3 · Administrator</span><span class="on">Finish</span></div>
  <div class="card">
    <h2>Installation complete 🎉</h2>
    <p>Green Submissions is installed and ready.</p>
    <div class="warn"><b>Do this now:</b> delete the <code>/install</code> folder from your server. Anyone who can reach it can see your setup details.</div>
    <div class="note">
      <b>Next steps, in order:</b>
      <ol style="margin:8px 0 0 18px; padding:0; line-height:1.7;">
        <li>Log in to the <b>Editorial Suite</b> at <code>/editors/login.php</code>.</li>
        <li>Open <b>SMTP</b> and enter your outgoing-mail settings — signup confirmations and password resets need them.</li>
        <li>Open <b>Editions</b> and create your first edition, then mark it <i>Open for Submissions</i>.</li>
        <li>Open <b>Guidelines</b> and replace the placeholder guidelines with your own.</li>
        <li>Optional: enable PayPal for contest fees on the <b>PayPal</b> page (or in <code>paypal_config.php</code>).</li>
        <li>Full documentation (install, writer guide, editor guide): <a href="https://greensubmissions.com/docs/" target="_blank" rel="noopener">greensubmissions.com/docs/</a>.</li>
      </ol>
    </div>
    <p style="margin-top:20px;">
      <a class="btn" href="../index.php">Open your submission site →</a>
      &nbsp;
      <a class="btn" style="background:#5a5a4d;" href="../editors/login.php">Editorial Suite login →</a>
    </p>
  </div>
<?php endif; ?>

<footer>
  <em>Submission Manager</em> by Glenn Lyvers, provided freely through <a href="https://greensubmissions.com" target="_blank" rel="noopener">greensubmissions.com</a><br>
  Fast, affordable hosting that runs this software beautifully: <a href="https://instantaccess.net" target="_blank" rel="noopener">instantaccess.net</a>
</footer>
</div>
</body>
</html>
