{% extends "base.html.j2" %}
<!-- 23 skidoo -->
{% block title %}{{ t.live }} - neopig{% endblock %}

{% block extra_css %}
/* Live feed specific stats */
.stats { display: flex; gap: 30px; flex-wrap: wrap; padding: 15px; }
.stat { display: flex; flex-direction: column; }
.stat-value { font-size: 24px; font-weight: bold; color: #ff6b6b; }
.stat-label { font-size: 12px; color: #888; }
/* Controls */
.controls { margin-bottom: 20px; display: flex; gap: 10px; align-items: center; }
.controls button { padding: 8px 16px; border: none; border-radius: 4px; cursor: pointer; font-size: 14px; }
.controls button.primary { background: #ff6b6b; color: white; }
.controls button.secondary { background: #333; color: #ddd; }
.controls button:hover { opacity: 0.8; }
.status { color: #4ade80; font-size: 14px; }
.status.paused { color: #fbbf24; }
/* Live cards */
.live-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 15px; }
.live-card { background: #1a1a1a; border-radius: 8px; overflow: hidden; animation: fadeIn 0.5s ease-out; }
.live-card.new { box-shadow: 0 0 20px rgba(255, 107, 107, 0.5); }
.live-card img, .live-card video { width: 100%; height: 180px; object-fit: contain; background: #222; }
.live-card-info { padding: 10px; }
.live-card-title { font-size: 12px; color: #888; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.live-card-source { font-size: 10px; color: #555; margin-top: 4px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Score badges */
.score-badge { display: inline-block; padding: 2px 6px; border-radius: 3px; font-size: 9px; font-weight: bold; text-transform: uppercase; margin-left: 6px; vertical-align: middle; }
.score-screenshot { background: #666; color: #ccc; }
.score-og { background: #8b5cf6; color: white; }
.score-thumb { background: #3b82f6; color: white; }
.score-hd { background: #10b981; color: white; }
.live-card.upgraded { box-shadow: 0 0 20px rgba(16, 185, 129, 0.7); animation: upgradeGlow 1s ease-out; }
@keyframes upgradeGlow { 0% { box-shadow: 0 0 30px rgba(16, 185, 129, 1); } 100% { box-shadow: 0 0 20px rgba(16, 185, 129, 0.5); } }
@media (max-width: 768px) { .live-grid { grid-template-columns: repeat(2, 1fr); } }
{% endblock %}

{% block content %}
<div class="container">
    {% include 'partials/search_box.html.j2' %}

    <h1>{{ t.live }}{% if domain %}: {{ domain }}{% endif %}</h1>
    <p class="subtitle">{{ t.live_subtitle }}</p>

    <div class="stats">
        <div class="stat">
            <span class="stat-value" id="total-count">0</span>
            <span class="stat-label">{{ t.total_images }}</span>
        </div>
        <div class="stat">
            <span class="stat-value" id="new-count">0</span>
            <span class="stat-label">{{ t.new_session }}</span>
        </div>
        <div class="stat">
            <span class="stat-value" id="rate">0</span>
            <span class="stat-label">{{ t.per_minute }}</span>
        </div>
    </div>

    <div class="controls">
        <button class="primary" id="toggle-btn" onclick="toggleFeed()">{{ t.pause }}</button>
        <button class="secondary" onclick="clearFeed()">{{ t.delete }}</button>
        <span class="status" id="status">{{ t.watching }}</span>
    </div>

    <div class="live-grid" id="grid"></div>
</div>
{% endblock %}

{% block scripts %}
<script>
const T = {{ t_json|safe }};
const DOMAIN_FILTER = {{ domain_json|safe }};

// Check for replay mode from URL
const urlParams = new URLSearchParams(window.location.search);
const REPLAY_JOB_ID = urlParams.get('replay');

let running = true;
let seenHashes = new Map();
let newCount = 0;
let startTime = Date.now();
let eventSource = null;
let replayMode = !!REPLAY_JOB_ID;

// Update UI for replay mode
if (replayMode) {
    document.addEventListener('DOMContentLoaded', () => {
        const h1 = document.querySelector('h1');
        h1.textContent = T.replay_job + ' #' + REPLAY_JOB_ID;
        h1.style.color = '#9b59b6';
        const subtitle = document.querySelector('.subtitle');
        subtitle.textContent = T.replay_subtitle;
        subtitle.style.color = '#9b59b6';
    });
}

function connectSSE() {
    if (eventSource) eventSource.close();

    // Use replay endpoint if in replay mode
    const sseUrl = replayMode
        ? '/api/crawl/jobs/' + REPLAY_JOB_ID + '/replay'
        : '/api/live/stream';

    eventSource = new EventSource(sseUrl);

    eventSource.onmessage = function(event) {
        if (!running) return;
        try {
            const item = JSON.parse(event.data);

            // Handle replay end marker
            if (item.type === 'replay_end') {
                const status = document.getElementById('status');
                status.textContent = T.replay_complete + ' (' + item.total + ' items)';
                status.style.color = '#10b981';
                eventSource.close();
                return;
            }

            addMediaCard(item, true);
        } catch (e) {
            console.error('SSE parse error:', e);
        }
    };

    eventSource.onerror = function(e) {
        if (replayMode) {
            // Replay might have ended normally
            console.log('Replay stream ended');
            return;
        }
        console.log('SSE reconnecting...');
        setTimeout(connectSSE, 3000);
    };
}

function addMediaCard(item, isNew) {
    if (seenHashes.has(item.md5_hash)) return;

    seenHashes.set(item.md5_hash, {upgraded_at: item.upgraded_at, score: item.score || 5});
    newCount++;

    const grid = document.getElementById('grid');
    const card = document.createElement('div');
    card.className = 'live-card' + (isNew ? ' new' : '');

    const isVideo = item.media_type === 'video';
    const isCode = item.media_type === 'code';
    const isStyle = item.media_type === 'style';
    const isFont = item.media_type === 'font';

    const mimeToExt = {
        'text/javascript': '.js', 'application/javascript': '.js',
        'text/css': '.css', 'application/json': '.json',
        'font/woff': '.woff', 'font/woff2': '.woff2', 'font/ttf': '.ttf',
    };
    const getExt = (mime, alt) => mimeToExt[mime] || (alt ? '.' + alt : '');
    const placeholder = (ext, icon, color) => `<svg viewBox="0 0 100 100" style="width:100%;height:100%;background:#1a1a1a;border-radius:4px;"><text x="50" y="40" text-anchor="middle" fill="${color}" font-size="24">${icon}</text><text x="50" y="65" text-anchor="middle" fill="#888" font-family="monospace" font-size="14" font-weight="bold">${ext}</text></svg>`;

    let mediaEl;
    if (isVideo) mediaEl = `<video src="/media/${item.md5_hash}" muted loop onmouseenter="this.play()" onmouseleave="this.pause()"></video>`;
    else if (isCode) mediaEl = placeholder(getExt(item.mime_type, item.alt_text), '{ }', '#6af');
    else if (isStyle) mediaEl = placeholder('.css', '#', '#f6a');
    else if (isFont) mediaEl = placeholder(getExt(item.mime_type, ''), 'Aa', '#af6');
    else mediaEl = `<img src="/media/${item.md5_hash}" loading="lazy" onerror="this.src='data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 width=%22200%22 height=%22180%22><rect fill=%22%23333%22 width=%22200%22 height=%22180%22/><text x=%2250%%22 y=%2250%%22 fill=%22%23666%22 text-anchor=%22middle%22>Error</text></svg>'">`;

    const getFilename = (uri) => {
        if (!uri) return '';
        try {
            const path = new URL(uri).pathname;
            const name = decodeURIComponent(path.split('/').pop() || '');
            return name.length > 35 ? name.slice(0, 32) + '...' : name;
        } catch { return ''; }
    };
    const filename = getFilename(item.media_uri);
    const scoreBadge = getScoreBadge(item.score, item.media_type);

    card.innerHTML = `<a href="/view/${item.md5_hash}">${mediaEl}</a>
        <div class="live-card-info">
            <div class="live-card-title">${filename || item.alt_text || item.title || item.md5_hash.slice(0,12)}</div>
            <div class="live-card-source">${item.media_type} - ${formatSize(item.file_size)}${scoreBadge}</div>
        </div>`;

    grid.insertBefore(card, grid.firstChild);
    updateStats(seenHashes.size);
    if (isNew) setTimeout(() => card.classList.remove('new'), 2000);
}

function toggleFeed() {
    running = !running;
    const btn = document.getElementById('toggle-btn');
    const status = document.getElementById('status');
    if (running) {
        btn.textContent = T.pause;
        status.textContent = T.watching;
        status.className = 'status';
        connectSSE();
        poll();
    } else {
        btn.textContent = T.resume;
        status.textContent = T.paused;
        status.className = 'status paused';
        if (eventSource) eventSource.close();
    }
}

function clearFeed() {
    document.getElementById('grid').innerHTML = '';
    seenHashes = new Map();
    newCount = 0;
    startTime = Date.now();
    updateStats(0);
}

function updateStats(total) {
    document.getElementById('total-count').textContent = total;
    document.getElementById('new-count').textContent = newCount;
    const minutes = (Date.now() - startTime) / 60000;
    document.getElementById('rate').textContent = minutes > 0 ? Math.round(newCount / minutes) : 0;
}

async function poll() {
    if (!running) return;
    try {
        const query = DOMAIN_FILTER || '';
        const res = await fetch(`/api/search?q=${encodeURIComponent(query)}&limit=50`);
        const media = await res.json();

        const statsRes = await fetch('/api/stats');
        const stats = await statsRes.json();

        const isFirstPoll = seenHashes.size === 0;
        media.filter(m => !seenHashes.has(m.md5_hash)).reverse().forEach(item => addMediaCard(item, !isFirstPoll));
        updateStats(stats.total_media || 0);
    } catch (err) {
        console.error('Poll error:', err);
    }
    setTimeout(poll, 10000);
}

function formatSize(bytes) {
    if (!bytes) return '?';
    if (bytes < 1024) return bytes + ' B';
    if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB';
    return (bytes / (1024 * 1024)).toFixed(1) + ' MB';
}

function getScoreBadge(score, mediaType) {
    let label, cssClass;
    if (mediaType === 'screenshot' || score <= 1) { label = '📸'; cssClass = 'score-screenshot'; }
    else if (score <= 3) { label = 'OG'; cssClass = 'score-og'; }
    else if (!score || score <= 5) { label = 'THUMB'; cssClass = 'score-thumb'; }
    else { label = 'HD'; cssClass = 'score-hd'; }
    return `<span class="score-badge ${cssClass}">${label}</span>`;
}

// In replay mode: start with empty feed, only stream replay data
// In normal mode: poll for existing media and connect to live stream
if (!replayMode) {
    poll();
}
connectSSE();
</script>
{% endblock %}
