{{ define "content" }}
<style>
  .store-cats { display:flex; flex-wrap:wrap; gap:.5rem; margin:0 0 1rem; }
  .cat-chip {
    display:inline-flex; align-items:center; gap:.4rem;
    padding:.5rem .85rem; min-height:44px; border-radius:999px;
    border:1px solid var(--border, #d1d5db); background:var(--surface, #fff);
    color:var(--text, #111827); font-weight:600; font-size:.95rem; cursor:pointer;
    transition:background .12s, border-color .12s;
  }
  .cat-chip:hover { border-color:var(--brand, #4f46e5); }
  .cat-chip.active { background:var(--brand, #4f46e5); border-color:var(--brand, #4f46e5); color:#fff; }
  .cat-chip .cat-n { font-size:.78rem; opacity:.7; font-weight:700; }
  .cat-chip.active .cat-n { opacity:.85; }
  .store-card[hidden] { display:none; }
  .store-search { width:100%; max-width:360px; padding:.6rem .9rem; min-height:44px;
    font-size:.95rem; border:1px solid var(--border, #d1d5db); border-radius:999px;
    background:var(--surface, #fff); color:var(--text, #111827); margin:0 0 1rem; }
  .store-search:focus { outline:none; border-color:var(--brand, #4f46e5); }
</style>
<h1>{{ T "plugins.store.title" }}</h1>

<div class="card" style="margin-bottom:1rem; display:flex; justify-content:space-between; align-items:center">
  <div>
    {{ if .EntitledFiltered }}
    <span class="muted">{{ T "plugins.store.filtered_note" }}</span>
    {{ else }}
    <span class="muted">{{ T "plugins.store.unfiltered_note" }}</span>
    {{ end }}
    {{ if .CatalogError }}
    <span style="color:#b91c1c"> — {{ T "plugins.store.catalog_error" }}</span>
    {{ end }}
  </div>
  <a class="btn secondary" href="/plugins">{{ T "plugins.store.manage_link" }}</a>
</div>

<div id="store-msg" class="muted" style="min-height:1.4rem; margin-bottom:.5rem" aria-live="polite"></div>

{{ if .Items }}
<input type="search" id="store-search" class="store-search" placeholder="{{ T "plugins.store.search_ph" }}" aria-label="{{ T "plugins.store.search_ph" }}" autocomplete="off">
{{ if .Categories }}
<div class="store-cats" role="group" aria-label="{{ T "plugins.store.browse" }}">
  <button type="button" class="cat-chip active" data-cat="">{{ T "plugins.store.all" }} <span class="cat-n">{{ len .Items }}</span></button>
  {{ range .Categories }}
  <button type="button" class="cat-chip" data-cat="{{ .Type }}">{{ T (printf "plugins.type.%s" .Type) }} <span class="cat-n">{{ .Count }}</span></button>
  {{ end }}
</div>
{{ end }}
<div id="store-grid" class="grid" style="grid-template-columns:repeat(auto-fill, minmax(260px, 1fr)); gap:1rem">
  {{ range .Items }}
  <div class="card store-card" data-listing-id="{{ .ListingID }}" data-type="{{ .Type }}" data-name="{{ .Name }}" data-desc="{{ .Description }}">
    <div style="display:flex; justify-content:space-between; align-items:baseline">
      <h3 style="margin:.2rem 0">{{ .Name }}</h3>
      <span class="tag">v{{ .Version }}</span>
    </div>
    <p class="muted" style="min-height:2.4rem">{{ .Description }}</p>
    <div style="display:flex; gap:.4rem; align-items:center; margin-bottom:.6rem">
      <span class="tag">{{ T (printf "plugins.type.%s" .Type) }}</span>
      {{ if .Installed }}
      <span class="tag" style="background:rgba(34,197,94,.2); color:#15803d">{{ T "plugins.store.state.installed" }}</span>
      {{ else if .Downloaded }}
      <span class="tag" style="background:rgba(59,130,246,.2); color:#1d4ed8">{{ T "plugins.store.state.downloaded" }}</span>
      {{ end }}
      {{ if eq .StatusState "failed" }}
      <span class="tag" data-testid="plugin-install-failed" style="background:rgba(248,113,113,.25); color:#b91c1c">
        {{ if .StatusMessageKey }}{{ T .StatusMessageKey }}{{ else }}{{ T "plugins.store.state.failed" }}{{ end }}
        {{ if .Retryable }}· {{ T "plugins.store.state.retryable" }}{{ end }}
      </span>
      {{ else if .StatusState }}
      <span class="tag" style="background:rgba(251,191,36,.25); color:#b45309">⏳ {{ .StatusState }}</span>
      {{ end }}
    </div>
    <div style="display:flex; gap:.5rem; flex-wrap:wrap">
      {{ if .Installed }}
      <a class="btn secondary" href="/plugins">{{ T "plugins.store.manage_link" }}</a>
      {{ else if .Downloaded }}
      <button class="btn" data-store-action="install" data-listing-id="{{ .ListingID }}">{{ T "plugins.store.action.install" }}</button>
      <button class="btn secondary" data-store-action="delete-download" data-listing-id="{{ .ListingID }}">{{ T "plugins.store.action.delete" }}</button>
      {{ else }}
      <button class="btn" data-store-action="download" data-listing-id="{{ .ListingID }}">{{ T "plugins.store.action.download" }}</button>
      {{ end }}
    </div>
  </div>
  {{ end }}
</div>
<p class="empty" id="store-no-matches" hidden>{{ T "plugins.store.no_matches" }}</p>
{{ else }}
<div class="card">
  {{ if .CatalogError }}
  {{/* The catalog didn't load (offline / blocked) — NOT an approvals problem. */}}
  <p class="empty">{{ T "plugins.store.offline" }}</p>
  {{ else if .EntitledFiltered }}
  {{/* Catalog reached, entitlements known, but nothing approved for this store. */}}
  <p class="empty">{{ T "plugins.store.empty" }}</p>
  {{ else }}
  {{/* Catalog reached, approvals unknown, but the catalog itself is empty. */}}
  <p class="empty">{{ T "plugins.store.none_available" }}</p>
  {{ end }}
</div>
{{ end }}

<script>
(function () {
  // Category browsing + search: filter the grid client-side (instant, works
  // offline — the whole catalog is already rendered). Category and search
  // combine (AND).
  var cats = document.querySelector('.store-cats');
  var search = document.getElementById('store-search');
  var cards = Array.prototype.slice.call(document.querySelectorAll('#store-grid .store-card'));
  var noMatch = document.getElementById('store-no-matches');
  var activeCat = '';
  function apply() {
    var q = (search && search.value || '').trim().toLowerCase();
    var shown = 0;
    cards.forEach(function (card) {
      var catOk = activeCat === '' || card.getAttribute('data-type') === activeCat;
      var hay = ((card.getAttribute('data-name') || '') + ' ' + (card.getAttribute('data-desc') || '')).toLowerCase();
      var textOk = q === '' || hay.indexOf(q) !== -1;
      var visible = catOk && textOk;
      card.hidden = !visible;
      if (visible) { shown++; }
    });
    if (noMatch) { noMatch.hidden = shown !== 0; }
  }
  if (cats) {
    cats.addEventListener('click', function (ev) {
      var chip = ev.target.closest('.cat-chip');
      if (!chip) return;
      activeCat = chip.getAttribute('data-cat');
      cats.querySelectorAll('.cat-chip').forEach(function (c) {
        c.classList.toggle('active', c === chip);
      });
      apply();
    });
  }
  if (search) { search.addEventListener('input', apply); }
})();
(function () {
  var msg = document.getElementById('store-msg');
  document.addEventListener('click', function (ev) {
    var btn = ev.target.closest('[data-store-action]');
    if (!btn) return;
    var action = btn.getAttribute('data-store-action');
    var listing = btn.getAttribute('data-listing-id');
    var card = btn.closest('.store-card');
    card.querySelectorAll('button').forEach(function (b) { b.disabled = true; });
    msg.textContent = '⏳ ' + action + '…';

    fetch('/api/plugins/store/' + action, {
      method: 'POST',
      headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
      body: new URLSearchParams({ listing_id: listing }).toString()
    }).then(function (res) { return res.json().catch(function () { return {}; }).then(function (j) {
      if (res.ok) { window.location.reload(); return; }
      msg.textContent = '✗ ' + (j.message || ('HTTP ' + res.status));
      card.querySelectorAll('button').forEach(function (b) { b.disabled = false; });
    }); }).catch(function (e) {
      msg.textContent = '✗ ' + e;
      card.querySelectorAll('button').forEach(function (b) { b.disabled = false; });
    });
  });
})();
</script>
{{ end }}
