{% extends "base.html" %}

{% block title %}My activity — {{ instance_brand }}{% endblock %}

{% block layout %}
    {% with messages = get_flashed_messages(with_categories=true) %}
    {% if messages %}
    <div class="flash-messages">
        {% for category, message in messages %}
        <div class="flash flash-{{ category }}">{{ message }}</div>
        {% endfor %}
    </div>
    {% endif %}
    {% endwith %}
    <main class="main">{{ self.content() }}</main>
{% endblock %}

{% block content %}
<style>
/* Page-specific styles only. Tables use the canonical .data-table, stat
   tiles use .stat-card, paginate buttons use .btn — all from
   style-custom.css (design-system pass, v0.54.10). What remains here is
   genuinely page-specific: panel show/hide, the token chart, the sessions
   help text, pipeline badges, and the download link. */
.activity-page { max-width: 1280px; margin: 0 auto; padding: 24px 24px 64px; }

.stats-panel { display: none; }
.stats-panel.is-active { display: block; }
.stats-loading { color: var(--hp-text-muted, #6b7280); font-style: italic; padding: 24px 0; }
.stats-error { color: #b91c1c; padding: 24px 0; }
.stats-empty { color: var(--hp-text-muted, #6b7280); padding: 24px 0; }

/* Canonical .data-table is left-aligned; numeric columns opt into
   right-alignment per-page via .num (matches the pre-migration look). */
.data-table th.num, .data-table td.num { text-align: right; }

/* Layout-only wrappers — the tiles/buttons inside are canonical. */
.stats-paginate {
    display: flex; gap: 8px; justify-content: flex-end; padding: 12px 0;
}
.stats-overview {
    display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; margin-bottom: 16px;
}
@media (max-width: 720px) { .stats-overview { grid-template-columns: repeat(2, 1fr); } }

.tok-chart { width: 100%; height: 160px; margin: 8px 0 16px; }
.tok-chart rect { fill: var(--hp-accent, #2563eb); opacity: 0.85; }
.tok-chart .axis text { font-size: 10px; fill: var(--hp-text-muted, #6b7280); }

.sess-help {
    color: var(--text-secondary, #6b7280); font-size: 13px;
    margin-bottom: 16px; line-height: 1.55;
}
.sess-help code {
    background: var(--border-light, #f3f4f6); padding: 1px 6px;
    border-radius: 4px; font-size: 12px;
}

.badge {
    display: inline-block; padding: 2px 8px; border-radius: 999px;
    font-size: 11px; font-weight: 500;
}
.badge-pending   { background: #fef3c7; color: #92400e; }
.badge-processed { background: #dbeafe; color: #1e40af; }
.badge-extracted { background: #d1fae5; color: #065f46; }

.dl-link {
    display: inline-block; padding: 4px 10px;
    border: 1px solid var(--border, #e5e7eb); border-radius: 6px;
    color: inherit; text-decoration: none; font-size: 12px; font-weight: 500;
    background: var(--surface, #fff);
    transition: background 0.15s, border-color 0.15s;
}
.dl-link:hover {
    background: var(--border-light, #f9fafb);
    border-color: var(--primary, #6366f1);
    color: var(--primary, #4338ca);
}
</style>

<div class="activity-page">
    {% set page_hero_eyebrow = "Profile" %}
    {% set page_hero_title = "My activity" %}
    {# Block-capture so the literal <strong> stays HTML while {{ user.email }}
       is still autoescaped. `~`-concatenating a Markup operand (user.email | e)
       made Jinja2's markup_join escape the literal tags too. #}
    {% set page_hero_subtitle %}Sessions, token usage, data access, and sync activity for <strong>{{ user.email }}</strong>.{% endset %}
    {% include "_page_hero.html" %}

    <nav class="tab-strip" role="tablist" aria-label="Activity sections">
        <button type="button" role="tab" class="tab-strip__item is-active"
                data-tab="sessions" aria-selected="true">Sessions</button>
        <button type="button" role="tab" class="tab-strip__item"
                data-tab="tokens" aria-selected="false">Token usage</button>
        <button type="button" role="tab" class="tab-strip__item"
                data-tab="queries" aria-selected="false">Data access</button>
        <button type="button" role="tab" class="tab-strip__item"
                data-tab="sync" aria-selected="false">Sync activity</button>
    </nav>

    <section class="stats-panel is-active" id="panel-sessions" role="tabpanel" aria-labelledby="tab-sessions">
        <p class="sess-help">
            Sessions from your Claude Code workspace. <strong>Items extracted = 0</strong>
            means the verification detector ran successfully but the LLM didn't find
            anything worth tracking — that's expected for sessions that are mostly tool
            calls or coding without confident factual claims.
            <em>Pending</em> means the file is on disk but the scheduler hasn't processed
            it yet (next tick: every 15 min by default).
        </p>
        <div class="stats-loading" data-state="loading">Loading sessions…</div>
        <div data-state="ready" hidden>
            <table class="data-table">
                <thead><tr>
                    <th>Started</th><th>Model</th>
                    <th class="num">Prompts</th><th class="num">Tools</th>
                    <th class="num">Tokens</th>
                    <th>Pipeline</th><th class="num">Items</th>
                    <th></th>
                </tr></thead>
                <tbody data-rows></tbody>
            </table>
            <div class="stats-paginate">
                <button class="btn btn-secondary btn-sm" type="button" data-action="prev">‹ Prev</button>
                <button class="btn btn-secondary btn-sm" type="button" data-action="next">Next ›</button>
            </div>
        </div>
    </section>

    <section class="stats-panel" id="panel-tokens" role="tabpanel" aria-labelledby="tab-tokens">
        <div class="stats-loading" data-state="loading">Loading token usage…</div>
        <div data-state="ready" hidden>
            <div class="stats-overview">
                <div class="stat-card"><div class="stat-card__label">Input</div><div class="stat-card__value" data-tok-total="input">—</div></div>
                <div class="stat-card"><div class="stat-card__label">Output</div><div class="stat-card__value" data-tok-total="output">—</div></div>
                <div class="stat-card"><div class="stat-card__label">Cache read</div><div class="stat-card__value" data-tok-total="cache_read">—</div></div>
                <div class="stat-card"><div class="stat-card__label">Cache creation</div><div class="stat-card__value" data-tok-total="cache_creation">—</div></div>
            </div>
            <svg class="tok-chart" data-tok-chart viewBox="0 0 600 160" preserveAspectRatio="none"></svg>

            <h3 style="font-size: 13px; margin: 16px 0 6px; text-transform: uppercase; letter-spacing: 0.04em; color: var(--hp-text-muted, #6b7280);">By model</h3>
            <table class="data-table">
                <thead><tr>
                    <th>Model</th><th class="num">Sessions</th>
                    <th class="num">Input</th><th class="num">Output</th>
                    <th class="num">Cache R/W</th><th class="num">Total</th>
                </tr></thead>
                <tbody data-tok-model></tbody>
            </table>

            <h3 style="font-size: 13px; margin: 16px 0 6px; text-transform: uppercase; letter-spacing: 0.04em; color: var(--hp-text-muted, #6b7280);">Top sessions</h3>
            <table class="data-table">
                <thead><tr>
                    <th>Started</th><th>Model</th>
                    <th class="num">Input</th><th class="num">Output</th>
                    <th class="num">Cache</th><th class="num">Total</th>
                </tr></thead>
                <tbody data-tok-top></tbody>
            </table>
        </div>
    </section>

    <section class="stats-panel" id="panel-queries" role="tabpanel" aria-labelledby="tab-queries">
        <div class="stats-loading" data-state="loading">Loading queries…</div>
        <div data-state="ready" hidden>
            <table class="data-table">
                <thead><tr>
                    <th>When</th><th>Action</th><th>Resource</th>
                    <th>Result</th><th class="num">Duration (ms)</th>
                </tr></thead>
                <tbody data-rows></tbody>
            </table>
            <div class="stats-paginate">
                <button class="btn btn-secondary btn-sm" type="button" data-action="next">Older ›</button>
            </div>
        </div>
    </section>

    <section class="stats-panel" id="panel-sync" role="tabpanel" aria-labelledby="tab-sync">
        <div class="stats-loading" data-state="loading">Loading sync activity…</div>
        <div data-state="ready" hidden>
            <div class="stats-overview" style="grid-template-columns: 1fr;">
                <div class="stat-card">
                    <div class="stat-card__label">Your last <code>agnes pull</code></div>
                    <div class="stat-card__value" data-sync-last-pull>—</div>
                </div>
            </div>
            <table class="data-table">
                <thead><tr>
                    <th>When</th><th>Action</th><th>Source</th>
                    <th>Result</th>
                </tr></thead>
                <tbody data-rows></tbody>
            </table>
        </div>
    </section>
</div>

<script>
(function () {
    const root = document.querySelector('.activity-page');
    if (!root) return;

    function fmtNum(n) {
        if (n == null) return '—';
        if (n >= 1_000_000) return (n / 1_000_000).toFixed(1) + 'M';
        if (n >= 10_000)    return (n / 1_000).toFixed(0) + 'k';
        if (n >= 1_000)     return (n / 1_000).toFixed(1) + 'k';
        return String(n);
    }

    function fmtRelative(iso) {
        if (!iso) return 'never';
        const then = new Date(iso);
        const sec = Math.max(0, (Date.now() - then.getTime()) / 1000);
        if (sec < 60)        return Math.floor(sec) + 's ago';
        if (sec < 3600)      return Math.floor(sec / 60) + 'm ago';
        if (sec < 86400)     return Math.floor(sec / 3600) + 'h ago';
        return Math.floor(sec / 86400) + 'd ago';
    }

    function fmtTimestamp(iso) {
        if (!iso) return '';
        const d = new Date(iso);
        return d.toLocaleString();
    }

    function escapeHtml(s) {
        const d = document.createElement('div');
        d.textContent = s == null ? '' : String(s);
        return d.innerHTML;
    }

    async function fetchJSON(url) {
        const r = await fetch(url, { credentials: 'same-origin' });
        if (!r.ok) throw new Error('HTTP ' + r.status);
        return r.json();
    }

    function setReady(panel) {
        panel.querySelector('[data-state="loading"]').hidden = true;
        panel.querySelector('[data-state="ready"]').hidden = false;
    }

    function setError(panel, msg) {
        const loading = panel.querySelector('[data-state="loading"]');
        loading.className = 'stats-error';
        loading.textContent = msg;
    }

    // ----- Sessions tab -----

    const sessionsState = { offset: 0, limit: 25, total: 0 };

    function pipelineBadge(status) {
        if (status === 'extracted') return '<span class="badge badge-extracted">extracted</span>';
        if (status === 'processed') return '<span class="badge badge-processed">processed</span>';
        return '<span class="badge badge-pending">pending</span>';
    }

    async function loadSessions() {
        const panel = document.getElementById('panel-sessions');
        try {
            const data = await fetchJSON(
                `/api/me/stats/sessions?offset=${sessionsState.offset}&limit=${sessionsState.limit}`
            );
            sessionsState.total = data.total;
            const tbody = panel.querySelector('[data-rows]');
            tbody.innerHTML = '';
            if (data.rows.length === 0) {
                tbody.innerHTML = '<tr><td colspan="8" class="stats-empty">No sessions yet — start Claude Code in a workspace and they\'ll appear here.</td></tr>';
            }
            for (const r of data.rows) {
                const tr = document.createElement('tr');
                const dlCell = r.download_url
                    ? `<a class="dl-link" href="${escapeHtml(r.download_url)}" download>Download</a>`
                    : '';
                tr.innerHTML = `
                    <td>${fmtTimestamp(r.started_at)}</td>
                    <td>${r.primary_model || '<em style="color:#9ca3af;">unprocessed</em>'}</td>
                    <td class="num">${fmtNum(r.user_messages)}</td>
                    <td class="num">${fmtNum(r.tool_calls)}</td>
                    <td class="num">${fmtNum(r.tokens_total)}</td>
                    <td>${pipelineBadge(r.pipeline_status)}</td>
                    <td class="num">${r.items_extracted != null ? r.items_extracted : 0}</td>
                    <td>${dlCell}</td>
                `;
                tbody.appendChild(tr);
            }
            setReady(panel);
            const prevBtn = panel.querySelector('[data-action="prev"]');
            const nextBtn = panel.querySelector('[data-action="next"]');
            prevBtn.disabled = sessionsState.offset === 0;
            nextBtn.disabled = sessionsState.offset + sessionsState.limit >= sessionsState.total;
        } catch (e) {
            setError(panel, 'Could not load sessions: ' + e.message);
        }
    }

    document.querySelector('#panel-sessions [data-action="prev"]').addEventListener('click', () => {
        sessionsState.offset = Math.max(0, sessionsState.offset - sessionsState.limit);
        loadSessions();
    });
    document.querySelector('#panel-sessions [data-action="next"]').addEventListener('click', () => {
        sessionsState.offset += sessionsState.limit;
        loadSessions();
    });

    // ----- Token usage tab -----

    async function loadTokens() {
        const panel = document.getElementById('panel-tokens');
        try {
            const data = await fetchJSON('/api/me/stats/tokens?days=30');
            for (const key of ['input', 'output', 'cache_read', 'cache_creation']) {
                panel.querySelector(`[data-tok-total="${key}"]`).textContent =
                    fmtNum(data.totals[key]);
            }

            const chart = panel.querySelector('[data-tok-chart]');
            chart.innerHTML = '';
            const days = data.daily;
            if (days.length > 0) {
                const max = Math.max(...days.map(d => d.total), 1);
                const w = 600 / Math.max(days.length, 1);
                days.forEach((d, i) => {
                    const h = Math.max(1, (d.total / max) * 140);
                    const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
                    rect.setAttribute('x', String(i * w + 1));
                    rect.setAttribute('y', String(160 - h));
                    rect.setAttribute('width', String(Math.max(1, w - 2)));
                    rect.setAttribute('height', String(h));
                    rect.setAttribute('title', `${d.day}: ${d.total}`);
                    chart.appendChild(rect);
                });
            }

            const modelTbody = panel.querySelector('[data-tok-model]');
            modelTbody.innerHTML = '';
            if (data.by_model.length === 0) {
                modelTbody.innerHTML = '<tr><td colspan="6" class="stats-empty">No token data yet.</td></tr>';
            }
            for (const m of data.by_model) {
                const tr = document.createElement('tr');
                tr.innerHTML = `
                    <td>${m.model}</td>
                    <td class="num">${fmtNum(m.sessions)}</td>
                    <td class="num">${fmtNum(m.input)}</td>
                    <td class="num">${fmtNum(m.output)}</td>
                    <td class="num">${fmtNum(m.cache_read + m.cache_creation)}</td>
                    <td class="num"><strong>${fmtNum(m.total)}</strong></td>
                `;
                modelTbody.appendChild(tr);
            }

            const topTbody = panel.querySelector('[data-tok-top]');
            topTbody.innerHTML = '';
            if (data.top_sessions.length === 0) {
                topTbody.innerHTML = '<tr><td colspan="6" class="stats-empty">No sessions yet.</td></tr>';
            }
            for (const s of data.top_sessions) {
                const tr = document.createElement('tr');
                tr.innerHTML = `
                    <td>${fmtTimestamp(s.started_at)}</td>
                    <td>${s.primary_model || ''}</td>
                    <td class="num">${fmtNum(s.input)}</td>
                    <td class="num">${fmtNum(s.output)}</td>
                    <td class="num">${fmtNum(s.cache_read + s.cache_creation)}</td>
                    <td class="num"><strong>${fmtNum(s.total)}</strong></td>
                `;
                topTbody.appendChild(tr);
            }

            setReady(panel);
        } catch (e) {
            setError(panel, 'Could not load token data: ' + e.message);
        }
    }

    // ----- Queries tab -----

    const queriesState = { cursor: null };

    async function loadQueries(append) {
        const panel = document.getElementById('panel-queries');
        try {
            const params = new URLSearchParams({ limit: '50' });
            if (queriesState.cursor) {
                params.set('cursor_ts', queriesState.cursor.timestamp);
                params.set('cursor_id', queriesState.cursor.id);
            }
            const data = await fetchJSON(`/api/me/stats/queries?${params}`);
            const tbody = panel.querySelector('[data-rows]');
            if (!append) tbody.innerHTML = '';
            if (data.rows.length === 0 && !append) {
                tbody.innerHTML = '<tr><td colspan="5" class="stats-empty">No queries logged for your account yet.</td></tr>';
            }
            for (const r of data.rows) {
                const tr = document.createElement('tr');
                tr.innerHTML = `
                    <td>${fmtTimestamp(r.timestamp)}</td>
                    <td><code>${r.action}</code></td>
                    <td>${r.resource || ''}</td>
                    <td>${r.result || ''}</td>
                    <td class="num">${r.duration_ms != null ? r.duration_ms : ''}</td>
                `;
                tbody.appendChild(tr);
            }
            queriesState.cursor = data.next_cursor;
            panel.querySelector('[data-action="next"]').disabled = !queriesState.cursor;
            setReady(panel);
        } catch (e) {
            setError(panel, 'Could not load queries: ' + e.message);
        }
    }

    document.querySelector('#panel-queries [data-action="next"]').addEventListener('click', () => {
        loadQueries(true);
    });

    // ----- Sync tab -----

    async function loadSync() {
        const panel = document.getElementById('panel-sync');
        try {
            const data = await fetchJSON('/api/me/stats/sync?limit=50');
            panel.querySelector('[data-sync-last-pull]').textContent =
                fmtRelative(data.last_pull_at);
            const tbody = panel.querySelector('[data-rows]');
            tbody.innerHTML = '';
            if (data.rows.length === 0) {
                tbody.innerHTML = '<tr><td colspan="4" class="stats-empty">No sync activity yet.</td></tr>';
            }
            for (const r of data.rows) {
                const tr = document.createElement('tr');
                tr.innerHTML = `
                    <td>${fmtTimestamp(r.timestamp)}</td>
                    <td><code>${r.action}</code></td>
                    <td>${r.client_kind || ''}</td>
                    <td>${r.result || ''}</td>
                `;
                tbody.appendChild(tr);
            }
            setReady(panel);
        } catch (e) {
            setError(panel, 'Could not load sync activity: ' + e.message);
        }
    }

    // ----- Tab switching -----

    const loaded = new Set();
    const loaders = {
        sessions: loadSessions,
        tokens: loadTokens,
        queries: loadQueries,
        sync: loadSync,
    };

    function activate(name) {
        document.querySelectorAll('.tab-strip__item').forEach((b) => {
            const on = b.dataset.tab === name;
            b.classList.toggle('is-active', on);
            b.setAttribute('aria-selected', on ? 'true' : 'false');
        });
        document.querySelectorAll('.stats-panel').forEach((p) => {
            p.classList.toggle('is-active', p.id === 'panel-' + name);
        });
        if (!loaded.has(name)) {
            loaded.add(name);
            loaders[name]();
        }
    }

    document.querySelectorAll('.tab-strip__item').forEach((b) => {
        b.addEventListener('click', () => activate(b.dataset.tab));
    });

    // URL hash support: /me/activity?tab=sessions
    const urlTab = new URLSearchParams(window.location.search).get('tab');
    activate(urlTab && loaders[urlTab] ? urlTab : 'sessions');
})();
</script>
{% endblock %}
