<?php

declare(strict_types=1);

/**
 * Door registry (SPEC §11.8): enable/disable, ACS, ordering, remove
 * registration, a "scan" that registers any doors/ or data/doors/ folder
 * with a valid door.json, and per-door admin panels (§13.6) rendered
 * inside this page with an authenticated $doorAdmin context.
 */

require __DIR__ . '/_lib.php';
admin_require();
$db = atdt_db();

/** @return ?array<string, mixed> validated door.json for a registered dir */
function door_manifest(string $dir): ?array
{
    $path = \Atdt\DoorRunner::dirFor(basename($dir));
    return $path === null ? null : \Atdt\DoorRunner::manifest($path);
}


if (($_SERVER['REQUEST_METHOD'] ?? '') === 'POST' && !isset($_GET['panel'])) {
    $id = (int)($_POST['id'] ?? 0);
    $door = $id > 0 ? $db->one('SELECT * FROM doors WHERE id = ?', [$id]) : null;
    switch ((string)($_POST['action'] ?? '')) {
        case 'toggle':
            if ($door !== null) {
                $db->q('UPDATE doors SET enabled = ? WHERE id = ?', [(int)$door['enabled'] === 1 ? 0 : 1, $id]);
                admin_log(((int)$door['enabled'] === 1 ? 'Disabled' : 'Enabled') . " door {$door['slug']}");
            }
            admin_redirect('doors.php');

        case 'save':
            if ($door !== null) {
                $db->q(
                    'UPDATE doors SET title = ?, acs = ? WHERE id = ?',
                    [
                        mb_strimwidth(trim((string)($_POST['title'] ?? (string)$door['title'])), 0, 40),
                        trim((string)($_POST['acs'] ?? '')),
                        $id,
                    ]
                );
                admin_log("Edited door {$door['slug']}");
                flash_set('ok', "Door {$door['slug']} saved.");
            }
            admin_redirect('doors.php');

        case 'move':
            if ($door !== null) {
                $dirn = (string)($_POST['dir'] ?? '') === 'up' ? -1 : 1;
                $swap = $db->one(
                    'SELECT * FROM doors WHERE sort ' . ($dirn < 0 ? '<' : '>') . ' ?
                     ORDER BY sort ' . ($dirn < 0 ? 'DESC' : 'ASC') . ' LIMIT 1',
                    [(int)$door['sort']]
                );
                if ($swap !== null) {
                    $db->q('UPDATE doors SET sort = ? WHERE id = ?', [(int)$swap['sort'], $id]);
                    $db->q('UPDATE doors SET sort = ? WHERE id = ?', [(int)$door['sort'], (int)$swap['id']]);
                }
            }
            admin_redirect('doors.php');

        case 'unregister':
            if ($door !== null) {
                $slug = (string)$door['slug'];
                $withData = (string)($_POST['with_data'] ?? '') === '1';
                $db->q('DELETE FROM doors WHERE id = ?', [$id]);
                if ($withData) {
                    $dropped = \Atdt\DoorStore::purge($db, $slug);
                    admin_log("Removed door $slug AND its data ($dropped table(s))");
                    flash_set('ok', "Door $slug removed and its data deleted ($dropped table(s), settings, files). "
                        . 'It will re-install fresh on the next Scan unless you also delete its folder from the server.');
                } else {
                    admin_log("Removed door $slug (data kept)");
                    flash_set('ok', "Door $slug removed from the board. Its data is still stored - "
                        . 'a Scan re-registers it with everything intact. To wipe it instead, use '
                        . 'Remove + data from the edit drawer, or delete its folder from the server to keep it gone.');
                }
            }
            admin_redirect('doors.php');

        case 'scan':
            $found = 0;
            foreach (\Atdt\DoorRunner::scan() as $m) {
                $slug = (string)$m['slug'];
                if ($db->one('SELECT id FROM doors WHERE slug = ?', [$slug]) !== null) {
                    continue;
                }
                $db->insert('doors', [
                    'slug' => $slug,
                    'title' => mb_strimwidth((string)$m['title'], 0, 40),
                    'dir' => basename((string)$m['dir']),
                    'acs' => (string)($m['acs'] ?? ''),
                    'enabled' => 1,
                    'sort' => 1 + (int)$db->val('SELECT COALESCE(MAX(sort), 0) FROM doors'),
                    'installed_at' => now_utc(),
                ]);
                $found++;
            }
            admin_log("Scanned doors: registered $found new");
            flash_set('ok', $found === 0 ? 'Scan done. Nothing new in doors/ or data/doors/.'
                : "Scan done. Registered $found new door(s). Add them to a menu in Menus (a DOOR-action item).");
            admin_redirect('doors.php');
    }
    admin_redirect('doors.php');
}

// --- Per-door admin panel (§13.6): included with an authed context. --------
$panelSlug = strtolower(trim((string)($_GET['panel'] ?? '')));
if ($panelSlug !== '' && preg_match('/^[a-z0-9][a-z0-9_-]{1,31}$/', $panelSlug)) {
    $door = $db->one('SELECT * FROM doors WHERE slug = ?', [$panelSlug]);
    $dir = $door === null ? null : (\Atdt\DoorRunner::dirFor((string)$door['dir']) ?? \Atdt\DoorRunner::dirFor($panelSlug));
    $m = $dir === null ? null : \Atdt\DoorRunner::manifest($dir);
    if ($m !== null && !empty($m['admin']) && preg_match('/^[a-z0-9_.-]+\.php$/i', (string)$m['admin'])) {
        admin_page_start('Door: ' . (string)$door['title'], 'doors');
        echo '<p><a class="btn small secondary" href="doors.php">← All doors</a></p>';
        $doorAdmin = new \Atdt\DoorAdminContext(new \Atdt\DoorStore($db, $panelSlug), $panelSlug, $db, new \Atdt\Settings($db));
        $csrfField = csrf_field();
        try {
            (static function (string $__file, \Atdt\DoorAdminContext $doorAdmin, string $csrfField): void {
                include $__file;
            })($dir . '/' . (string)$m['admin'], $doorAdmin, $csrfField);
        } catch (\Throwable $e) {
            atdt_log_event('error', 'door:' . $panelSlug, 'admin panel failed: ' . $e->getMessage());
            echo '<div class="flash bad">The door\'s admin panel crashed: ' . h($e->getMessage()) . '</div>';
        }
        admin_page_end();
        exit;
    }
    flash_set('err', 'That door has no admin panel.');
    admin_redirect('doors.php');
}

$doors = $db->all('SELECT * FROM doors ORDER BY sort, id');
$edit = isset($_GET['edit']) ? $db->one('SELECT * FROM doors WHERE id = ?', [(int)$_GET['edit']]) : null;

admin_page_start('Doors', 'doors');
?>

<div class="cols">
<div>
  <div class="card">
    <table class="list">
      <tr><th></th><th>Door</th><th>Slug</th><th>ACS</th><th>Status</th><th>Manifest</th><th></th></tr>
      <?php if ($doors === []): ?><tr><td colspan="7" class="hint">No doors registered.</td></tr><?php endif; ?>
      <?php foreach ($doors as $i => $d): $m = door_manifest((string)$d['dir']); ?>
      <tr>
        <td class="nowrap">
          <form method="post" class="inline"><?= csrf_field() ?>
            <input type="hidden" name="action" value="move"><input type="hidden" name="id" value="<?= (int)$d['id'] ?>">
            <input type="hidden" name="dir" value="up">
            <button class="btn small secondary" <?= $i === 0 ? 'disabled' : '' ?>>↑</button></form>
          <form method="post" class="inline"><?= csrf_field() ?>
            <input type="hidden" name="action" value="move"><input type="hidden" name="id" value="<?= (int)$d['id'] ?>">
            <input type="hidden" name="dir" value="down">
            <button class="btn small secondary" <?= $i === count($doors) - 1 ? 'disabled' : '' ?>>↓</button></form>
        </td>
        <td><?= h((string)$d['title']) ?></td>
        <td><code><?= h((string)$d['slug']) ?></code></td>
        <td><code><?= h((string)$d['acs']) ?: '<span class="hint">open</span>' ?></code></td>
        <td><?= (int)$d['enabled'] === 1 ? '<span class="ok">enabled</span>' : '<span class="warn">disabled</span>' ?></td>
        <td class="hint">
          <?php if ($m === null): ?>
            folder missing (re-upload it)
          <?php else: ?>
            <?= h((string)($m['author'] ?? '')) ?><?= isset($m['version']) ? ' v' . h((string)$m['version']) : '' ?>
            <?php if (!empty($m['admin'])): ?> · <a href="doors.php?panel=<?= h((string)$d['slug']) ?>">admin panel</a><?php endif; ?>
          <?php endif; ?>
        </td>
        <td class="nowrap">
          <form method="post" class="inline"><?= csrf_field() ?>
            <input type="hidden" name="action" value="toggle"><input type="hidden" name="id" value="<?= (int)$d['id'] ?>">
            <button class="btn small secondary"><?= (int)$d['enabled'] === 1 ? 'Disable' : 'Enable' ?></button></form>
          <a href="doors.php?edit=<?= (int)$d['id'] ?>">edit</a>
          <form method="post" class="inline" onsubmit="return confirm('Remove <?= h((string)$d['slug']) ?> from the board? Its DATA IS KEPT (a Scan re-registers it whole). To delete the data too, open edit and use Remove + data.');">
            <?= csrf_field() ?>
            <input type="hidden" name="action" value="unregister"><input type="hidden" name="id" value="<?= (int)$d['id'] ?>">
            <button class="btn small danger">×</button></form>
        </td>
      </tr>
      <?php endforeach; ?>
    </table>
  </div>

  <form method="post">
    <?= csrf_field() ?>
    <input type="hidden" name="action" value="scan">
    <button class="btn secondary">Scan doors/ folder</button>
  </form>
  <p class="hint">Drop a door folder (with <code>door.json</code>) into <code>doors/</code>, then scan.
  Scanning only registers the door; no menu changes. To put it in front of callers, add a
  menu item on the Menus page with the <code>DOOR</code> action - every registered door is
  offered in the item's argument list automatically.</p>
</div>

<div>
  <?php if ($edit !== null): ?>
  <div class="card drawer">
    <h2>Edit: <?= h((string)$edit['slug']) ?></h2>
    <form method="post">
      <?= csrf_field() ?>
      <input type="hidden" name="action" value="save">
      <input type="hidden" name="id" value="<?= (int)$edit['id'] ?>">
      <label>Title <input type="text" name="title" maxlength="40" value="<?= h((string)$edit['title']) ?>"></label>
      <label>ACS <span class="hint">(blank = everyone)</span>
        <input type="text" name="acs" value="<?= h((string)$edit['acs']) ?>"></label>
      <button class="btn">Save door</button>
      <a class="btn secondary" href="doors.php">Close</a>
    </form>
    <hr>
    <h2>Remove this door</h2>
    <p class="hint">Removing takes it off the board either way. <strong>Keep data</strong> preserves
       every table, setting, and file the door stored - a Scan re-registers it exactly where it
       left off (that pair is also a clean way to fix a broken registration). <strong>Delete data</strong>
       wipes all of it - players, scores, galaxies, everything - which is the full reset: delete
       + Scan reboots the door from nothing. Either way the door <em>re-installs on the next Scan</em>
       unless you also delete its folder from <code>doors/</code> or <code>data/doors/</code> on the server.</p>
    <form method="post" onsubmit="return confirm(this.with_data.checked
        ? 'Remove <?= h((string)$edit['slug']) ?> and DELETE ALL ITS DATA? There is no undo.'
        : 'Remove <?= h((string)$edit['slug']) ?>? Its data is kept for a re-scan.');">
      <?= csrf_field() ?>
      <input type="hidden" name="action" value="unregister">
      <input type="hidden" name="id" value="<?= (int)$edit['id'] ?>">
      <label><input type="checkbox" name="with_data" value="1">
        Also delete its data (tables, settings, stored files) - no undo</label>
      <button class="btn danger">Remove door</button>
    </form>
  </div>
  <?php endif; ?>
</div>
</div>

<?php admin_page_end(); ?>
