<?php
if (!isset($registry)) $registry = ['view'=>[], 'edit'=>[], 'filter'=>[], 'validation'=>[]];
if (!isset($baseUrl)) $baseUrl = '';
if (!isset($assetsUrl)) $assetsUrl = rtrim($baseUrl, '/') . '/assets';
if (!isset($user)) $user = [];
if (!isset($isOwner)) $isOwner = false;
$error = $_SESSION['plugin_error'] ?? '';
$success = $_SESSION['plugin_success'] ?? '';
unset($_SESSION['plugin_error'], $_SESSION['plugin_success']);

$iconMap = [
    'PlainText'=>'bi-type','ShortDate'=>'bi-calendar3','MediumDate'=>'bi-calendar3','LongDate'=>'bi-calendar3',
    'Currency'=>'bi-currency-dollar','Percent'=>'bi-percent','Hyperlink'=>'bi-link-45deg','EmailHyperlink'=>'bi-envelope',
    'Image'=>'bi-image','File'=>'bi-file-earmark','Number'=>'bi-hash','PhoneNumber'=>'bi-telephone','HTML'=>'bi-file-code',
    'QRCode'=>'bi-qr-code','Custom'=>'bi-braces','Audio'=>'bi-volume-up','Video'=>'bi-camera-video','Badge'=>'bi-tag',
    'TextBox'=>'bi-input-cursor-text','TextArea'=>'bi-textarea','Password'=>'bi-lock','DatePicker'=>'bi-calendar-date',
    'TimePicker'=>'bi-clock','Checkbox'=>'bi-check-square','FileImage'=>'bi-upload','LookupWizard'=>'bi-search',
    'ReadOnlyControl'=>'bi-eye','Switch'=>'bi-toggle-on','StarRating'=>'bi-star','ButtonToggle'=>'bi-ui-radios',
    'RadioGroup'=>'bi-ui-radios','Dropdown'=>'bi-menu-button-wide','NepaliDatePicker'=>'bi-calendar-heart',
    'TextFilter'=>'bi-funnel','DateRange'=>'bi-calendar-range','SelectFilter'=>'bi-filter-circle','NumberRange'=>'bi-filter',
    'DropdownFilter'=>'bi-filter-square',
    // validation
    'email'=>'bi-envelope-check','fullName'=>'bi-person-badge','phone'=>'bi-telephone','required'=>'bi-asterisk',
    'regex'=>'bi-slash-square','number'=>'bi-123','length'=>'bi-rulers','url'=>'bi-globe','alpha'=>'bi-alphabet',
    'alphanumeric'=>'bi-fonts','dateValid'=>'bi-calendar-check','timeValid'=>'bi-clock-history','unique'=>'bi-fingerprint',
    'inList'=>'bi-list-check','compare'=>'bi-arrow-left-right','different'=>'bi-shuffle','match'=>'bi-check2-all',
    'mustAccept'=>'bi-check-circle','passwordStrength'=>'bi-shield-lock','creditCard'=>'bi-credit-card','ipAddress'=>'bi-hdd-network',
];

// ── Categories (Validation is now first-class) ────────────────────────────
$categories = [
    'view'       => ['title'=>'View',       'icon'=>'bi-eye',           'desc'=>'Display renderers'],
    'edit'       => ['title'=>'Edit',       'icon'=>'bi-pencil-square', 'desc'=>'Input controls'],
    'filter'     => ['title'=>'Filter',     'icon'=>'bi-funnel',        'desc'=>'List search widgets'],
    'validation' => ['title'=>'Validation', 'icon'=>'bi-shield-check',  'desc'=>'Field rules'],
];

// ── Build a flat, normalised plugin list + live stats ─────────────────────
$all = [];
$stats = ['total'=>0, 'enabled'=>0, 'disabled'=>0, 'core'=>0, 'custom'=>0];
foreach ($categories as $catKey => $catInfo) {
    $cat = ucfirst($catKey);
    foreach (($registry[$catKey] ?? []) as $id => $p) {
        $disabled  = file_exists(($p['path'] ?? '') . '/.disabled');
        $isCore    = \PpPhp\Core\PluginOwnership::isCore($cat, $id);
        $canManage = \PpPhp\Core\PluginOwnership::canManage($cat, $id);
        $ownerName = \PpPhp\Core\PluginOwnership::ownerLabel($cat, $id);
        // Validation rules describe options via params; the rest via settings.
        $options   = $catKey === 'validation' ? ($p['params'] ?? []) : ($p['settings'] ?? []);
        $all[] = [
            'id'=>$id, 'label'=>$p['label'] ?? $id, 'catKey'=>$catKey, 'cat'=>$cat,
            'icon'=>$iconMap[$id] ?? $catInfo['icon'], 'version'=>$p['version'] ?? '',
            'description'=>$p['description'] ?? '', 'docsUrl'=>$p['docsUrl'] ?? '',
            'disabled'=>$disabled, 'isCore'=>$isCore, 'canManage'=>$canManage, 'owner'=>$ownerName,
            'options'=>array_values($options), 'vendor'=>array_values($p['vendor'] ?? []),
            'assets'=>$p['assets'] ?? ['js'=>[],'css'=>[]],
            'group'=>$p['group'] ?? '', 'applies'=>$p['applies'] ?? [], 'message'=>$p['message'] ?? '',
        ];
        $stats['total']++;
        $stats[$disabled ? 'disabled' : 'enabled']++;
        $stats[$isCore ? 'core' : 'custom']++;
    }
}
// Stable, friendly order: category, then label.
usort($all, fn($a, $b) => [array_search($a['catKey'], array_keys($categories)), strtolower($a['label'])]
                       <=> [array_search($b['catKey'], array_keys($categories)), strtolower($b['label'])]);
$catCounts = array_fill_keys(array_keys($categories), 0);
foreach ($all as $pl) $catCounts[$pl['catKey']]++;
?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
    <title><?= htmlspecialchars(\PpPhp\Core\Brand::name()) ?> · Plugin Manager</title>
    <link href="<?= $assetsUrl ?>/bootstrap/css/bootstrap.min.css" rel="stylesheet">
    <link href="<?= $assetsUrl ?>/icons/bootstrap-icons.css" rel="stylesheet">
    <?php include constant('BASE_PATH') . '/core/views/theme-head.php'; ?>
    <link href="<?= $assetsUrl ?>/sweetalert2/sweetalert2.min.css" rel="stylesheet">
    <?= \PpPhp\Core\ModuleAssets::style('PluginManager', 'Views/plugin-manager-theme.css') ?>
</head>
<body class="plugin-manager-page">
<nav class="navbar navbar-manager navbar-dark px-3 shadow-sm">
    <a class="navbar-brand plugin-manager-back" href="<?= $baseUrl ?>/projects"><i class="bi bi-arrow-left me-2"></i>Back to Projects</a>
    <span class="plugin-manager-navbar-title">Plugin Manager</span>
    <div class="pm-nav-right">
        <a class="pm-guide-link" href="<?= $baseUrl ?>/plugin-manager/guide"><i class="bi bi-journal-code me-1"></i><span class="d-none d-sm-inline">Developer Guide</span></a>
        <?php include constant('BASE_PATH') . '/core/views/theme-toggle.php'; ?>
    </div>
</nav>

<div class="container plugin-manager-content py-4">

    <!-- ── Hero ─────────────────────────────────────────────────────── -->
    <header class="pm-hero mb-3">
        <div class="pm-hero-aurora" aria-hidden="true"><span></span><span></span><span></span></div>
        <div class="pm-hero-main">
            <span class="pm-hero-icon"><i class="bi bi-puzzle"></i></span>
            <div>
                <p class="pm-eyebrow mb-1">EXTEND YOUR BUILDER</p>
                <h1 class="pm-hero-title mb-1">Plugin Manager</h1>
                <p class="pm-hero-sub mb-0">Install, configure and manage the display, input, filter and validation controls that power your apps.</p>
            </div>
        </div>
        <div class="pm-hero-actions">
            <a href="<?= $baseUrl ?>/plugin-manager/guide" class="btn pm-btn-ghost"><i class="bi bi-journal-code me-1"></i>Developer Guide</a>
            <button type="button" class="btn pm-btn-accent" data-bs-toggle="collapse" data-bs-target="#installPanel"><i class="bi bi-plus-lg me-1"></i>Install Plugin</button>
        </div>
    </header>

    <!-- ── Stats ────────────────────────────────────────────────────── -->
    <div class="pm-stats mb-3">
        <div class="pm-stat"><span class="pm-stat-num"><?= $stats['total'] ?></span><span class="pm-stat-lbl"><i class="bi bi-puzzle"></i>Total</span></div>
        <div class="pm-stat is-ok"><span class="pm-stat-num"><?= $stats['enabled'] ?></span><span class="pm-stat-lbl"><i class="bi bi-check-circle"></i>Enabled</span></div>
        <div class="pm-stat is-off"><span class="pm-stat-num"><?= $stats['disabled'] ?></span><span class="pm-stat-lbl"><i class="bi bi-pause-circle"></i>Disabled</span></div>
        <div class="pm-stat is-core"><span class="pm-stat-num"><?= $stats['core'] ?></span><span class="pm-stat-lbl"><i class="bi bi-shield-lock"></i>Core</span></div>
        <div class="pm-stat is-custom"><span class="pm-stat-num"><?= $stats['custom'] ?></span><span class="pm-stat-lbl"><i class="bi bi-person-gear"></i>Custom</span></div>
    </div>

    <?php if ($error): ?>
        <div class="alert alert-danger alert-dismissible fade show"><i class="bi bi-exclamation-octagon me-2"></i><?= htmlspecialchars($error) ?><button type="button" class="btn-close" data-bs-dismiss="alert"></button></div>
    <?php endif; ?>
    <?php if ($success): ?>
        <div class="alert alert-success alert-dismissible fade show"><i class="bi bi-check-circle me-2"></i><?= htmlspecialchars($success) ?><button type="button" class="btn-close" data-bs-dismiss="alert"></button></div>
    <?php endif; ?>

    <!-- ── Install panel (collapsible) ──────────────────────────────── -->
    <div class="collapse mb-3" id="installPanel">
        <div class="pm-install">
            <div class="pm-install-head">
                <span><i class="bi bi-cloud-upload"></i></span>
                <div>
                    <h2 class="h6 mb-1">Install a new plugin</h2>
                    <p class="mb-0">Pick the control family and upload a validated <code>.zip</code>. The package is staged and verified before anything goes live.</p>
                </div>
            </div>
            <form method="post" action="<?= $baseUrl ?>/plugin-manager/upload" enctype="multipart/form-data" class="pm-install-form">
                <select name="category" class="form-select form-select-sm">
                    <option value="View">View</option>
                    <option value="Edit">Edit</option>
                    <option value="Filter">Filter</option>
                    <option value="Validation">Validation</option>
                </select>
                <input type="file" name="plugin_zip" class="form-control form-control-sm" accept=".zip" required>
                <button type="submit" class="btn btn-sm pm-btn-accent"><i class="bi bi-upload me-1"></i>Install</button>
            </form>
        </div>
    </div>

    <!-- ── Toolbar: search + filters ────────────────────────────────── -->
    <div class="pm-toolbar mb-3">
        <div class="pm-search">
            <i class="bi bi-search"></i>
            <input type="text" id="pmSearch" placeholder="Search plugins by name or id…" autocomplete="off">
            <button type="button" id="pmSearchClear" class="pm-search-clear" title="Clear" hidden><i class="bi bi-x-lg"></i></button>
        </div>
        <div class="pm-filters" role="group" aria-label="Filter by family">
            <button type="button" class="pm-pill active" data-filter="cat" data-value="all">All <span class="pm-pill-n"><?= $stats['total'] ?></span></button>
            <?php foreach ($categories as $ck => $ci): ?>
                <button type="button" class="pm-pill" data-filter="cat" data-value="<?= $ck ?>"><i class="bi <?= $ci['icon'] ?>"></i><?= $ci['title'] ?> <span class="pm-pill-n"><?= $catCounts[$ck] ?></span></button>
            <?php endforeach; ?>
        </div>
        <div class="pm-filters pm-filters-status" role="group" aria-label="Filter by status">
            <button type="button" class="pm-pill sm active" data-filter="status" data-value="all">Any</button>
            <button type="button" class="pm-pill sm" data-filter="status" data-value="enabled">Enabled</button>
            <button type="button" class="pm-pill sm" data-filter="status" data-value="disabled">Disabled</button>
            <button type="button" class="pm-pill sm" data-filter="status" data-value="core">Core</button>
            <button type="button" class="pm-pill sm" data-filter="status" data-value="custom">Custom</button>
        </div>
    </div>

    <!-- ── Plugin grid ──────────────────────────────────────────────── -->
    <div class="pm-grid" id="pmGrid">
        <?php foreach ($all as $p):
            $id = $p['id'];
            $lockedHint = $p['isCore']
                ? 'Core plugin — managed only by the platform owner.'
                : 'Installed by ' . $p['owner'] . ' — only they or an administrator can change it.';
            $details = json_encode([
                'label'=>$p['label'], 'id'=>$id, 'category'=>$p['cat'], 'catKey'=>$p['catKey'],
                'version'=>$p['version'], 'description'=>$p['description'], 'docsUrl'=>$p['docsUrl'],
                'core'=>$p['isCore'], 'owner'=>$p['owner'], 'disabled'=>$p['disabled'], 'canManage'=>$p['canManage'],
                'settings'=>$p['options'], 'vendor'=>$p['vendor'], 'assets'=>$p['assets'],
                'group'=>$p['group'], 'applies'=>$p['applies'], 'message'=>$p['message'],
            ], JSON_UNESCAPED_SLASHES | JSON_HEX_APOS | JSON_HEX_QUOT);
            $search = strtolower($p['label'] . ' ' . $id . ' ' . $p['description']);
        ?>
            <article class="pm-card<?= $p['disabled'] ? ' is-disabled' : '' ?>"
                     data-cat="<?= $p['catKey'] ?>"
                     data-status="<?= $p['disabled'] ? 'disabled' : 'enabled' ?>"
                     data-type="<?= $p['isCore'] ? 'core' : 'custom' ?>"
                     data-search="<?= htmlspecialchars($search, ENT_QUOTES) ?>">
                <div class="pm-card-top">
                    <span class="pm-card-ic"><i class="bi <?= $p['icon'] ?>"></i></span>
                    <div class="pm-card-id">
                        <span class="pm-card-cat"><i class="bi <?= $categories[$p['catKey']]['icon'] ?>"></i><?= $categories[$p['catKey']]['title'] ?></span>
                        <?php if ($p['version']): ?><span class="pm-card-ver">v<?= htmlspecialchars($p['version']) ?></span><?php endif; ?>
                    </div>
                </div>
                <div class="pm-card-body">
                    <h3 class="pm-card-name"><?= htmlspecialchars($p['label']) ?></h3>
                    <code class="pm-card-code"><?= htmlspecialchars($id) ?></code>
                    <?php if ($p['description']): ?>
                        <p class="pm-card-desc"><?= htmlspecialchars(mb_strimwidth($p['description'], 0, 96, '…')) ?></p>
                    <?php endif; ?>
                </div>
                <div class="pm-card-foot">
                    <div class="pm-card-badges">
                        <?php if ($p['isCore']): ?>
                            <span class="pm-badge core" title="Built-in / owner-managed"><i class="bi bi-shield-lock"></i>Core</span>
                        <?php else: ?>
                            <span class="pm-badge custom"><i class="bi bi-person"></i><?= htmlspecialchars($p['owner']) ?></span>
                        <?php endif; ?>
                        <span class="pm-badge <?= $p['disabled'] ? 'off' : 'on' ?>"><?= $p['disabled'] ? 'Disabled' : 'Enabled' ?></span>
                    </div>
                    <div class="pm-card-actions">
                        <button type="button" class="pm-act plugin-details-btn" data-plugin='<?= htmlspecialchars($details, ENT_QUOTES) ?>' title="Properties &amp; details"><i class="bi bi-info-circle"></i></button>
                        <?php if ($p['canManage']): ?>
                            <form method="post" action="<?= $baseUrl ?>/plugin-manager/toggle/<?= urlencode($id) ?>" class="toggle-form d-inline">
                                <button type="submit" class="pm-act <?= $p['disabled'] ? 'is-on' : '' ?>" title="<?= $p['disabled'] ? 'Enable' : 'Disable' ?>"><i class="bi <?= $p['disabled'] ? 'bi-toggle-off' : 'bi-toggle-on' ?>"></i></button>
                            </form>
                        <?php else: ?>
                            <button class="pm-act" disabled title="<?= htmlspecialchars($lockedHint) ?>"><i class="bi <?= $p['disabled'] ? 'bi-toggle-off' : 'bi-toggle-on' ?>"></i></button>
                        <?php endif; ?>
                        <?php if (!$p['isCore'] && $p['canManage']): ?>
                            <form method="post" action="<?= $baseUrl ?>/plugin-manager/delete/<?= urlencode($id) ?>" class="delete-form d-inline">
                                <button type="submit" class="pm-act danger" title="Delete"><i class="bi bi-trash"></i></button>
                            </form>
                        <?php else: ?>
                            <button class="pm-act" disabled title="<?= htmlspecialchars($p['isCore'] ? 'Core plugins cannot be deleted' : $lockedHint) ?>"><i class="bi bi-lock"></i></button>
                        <?php endif; ?>
                    </div>
                </div>
            </article>
        <?php endforeach; ?>
    </div>
    <div class="pm-empty" id="pmEmpty" hidden>
        <i class="bi bi-search"></i>
        <p class="mb-1">No plugins match your filters.</p>
        <button type="button" class="btn btn-sm pm-btn-ghost" id="pmReset">Clear filters</button>
    </div>
</div>

<!-- Plugin properties / details -->
<div class="modal fade" id="pluginDetailsModal" tabindex="-1" aria-hidden="true">
  <div class="modal-dialog modal-lg modal-dialog-scrollable">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="pdTitle"><span class="pd-ic"><i class="bi bi-puzzle"></i></span><span class="pd-t"></span></h5>
        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
      </div>
      <div class="modal-body" id="pdBody"></div>
    </div>
  </div>
</div>

<script src="<?= $assetsUrl ?>/bootstrap/js/bootstrap.bundle.min.js"></script>
<script src="<?= $assetsUrl ?>/sweetalert2/sweetalert2.min.js"></script>
<script>
var PM_BASE = <?= json_encode(rtrim($baseUrl, '/')) ?>;
var PM_IS_OWNER = <?= (!empty($isOwner)) ? 'true' : 'false' ?>;

// ── Details modal ─────────────────────────────────────────────────────────
(function(){
  var esc = function(s){ var d=document.createElement('div'); d.textContent=(s==null?'':String(s)); return d.innerHTML; };
  var modalEl = document.getElementById('pluginDetailsModal');
  var bsModal = modalEl ? new bootstrap.Modal(modalEl) : null;
  function typeLabel(f){
    var t = f.type || 'text';
    if ((t==='select'||t==='radiogroup') && Array.isArray(f.options)) return t + ' (' + f.options.filter(Boolean).join(', ') + ')';
    return t;
  }
  function render(p){
    var isVal = p.catKey === 'validation';
    document.querySelector('#pdTitle .pd-t').textContent = p.label + '  ·  ' + p.id;
    var h = '';
    h += '<div class="pd-meta mb-3">';
    h += '<span class="pm-badge ' + (p.core?'core':'custom') + '">' + (p.core?'Core':'Custom') + '</span> ';
    h += '<span class="pm-badge cat">' + esc(p.category) + '</span> ';
    if (p.version) h += '<span class="pm-badge ver">v' + esc(p.version) + '</span> ';
    h += '<span class="pm-badge ' + (p.disabled?'off':'on') + '">' + (p.disabled?'Disabled':'Enabled') + '</span> ';
    h += '<span class="pm-badge owner"><i class="bi bi-person me-1"></i>' + esc(p.core?'Owner only':('Managed by ' + p.owner)) + '</span>';
    if (isVal && p.group) h += ' <span class="pm-badge cat">' + esc(p.group) + '</span>';
    h += '</div>';
    if (p.description) h += '<p class="pd-desc">' + esc(p.description) + '</p>';
    if (p.docsUrl) h += '<p class="mb-3"><a href="' + esc(p.docsUrl) + '" target="_blank" rel="noopener"><i class="bi bi-book me-1"></i>Documentation</a></p>';
    if (isVal && p.message){ h += '<h6 class="pd-h">Default message</h6><p class="pd-desc">' + esc(p.message) + '</p>'; }

    // options / parameters
    h += '<h6 class="pd-h">' + (isVal ? 'Parameters' : 'Properties (Designer options)') + '</h6>';
    if (p.settings && p.settings.length){
      h += '<div class="table-responsive"><table class="table table-sm pd-table"><thead><tr><th>' + (isVal?'Param':'Option') + '</th><th>Type</th><th>Default</th></tr></thead><tbody>';
      p.settings.forEach(function(f){
        h += '<tr><td><code>' + esc(f.key) + '</code>' + (f.label?' <span class="text-muted">'+esc(f.label)+'</span>':'') + '</td><td>' + esc(typeLabel(f)) + '</td><td>' + esc(f['default']!=null && f['default']!==''?f['default']:'—') + '</td></tr>';
      });
      h += '</tbody></table></div>';
    } else { h += '<p class="text-muted small">' + (isVal?'This rule takes no parameters.':'This plugin exposes no configurable options.') + '</p>'; }

    // assets
    var aj = (p.assets&&p.assets.js)||[], ac = (p.assets&&p.assets.css)||[];
    if (aj.length || ac.length){
      h += '<h6 class="pd-h mt-3">Assets</h6><div class="pd-assets">';
      aj.concat(ac).forEach(function(f){ h += '<div class="pd-asset"><i class="bi bi-filetype-' + (/\.css$/.test(f)?'css':'js') + ' me-1"></i>' + esc(f) + '</div>'; });
      h += '</div>';
    }

    if (p.vendor && p.vendor.length){
      h += '<h6 class="pd-h mt-3">Bundled libraries</h6>';
      p.vendor.forEach(function(v){
        h += '<div class="pd-vendor"><strong>' + esc(v.name) + '</strong> ' + (v.version?'<span class="pm-badge ver">v'+esc(v.version)+'</span>':'') + (v.license?' <span class="pm-badge cat">'+esc(v.license)+'</span>':'');
        if (v.author) h += ' <span class="text-muted">by ' + esc(v.author) + '</span>';
        if (v.update) h += '<div class="small text-muted mt-1"><i class="bi bi-arrow-repeat me-1"></i>Update: ' + esc(v.update) + '</div>';
        if (Array.isArray(v.files)) h += '<div class="small text-muted">' + v.files.map(esc).join('<br>') + '</div>';
        h += '</div>';
      });
    }

    if (p.canManage){
      h += '<h6 class="pd-h mt-3">Update this plugin</h6>';
      h += '<form class="pd-update-form" method="post" action="' + esc(PM_BASE) + '/plugin-manager/update" enctype="multipart/form-data">'
        + '<input type="hidden" name="category" value="' + esc(p.category) + '">'
        + '<input type="hidden" name="name" value="' + esc(p.id) + '">'
        + '<div class="input-group input-group-sm">'
        + '<input type="file" name="plugin_zip" class="form-control" accept=".zip" required>'
        + '<button type="submit" class="btn pm-btn-accent"><i class="bi bi-arrow-repeat me-1"></i>Update</button>'
        + '</div>'
        + '<div class="small text-muted mt-1"><i class="bi bi-shield-check me-1"></i>The current version is backed up first and restored automatically if the new package is invalid.</div>'
        + '</form>';
    } else if (p.core){
      h += '<div class="small text-muted mt-3"><i class="bi bi-lock me-1"></i>Core plugin — only the platform owner can update it.</div>';
    }

    if (PM_IS_OWNER){
      h += '<h6 class="pd-h mt-3">Classification</h6>';
      h += '<form class="pd-core-form" method="post" action="' + esc(PM_BASE) + '/plugin-manager/mark-core">'
        + '<input type="hidden" name="category" value="' + esc(p.category) + '">'
        + '<input type="hidden" name="name" value="' + esc(p.id) + '">'
        + '<input type="hidden" name="core" value="' + (p.core ? '0' : '1') + '">'
        + '<span class="me-2">This is a <strong>' + (p.core ? 'Core' : 'Custom') + '</strong> plugin.</span>'
        + '<button type="submit" class="btn btn-sm pm-btn-ghost"><i class="bi bi-arrow-left-right me-1"></i>Mark as ' + (p.core ? 'Custom' : 'Core') + '</button>'
        + '<div class="small text-muted mt-1">Core plugins are managed only by you (the owner); Custom plugins can be managed by admins and their installer.</div>'
        + '</form>';
    }
    document.getElementById('pdBody').innerHTML = h;
    var uf = document.querySelector('#pdBody .pd-update-form');
    if (uf) uf.addEventListener('submit', function(e){
      e.preventDefault();
      Swal.fire({ title:'Update plugin?', text:'Replace this plugin with the uploaded ZIP? The current version will be backed up.', icon:'question', showCancelButton:true, confirmButtonText:'Yes, update' })
        .then(function(r){ if(r.isConfirmed) uf.submit(); });
    });
    if (bsModal) bsModal.show();
  }
  document.querySelectorAll('.plugin-details-btn').forEach(function(btn){
    btn.addEventListener('click', function(){
      try { render(JSON.parse(btn.getAttribute('data-plugin'))); } catch(e){ console.error(e); }
    });
  });
})();

// ── Search + filter ───────────────────────────────────────────────────────
(function(){
  var grid = document.getElementById('pmGrid');
  var cards = Array.prototype.slice.call(grid.querySelectorAll('.pm-card'));
  var search = document.getElementById('pmSearch');
  var clearBtn = document.getElementById('pmSearchClear');
  var empty = document.getElementById('pmEmpty');
  var state = { cat:'all', status:'all', q:'' };

  function apply(){
    var q = state.q.trim().toLowerCase();
    var shown = 0;
    cards.forEach(function(c){
      var okCat = state.cat === 'all' || c.dataset.cat === state.cat;
      var okStatus = state.status === 'all'
        || c.dataset.status === state.status
        || c.dataset.type === state.status;   // core/custom live on data-type
      var okQ = q === '' || c.dataset.search.indexOf(q) !== -1;
      var show = okCat && okStatus && okQ;
      c.hidden = !show;
      if (show) shown++;
    });
    empty.hidden = shown !== 0;
    clearBtn.hidden = state.q === '';
  }

  document.querySelectorAll('.pm-pill').forEach(function(pill){
    pill.addEventListener('click', function(){
      var f = pill.dataset.filter, v = pill.dataset.value;
      document.querySelectorAll('.pm-pill[data-filter="'+f+'"]').forEach(function(x){ x.classList.remove('active'); });
      pill.classList.add('active');
      state[f] = v;
      apply();
    });
  });
  search.addEventListener('input', function(){ state.q = search.value; apply(); });
  clearBtn.addEventListener('click', function(){ search.value=''; state.q=''; search.focus(); apply(); });
  document.getElementById('pmReset').addEventListener('click', function(){
    state = { cat:'all', status:'all', q:'' }; search.value='';
    document.querySelectorAll('.pm-pill').forEach(function(x){ x.classList.toggle('active', x.dataset.value==='all'); });
    apply();
  });
})();

// ── Confirmations ─────────────────────────────────────────────────────────
document.querySelectorAll('.toggle-form').forEach(function(form){
    form.addEventListener('submit', function(e){
        e.preventDefault();
        var btn = this.querySelector('button');
        var isEnabling = btn.classList.contains('is-on');
        var action = isEnabling ? 'enable' : 'disable';
        Swal.fire({
            title: 'Confirm ' + action, text: 'Are you sure you want to ' + action + ' this plugin?',
            icon:'question', showCancelButton:true,
            confirmButtonColor: isEnabling ? '#198754' : '#dc3545',
            confirmButtonText: 'Yes, ' + action + ' it'
        }).then(function(r){ if(r.isConfirmed) form.submit(); });
    });
});
document.querySelectorAll('.delete-form').forEach(function(form){
    form.addEventListener('submit', function(e){
        e.preventDefault();
        Swal.fire({ title:'Delete plugin?', text:'This action cannot be undone.', icon:'warning',
            showCancelButton:true, confirmButtonColor:'#dc3545', confirmButtonText:'Yes, delete', cancelButtonText:'Cancel'
        }).then(function(r){ if(r.isConfirmed) form.submit(); });
    });
});
</script>
</body>
</html>
