<h1>Projects</h1>

<% if (msg) { %><div class="flash"><%= msg %></div><% } %>
<% if (err) { %><div class="flash err"><%= err %></div><% } %>

<a id="active-banner" class="deploy-banner <%= active ? '' : 'hidden' %>" href="<%= active ? '/deployments/' + active.id : '#' %>">
  <span class="spinner"></span>
  <span id="banner-text"><%= active ? 'Deploying ' + active.app + ' — ' + (active.step || active.status) : '' %></span>
  <span id="banner-elapsed" class="muted" data-started="<%= active ? h.toMs(active.started_at) : 0 %>"></span>
</a>

<% if (projects.length === 0) { %>
  <div class="card">No projects yet. <a href="/projects/new">Create the first one</a>.</div>
<% } else { %>
<% const sortedProjects = projects.slice().sort(function (a, b) {
     var ga = a.group_name || '\uffff', gb = b.group_name || '\uffff';
     return ga < gb ? -1 : ga > gb ? 1 : (a.name < b.name ? -1 : 1);
   }); %>
<% const hasGroups = sortedProjects.some(function (p) { return p.group_name; }); %>
<% let prevG = null; %>
<% for (const p of sortedProjects) { %>
  <% const g = p.group_name || ''; %>
  <% if (prevG === null || (hasGroups && g !== prevG)) { %>
    <% if (prevG !== null) { %></div><% } %>
    <% if (hasGroups) { %><h2 class="group-h"><%= g || 'Ungrouped' %></h2><% } %>
    <div class="project-grid">
  <% } %>
  <% prevG = g; %>
    <% const d = latest[p.name]; %>
    <% const live = lastLive[p.name]; %>
    <% const af = accessFlags[p.name] || { enabled: true, protected: false }; %>
    <% const ps = !af.enabled ? 'deactivated' : (pm2[p.name] || 'unknown'); %>
    <% const info = infos[p.name]; %>
    <% const primary = info && info.DOMAINS ? String(info.DOMAINS).split(',')[0].trim() : (info && info.SYSTEM_DOMAIN ? String(info.SYSTEM_DOMAIN).trim() : ''); %>
    <% const commitLine = d ? (d.commit_msg || d.step || d.status) : 'no deployments yet'; %>
    <div class="project-card" data-app="<%= p.name %>">
      <div class="pc-head">
        <% if (primary) { %>
          <img class="favicon" src="https://<%= primary %>/favicon.ico" onerror="this.style.visibility='hidden'" width="20" height="20" alt="">
        <% } %>
        <div class="pc-names">
          <a class="pc-name" href="/projects/<%= p.name %>"><%= p.name %></a>
          <% if (primary) { %>
            <a class="pc-domain" href="https://<%= primary %>/" target="_blank" rel="noopener"><%= primary %></a>
          <% } else { %>
            <span class="pc-domain">no domain</span>
          <% } %>
        </div>
        <span class="spacer"></span>
        <% if (typeof user !== 'undefined' && user && user.role === 'admin' && typeof owners !== 'undefined' && owners[p.owner_user_id] && owners[p.owner_user_id] !== user.username) { %>
          <span class="chip queued" title="owner"><%= owners[p.owner_user_id] %></span>
        <% } %>
        <% if (d) { %>
          <a class="chip dep-chip <%= d.status %>" href="/deployments/<%= d.id %>"><%= h.depLabel(d.status) %></a>
        <% } else { %>
          <span class="chip dep-chip queued">never</span>
        <% } %>
      </div>
      <div class="pc-commit" title="<%= commitLine %>"><%= commitLine %></div>
      <div class="pc-meta" title="<%= p.repo_url %>">📦 <%= h.repoShort(p.repo_url) %> · <%= p.branch %></div>
      <div class="pc-foot">
        <% const tt = trafficToday[p.name]; %>
        <span class="pc-traffic">📈 <%= tt ? h.fmtInt(tt.requests) + ' req · ' + h.fmtBytes(tt.bytes) : 'no traffic today' %></span>
        <% if (live && live.finished_at) { %>
          <span class="pc-when" title="<%= live.finished_at %> UTC">🕑 <%= h.relTime(live.finished_at) %></span>
        <% } else { %>
          <span class="pc-when">🕑 never deployed</span>
        <% } %>
      </div>
      <div class="pc-actions">
        <span class="chip pm2-chip <%= ps === 'online' ? 'live' : (ps === 'unknown' || ps === 'deactivated' ? 'queued' : 'failed') %>"><%= ps %></span>
        <% if (af.protected) { %><span class="chip queued" title="Password protection (htpasswd) is enabled — visitors need credentials">🔒 protected</span><% } %>
        <form class="inline" method="post" action="/projects/<%= p.name %>/deploy">
          <button class="btn small" type="submit">Deploy</button>
        </form>
      </div>
    </div>
  <% } %>
</div>
<% } %>

<script>
(function () {
  var hadActive = <%= active ? 'true' : 'false' %>;

  function pmClass(s) {
    return 'chip pm2-chip ' + (s === 'online' ? 'live' : (s === 'unknown' || s === 'deactivated' ? 'queued' : 'failed'));
  }

  function tick() {
    var el = document.getElementById('banner-elapsed');
    if (!el) return;
    var t = Number(el.getAttribute('data-started') || 0);
    if (t > 0) {
      var sec = Math.max(0, Math.floor((Date.now() - t) / 1000));
      el.textContent = Math.floor(sec / 60) + 'm ' + (sec % 60) + 's';
    } else {
      el.textContent = '';
    }
  }

  async function poll() {
    var s;
    try {
      var r = await fetch('/api/status', { cache: 'no-store' });
      if (r.status === 401) { location.href = '/login'; return; }
      if (!r.ok) return;
      s = await r.json();
    } catch (e) { return; }

    document.querySelectorAll('[data-app]').forEach(function (card) {
      var app = card.getAttribute('data-app');
      var d = s.deployments[app];
      var chip = card.querySelector('.dep-chip');
      if (d && chip) {
        chip.className = 'chip dep-chip ' + d.status;
        chip.textContent = d.status === 'live' ? '\u25CF Ready' : d.status;
        if (chip.tagName === 'A') chip.setAttribute('href', '/deployments/' + d.id);
      }
      var pchip = card.querySelector('.pm2-chip');
      if (pchip) {
        var ps = s.pm2[app] || 'unknown';
        pchip.className = pmClass(ps);
        pchip.textContent = ps;
      }
    });

    var banner = document.getElementById('active-banner');
    var a = s.active && s.active[0];
    if (a) {
      hadActive = true;
      banner.classList.remove('hidden');
      banner.setAttribute('href', '/deployments/' + a.id);
      document.getElementById('banner-text').textContent = 'Deploying ' + a.app + ' — ' + (a.step || a.status);
      document.getElementById('banner-elapsed').setAttribute('data-started', String(a.started_ms || 0));
      tick();
    } else if (hadActive) {
      location.reload();
    } else {
      banner.classList.add('hidden');
    }
  }

  setInterval(poll, 3000);
  setInterval(tick, 1000);
  tick();
})();
</script>
