{%- import "partials/oneliner.html" as ol -%}
{%- import "partials/csrf_field.html" as csrf -%}
<!DOCTYPE html>
<html lang="de" style="--preview-lines: {{ preview_lines }}">
<head>
<meta charset="utf-8">
<title>Doctate — Meine Fälle</title>
<style>
body { font-family: sans-serif; max-width: 900px; margin: 2em auto; padding: 0 1em; }
header { display: flex; justify-content: space-between; align-items: center; }
header form { margin: 0; }
section { margin: 1.5em 0; }
section h2 { font-size: 1.1em; color: #555; border-bottom: 1px solid #ddd; padding-bottom: 0.2em; display: flex; justify-content: space-between; align-items: baseline; gap: 1em; }
section h2 .count { font-weight: normal; font-size: 0.85em; color: #888; }
.empty { color: #888; font-style: italic; }
.pending { color: #888; font-style: italic; }

.case-list { list-style: none; padding: 0; margin: 0; }
.case-row { display: grid; grid-template-columns: 1fr auto; gap: 0.6em 1em; align-items: center; padding: 0.7em 1em; border: 1px solid #ccc; border-radius: 4px; margin: 0.5em 0; }
.case-list.has-bulk .case-row { grid-template-columns: auto 1fr auto; }
html.admin-view-off .case-list.has-bulk .case-row { grid-template-columns: 1fr auto; }
.case-row.done { border-left: 4px solid #7ed321; }
.case-row.open { border-left: 4px solid #4a90e2; }
.case-row .check { align-self: start; padding-top: 0.25em; }
.case-row .body { min-width: 0; }
.case-row .body h3 { margin: 0 0 0.2em 0; font-size: 1em; font-weight: 600; }
.case-row .body small { color: #666; font-family: monospace; font-size: 0.85em; }
.case-row .oneliner { color: #333; margin: 0.2em 0 0; }
.case-row .line1 { font-size: 1em; margin: 0; display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 0.25em 0.6em; }
.case-row .line1 .time { font-family: monospace; font-weight: bold; color: #444; }
.case-row .case-link { color: inherit; text-decoration: none; min-width: 0; }
.case-row .case-link:hover { text-decoration: underline; }
.case-row .recordings-link { color: #4a90e2; text-decoration: none; font-size: 0.9em; white-space: nowrap; }
.case-row .recordings-link:hover { text-decoration: underline; }
.case-row .manual-marker { font-size: 0.9em; opacity: 0.55; margin-left: 0.15em; cursor: help; }
.case-row .analysis { margin-top: 0.55em; padding-top: 0.45em; border-top: 1px solid #e5e5e5; display: flex; align-items: flex-start; gap: 0.4em; cursor: pointer; }
.case-row .analysis .arrow { flex-shrink: 0; color: #888; line-height: 1.2; transition: transform 0.15s ease; }
.case-row .analysis.open .arrow { transform: rotate(90deg); }
.case-row .analysis-content { color: #555; font-size: 0.9em; min-width: 0; flex: 1 1 auto; display: -webkit-box; -webkit-line-clamp: var(--preview-lines); line-clamp: var(--preview-lines); -webkit-box-orient: vertical; overflow: hidden; }
.case-row .analysis-content > :first-child { margin-top: 0; }
.case-row .analysis-content > :last-child { margin-bottom: 0; }
.case-row .analysis-content p { display: inline; margin: 0; }
.case-row .analysis-content mark { background: #fff3a0; padding: 0 0.15em; border-radius: 2px; }
.case-row .analysis.open .analysis-content { display: block; overflow: visible; }
.case-row .analysis.open .analysis-content p { display: block; margin: 0 0 0.5em; }
.case-row .uuid { color: #999; font-family: monospace; font-size: 0.7em; margin-top: 0.2em; }
.status-badge { display: inline-block; padding: 0.05em 0.5em; border-radius: 999px; font-size: 0.75em; font-weight: bold; color: white; margin-left: 0.7em; }
.status-badge.open { background: #4a90e2; }
.status-badge.done { background: #7ed321; }
.status-badge.fehler { background: #e24a4a; }
.case-row .actions { display: flex; gap: 0.4em; align-items: center; }
.case-row .actions button { font-size: 0.85em; padding: 0.35em 0.8em; }
.case-row .actions .delete-btn { padding: 0.3em; background: transparent; border: none; color: #888; cursor: pointer; display: inline-flex; align-items: center; line-height: 0; border-radius: 4px; transition: color 0.15s, background 0.15s; }
.case-row .actions .delete-btn:hover { color: #e24a4a; background: #fff0f0; }
.case-row .actions .reopen-btn { padding: 0.3em; background: transparent; border: none; color: #888; cursor: pointer; display: inline-flex; align-items: center; line-height: 0; border-radius: 4px; transition: color 0.15s, background 0.15s; }
.case-row .actions .reopen-btn:hover { color: #4a90e2; background: #eef4fb; }
.case-row.closed { opacity: 0.65; background: #fafafa; }
.case-row.closed .case-link { color: #777; }
.case-row .closed-badge { display: inline-block; margin-left: 0.5em; padding: 0.05em 0.5em; border-radius: 999px; font-size: 0.75em; font-weight: bold; background: #ddd; color: #444; }

.closed-toggle { display: block; margin: 0.5em 0 1em; font-size: 0.9em; color: #4a90e2; text-decoration: none; }
.closed-toggle:hover { text-decoration: underline; }

.label { display: inline-block; margin-left: 0.6em; padding: 0.05em 0.5em; border-radius: 999px; font-size: 0.75em; font-weight: bold; vertical-align: middle; }
.label.analyzing { background: #eee; color: #555; }
.label.done-doc { background: #7ed321; color: white; }

.bulk-bar { margin: 1em 0; padding: 0.8em 1em; background: #f6f6f6; border-radius: 4px; display: flex; gap: 0.6em; flex-wrap: wrap; align-items: center; }
.bulk-bar button { font-size: 0.9em; padding: 0.5em 1em; }
.bulk-bar.purge { background: #fff0f0; border: 1px solid #e24a4a; }
.bulk-bar.purge button { background: #e24a4a; color: white; border: none; }
.bulk-bar.purge button:hover { background: #c43030; }

.header-right { display: flex; align-items: center; gap: 0.8em; }
.admin-toggle { font-size: 0.85em; color: #666; display: inline-flex; align-items: center; gap: 0.3em; cursor: pointer; user-select: none; }
html.admin-view-off .admin-only { display: none !important; }
</style>
<script>
try {
  if (localStorage.getItem('admin-view') === 'off') {
    document.documentElement.classList.add('admin-view-off');
  }
} catch (_) {}
</script>
</head>
<body>
<header>
<h1>{{ slug }} — Meine Fälle</h1>
<div class="header-right">
{% if is_admin %}<label class="admin-toggle"><input type="checkbox" id="admin-view-toggle"> Admin view</label>{% endif %}
<form method="post" action="/web/logout">{% call csrf::field(csrf_token) %}<button type="submit">Logout</button></form>
</div>
</header>

{% if show_closed %}
<a class="closed-toggle" href="/web/cases">← Nur offene Fälle anzeigen</a>
{% else %}
<a class="closed-toggle" href="/web/cases?show_closed=1">Geschlossene Fälle einblenden</a>
{% endif %}

{% if total == 0 %}
<section><p class="empty">{% if show_closed %}Keine offenen oder geschlossenen Fälle.{% else %}Keine Fälle.{% endif %}</p></section>
{% else %}
<form method="post" action="/web/cases/bulk">
{% call csrf::field(csrf_token) %}
<input type="hidden" name="return_to" value="/web/cases{% if show_closed %}?show_closed=1{% endif %}">

{% for g in groups %}
<section>
<h2 class="date-group" data-iso="{{ g.label }}"><span class="date-label">{{ g.label }}</span><span class="count">{{ g.open_count }}/{{ g.total_count }} Fälle</span></h2>
<ul class="case-list{% if is_admin %} has-bulk{% endif %}">
{% for case in g.cases %}
<li class="case-row {% if case.is_closed %}closed{% else if case.has_document %}done{% else %}open{% endif %}">
{% if is_admin %}<div class="check admin-only"><input type="checkbox" name="case_id" value="{{ case.case_id }}"{% if case.is_closed %} disabled{% endif %}></div>{% endif %}
<div class="body">
<div class="line1">
<a class="case-link" href="/web/cases/{{ case.case_id }}{% if case.is_closed %}?show_closed=1{% endif %}"><span class="time"><time datetime="{{ case.recorded_at_iso }}">{{ case.time_hms_utc }}</time></span> — {% call ol::render(case.oneliner) %}{% if case.oneliner_is_manual %} <span class="manual-marker" title="manuell bearbeitet" aria-label="manuell bearbeitet">👤</span>{% endif %}{% if case.has_failed_recording %} <span class="status-badge fehler">Fehler</span>{% else if case.has_document %} <span class="status-badge done">ausgewertet</span>{% else if !case.is_closed %} <span class="status-badge open">offen</span>{% endif %}{% if case.analyzing %} <span class="label analyzing">wird analysiert</span>{% endif %}{% if case.is_closed %} <span class="closed-badge">geschlossen{% match case.days_until_purge %}{% when Some with (d) %} — wird in {{ d }} Tagen entfernt{% when None %}{% endmatch %}</span>{% endif %}</a>
<a class="recordings-link" href="/web/cases/{{ case.case_id }}/recordings{% if case.is_closed %}?show_closed=1{% endif %}">{{ case.recordings_count }} Aufnahmen</a>
</div>
{% match case.analysis_html %}{% when Some with (html) %}<div class="analysis" data-expand><span class="arrow">▸</span><div class="analysis-content">{{ html|safe }}</div></div>{% when None %}{% endmatch %}
{% if is_admin %}<div class="uuid admin-only">{{ case.case_id }}</div>{% endif %}
</div>
<div class="actions">
{% if is_admin %}<button type="submit" formaction="/web/cases/{{ case.case_id }}/analyze" class="admin-only"{% if !case.can_analyze || case.is_closed %} disabled{% endif %}>{% if case.has_document %}Neu analysieren{% else %}Analysieren{% endif %}</button>
<button type="submit" formaction="/web/cases/{{ case.case_id }}/reset" class="admin-only"{% if case.is_closed %} disabled{% endif %}>Reset</button>{% endif %}
{% if case.is_closed %}
<button type="submit" formaction="/web/cases/{{ case.case_id }}/reopen" class="reopen-btn" title="Fall wiedereröffnen" aria-label="Fall wiedereröffnen"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"></path><path d="M3 3v5h5"></path></svg></button>
{% else %}
<button type="submit" formaction="/web/cases/{{ case.case_id }}/close" class="delete-btn" title="Fall schließen" aria-label="Fall schließen"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"></path><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"></path><path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path><line x1="10" x2="10" y1="11" y2="17"></line><line x1="14" x2="14" y1="11" y2="17"></line></svg></button>
{% endif %}
</div>
</li>
{% endfor %}
</ul>
</section>
{% endfor %}
{% if is_admin %}<div class="bulk-bar admin-only">
<span>Auswahl:</span>
<button type="button" onclick="const b=document.querySelectorAll('input[name=case_id]');const all=Array.from(b).every(c=>c.checked);b.forEach(c=>c.checked=!all);this.textContent=all?'Alles auswählen':'Keine auswählen'">Alles auswählen</button>
<button type="submit" name="action" value="analyze">Analysieren</button>
<button type="submit" name="action" value="reset">Reset</button>
<button type="submit" name="action" value="close">Schließen</button>
</div>{% endif %}
</form>
{% if is_admin && show_closed && any_closed %}
<form class="bulk-bar purge admin-only" method="post" action="/web/cases/purge-closed" onsubmit="return confirm('Alle geschlossenen Fälle UNWIDERRUFLICH löschen? Diese Aktion kann nicht rückgängig gemacht werden.')">
{% call csrf::field(csrf_token) %}
<input type="hidden" name="confirm" value="yes">
<span>Geschlossene Fälle:</span>
<button type="submit">Alle geschlossenen unwiderruflich löschen</button>
</form>
{% endif %}
{% endif %}
<script>
{% include "partials/time_format.js" %}
</script>
<script>
// Render all UTC timestamps in the browser's local timezone, and relabel
// date-group headings to Heute/Gestern/DD.MM.YYYY.
(() => {
  document.querySelectorAll('time[datetime]').forEach((el) => {
    const d = new Date(el.dateTime);
    if (!isNaN(d.getTime())) el.textContent = TimeFmt.timeLabel(d);
  });
  document.querySelectorAll('h2.date-group').forEach((h) => {
    const iso = h.dataset.iso;
    if (!iso) return;
    const labelEl = h.querySelector('.date-label');
    if (labelEl) labelEl.textContent = TimeFmt.dateLabelFromISO(iso);
  });
})();

(() => {
  const cb = document.getElementById('admin-view-toggle');
  if (!cb) return;
  cb.checked = !document.documentElement.classList.contains('admin-view-off');
  cb.addEventListener('change', () => {
    const on = cb.checked;
    try { localStorage.setItem('admin-view', on ? 'on' : 'off'); } catch (_) {}
    document.documentElement.classList.toggle('admin-view-off', !on);
  });
})();

// Preserve scroll position across POST-redirects (close, reopen,
// bulk-*). Browsers keep scroll on location.reload() but NOT on a
// redirect-driven navigation, even when the target URL matches the
// referer. Without this, clicking close on row 30 of a long list
// dumps the user back at scrollY=0 with the action-row off-screen.
//
// Mechanism: capture scrollY in sessionStorage before every form
// submit on this page, restore it on the very next load, then delete.
// Using the classic two-arg scrollTo(0, y) form — the options-object
// variant is silently ignored in some older browsers.
(() => {
  const STASH = 'doctate:scrollY';
  try {
    document.querySelectorAll('form').forEach((f) => {
      f.addEventListener('submit', () => {
        sessionStorage.setItem(STASH, String(window.scrollY));
      });
    });
    const stashed = sessionStorage.getItem(STASH);
    if (stashed !== null) {
      sessionStorage.removeItem(STASH);
      const y = parseInt(stashed, 10);
      if (!isNaN(y)) {
        window.scrollTo(0, y);
      }
    }
  } catch (_) {
    // sessionStorage may be blocked (strict privacy mode) — silent fail,
    // scroll returns to 0 like it did before this feature.
  }
})();

// Live-update bus: any case event for this user triggers a debounced
// page reload. Debounce collapses event bursts (e.g. bulk-delete) into
// one reload. EventSource auto-reconnects on network drops.
(() => {
  let timer = null;
  const scheduleReload = () => {
    clearTimeout(timer);
    timer = setTimeout(() => location.reload(), 300);
  };
  const es = new EventSource('/web/events');
  // Release the socket-pool slot on navigation. Without this, Chrome
  // keeps the SSE connection "draining" after unload; six rapid nav
  // cycles exhaust the 6-per-origin pool and stall further requests.
  window.addEventListener('pagehide', () => es.close());
  es.addEventListener('case', () => scheduleReload());
})();

// Expandable analysis: click anywhere on .analysis toggles the `open`
// class. Links/buttons inside the analysis are preserved — a click on
// a <mark>-wrapped term shouldn't accidentally expand (no such case
// today, but the guard is free). Delegation keeps one listener across
// all case rows, no per-row wiring.
document.addEventListener('click', (e) => {
  const exp = e.target.closest('[data-expand]');
  if (!exp) return;
  if (e.target.closest('a, button, input')) return;
  exp.classList.toggle('open');
});
</script>
</body>
</html>
