// discover_activity.js — Activity heatmap (15-min resolution) for Discover page
// Uses scatter endpoints for minute-level data, aggregated into 15-min buckets

var discActivityLoaded = false;
var discActivityView = 'activity';
var discActivityExcludeOwner = false;
var discActivityCachedSkoolIds = null;
var discActivityScatterData = null;
var discOnlineScatterData = null;

// ── Tooltip ──
var _actTip = null;
function actTip() {
    if (!_actTip) { _actTip = document.createElement('div'); _actTip.className = 'disc-scatter-tooltip'; document.body.appendChild(_actTip); }
    return _actTip;
}

// ── Data loading ──

async function loadActivityTab() {
    discActivityLoaded = true;
    var c = document.getElementById('disc-activity-content');
    if (!c) return;
    c.innerHTML = '<div class="disc-network-empty"><div style="font-size:0.9rem;">Loading activity data...</div></div>';

    if (!discActivityCachedSkoolIds) {
        try {
            var res = await fetch('/api/user/filter', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ page: 1, limit: 5000 }) });
            if (res.ok) { var d = await res.json(); discActivityCachedSkoolIds = (d.users || d.data || d.members || []).map(function(m) { return m.skool_id; }); }
        } catch (e) { c.innerHTML = '<div class="disc-network-empty"><div style="color:var(--color-error);">Error loading members.</div></div>'; return; }
    }
    if (!discActivityCachedSkoolIds || !discActivityCachedSkoolIds.length) {
        c.innerHTML = '<div class="disc-network-empty"><div style="font-size:2.5rem;opacity:.4;">&#128200;</div><div>No members found.</div></div>';
        return;
    }
    await Promise.all([loadScatterActivity(), loadScatterOnline()]);
    renderActivityTabContent();
}

async function loadScatterActivity() {
    try { var r = await fetch('/api/activity/scatter', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ skool_ids: discActivityCachedSkoolIds, exclude_owner: discActivityExcludeOwner, days: 30 }) }); if (r.ok) discActivityScatterData = await r.json(); } catch (e) { discActivityScatterData = null; }
}
async function loadScatterOnline() {
    try { var r = await fetch('/api/activity/online-scatter', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ skool_ids: discActivityCachedSkoolIds, days: 30 }) }); if (r.ok) discOnlineScatterData = await r.json(); } catch (e) { discOnlineScatterData = null; }
}

// ── Tab rendering ──

function renderActivityTabContent() {
    var c = document.getElementById('disc-activity-content');
    if (!c) return;

    var h = '<div class="disc-activity-toolbar">';
    h += '<button class="disc-activity-toolbar__view-btn' + (discActivityView === 'activity' ? ' disc-activity-toolbar__view-btn--active' : '') + '" onclick="switchActivityView(\'activity\')">Posts &amp; Comments</button>';
    h += '<button class="disc-activity-toolbar__view-btn' + (discActivityView === 'online' ? ' disc-activity-toolbar__view-btn--active' : '') + '" onclick="switchActivityView(\'online\')">Online Status</button>';
    h += '<div class="disc-toolbar__separator"></div>';
    h += '<label class="disc-activity-toolbar__toggle" style="' + (discActivityView === 'activity' ? '' : 'opacity:.4;pointer-events:none;') + '">';
    h += '<input type="checkbox" ' + (discActivityExcludeOwner ? 'checked' : '') + ' onchange="toggleExcludeOwner(this.checked)"> Exclude owner activity</label>';
    h += '</div>';

    var data = discActivityView === 'activity' ? discActivityScatterData : discOnlineScatterData;
    var type = discActivityView;

    if (!data || !data.points) {
        h += '<div class="disc-heatmap-section"><div class="disc-network-empty" style="flex:1;"><div>No data available.</div></div></div>';
    } else {
        var sub = type === 'activity'
            ? 'When members post and comment (last 30 days)' + (discActivityExcludeOwner && data.owner_skool_id ? ' · owner excluded' : '')
            : 'When members were last seen online (last 30 days)';
        h += renderHeatmapSection(type === 'activity' ? 'Member Activity' : 'Member Online Times', sub, data.points, data.total, type);
    }
    c.innerHTML = h;
    bindHeatmapTooltips(c);
}

function switchActivityView(v) { discActivityView = v; renderActivityTabContent(); }
async function toggleExcludeOwner(v) {
    discActivityExcludeOwner = v;
    var s = document.querySelector('.disc-heatmap-section'); if (s) s.style.opacity = '.5';
    await loadScatterActivity();
    renderActivityTabContent();
}

// ── Constants ──
var DAYS = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
var SLOTS = 96; // 24h * 4 (15-min each)

// ── Aggregate scatter data into 7×96 matrix ──

function buildMatrix(points) {
    var matrix = [];
    for (var s = 0; s < SLOTS; s++) {
        var row = new Array(7).fill(0);
        matrix.push(row);
    }
    for (var di = 0; di < 7; di++) {
        var arr = points[DAYS[di]] || [];
        for (var i = 0; i < arr.length; i++) {
            var slot = Math.floor(arr[i] / 15);
            if (slot >= 0 && slot < SLOTS) matrix[slot][di]++;
        }
    }
    return matrix;
}

// ── Analysis ──

function analyzeScatter(points) {
    var minCounts = {};
    var dayTotals = [];
    var allMins = [];

    for (var di = 0; di < 7; di++) {
        var day = DAYS[di];
        var arr = points[day] || [];
        dayTotals.push({ day: day, total: arr.length });
        for (var i = 0; i < arr.length; i++) {
            var k = day + ':' + arr[i];
            minCounts[k] = (minCounts[k] || 0) + 1;
            allMins.push(arr[i]);
        }
    }

    var peakKey = '', peakCount = 0;
    for (var k in minCounts) { if (minCounts[k] > peakCount) { peakCount = minCounts[k]; peakKey = k; } }
    var pp = peakKey.split(':');
    dayTotals.sort(function(a, b) { return b.total - a.total; });

    // 30-min sliding window
    var wm = new Array(1440).fill(0);
    for (var i = 0; i < allMins.length; i++) wm[allMins[i]]++;
    var ws = 0; for (var i = 0; i < 30; i++) ws += wm[i];
    var bestWS = ws, bestWI = 0;
    for (var i = 1; i <= 1410; i++) { ws = ws - wm[i - 1] + wm[i + 29]; if (ws > bestWS) { bestWS = ws; bestWI = i; } }

    return {
        peakDay: pp[0] || 'Mon', peakMinute: parseInt(pp[1]) || 0, peakCount: peakCount,
        bestDay: dayTotals[0] || { day: 'Mon', total: 0 },
        winStart: bestWI, winCount: bestWS
    };
}

// ── Heatmap section ──

function renderHeatmapSection(title, subtitle, points, total, type) {
    var matrix = buildMatrix(points);
    var stats = analyzeScatter(points);
    var unit = type === 'activity' ? 'interactions' : 'sightings';

    // Find max value in matrix for color scaling
    var maxVal = 0;
    for (var s = 0; s < SLOTS; s++)
        for (var d = 0; d < 7; d++)
            if (matrix[s][d] > maxVal) maxVal = matrix[s][d];

    if (total === 0) {
        return '<div class="disc-heatmap-section"><div class="disc-heatmap-section__header"><div class="disc-heatmap-section__title">' + title + '</div></div>'
            + '<div class="disc-network-empty" style="flex:1;"><div>No data available.</div></div></div>';
    }

    var colorFn = type === 'activity' ? colorActivity : colorOnline;

    var h = '<div class="disc-heatmap-section">';
    // Header
    h += '<div class="disc-heatmap-section__header">';
    h += '<div class="disc-heatmap-section__title">' + title + '</div>';
    h += '<div class="disc-heatmap-section__subtitle">' + subtitle + '</div>';
    h += '</div>';
    // Stat strip
    h += '<div class="disc-heatmap-stats">';
    h += statChip('Total', total.toLocaleString(), unit);
    h += statChip('Peak', stats.peakDay + ' ' + mToTime(stats.peakMinute), stats.peakCount + ' in 1 min');
    h += statChip('Best Day', stats.bestDay.day, stats.bestDay.total.toLocaleString());
    h += statChip('Best 30 min', mToTime(stats.winStart) + ' – ' + mToTime(stats.winStart + 30), stats.winCount.toLocaleString());
    h += '</div>';

    // Grid
    h += '<div class="disc-hm15-wrap"><div class="disc-hm15">';

    // Header row: empty corner + day names
    h += '<div class="disc-hm15__corner"></div>';
    for (var d = 0; d < 7; d++) {
        h += '<div class="disc-hm15__day-header">' + DAYS[d] + '</div>';
    }

    // 96 rows
    for (var s = 0; s < SLOTS; s++) {
        var minuteStart = s * 15;
        var hr = Math.floor(minuteStart / 60);

        // Time label: show at every full hour
        if (minuteStart % 60 === 0) {
            h += '<div class="disc-hm15__time-label" style="grid-row: span 4;">' + fmtH(hr) + '</div>';
        }

        // 7 cells for this time slot
        for (var d = 0; d < 7; d++) {
            var val = matrix[s][d];
            var bg = colorFn(val, maxVal);
            var slotLabel = mToTime(minuteStart) + ' – ' + mToTime(minuteStart + 15);
            h += '<div class="disc-hm15__cell" style="background:' + bg + ';"'
                + ' data-day="' + DAYS[d] + '" data-slot="' + slotLabel + '" data-val="' + val + '"'
                + '></div>';
        }
    }

    h += '</div></div>';

    // Footer
    h += '<div class="disc-heatmap-footer">';
    h += renderLegend(colorFn, maxVal);
    h += '<div class="disc-heatmap-timezone">Times in UTC · last 30 days</div>';
    h += '</div>';

    h += '</div>';
    return h;
}

function statChip(label, value, detail) {
    return '<div class="disc-heatmap-stat">'
        + '<span class="disc-heatmap-stat__label">' + label + '</span>'
        + '<span class="disc-heatmap-stat__value">' + value + '</span>'
        + (detail ? '<span class="disc-heatmap-stat__detail">' + detail + '</span>' : '')
        + '</div>';
}

// ── Color ramps ──

function colorActivity(val, maxVal) {
    if (val === 0 || maxVal === 0) return 'rgba(var(--brand-primary-rgb), 0.04)';
    var r = val / maxVal;
    if (r < 0.10) return 'rgba(var(--brand-primary-rgb), 0.12)';
    if (r < 0.20) return 'rgba(var(--brand-primary-rgb), 0.22)';
    if (r < 0.35) return 'rgba(var(--brand-primary-rgb), 0.34)';
    if (r < 0.50) return 'rgba(var(--brand-primary-rgb), 0.48)';
    if (r < 0.65) return 'rgba(var(--brand-primary-rgb), 0.62)';
    if (r < 0.80) return 'rgba(var(--brand-primary-rgb), 0.76)';
    if (r < 0.92) return 'rgba(var(--brand-primary-rgb), 0.88)';
    return 'var(--brand-primary)';
}

function colorOnline(val, maxVal) {
    if (val === 0 || maxVal === 0) return 'rgba(var(--color-success-rgb), 0.04)';
    var r = val / maxVal;
    if (r < 0.10) return 'rgba(var(--color-success-rgb), 0.12)';
    if (r < 0.20) return 'rgba(var(--color-success-rgb), 0.22)';
    if (r < 0.35) return 'rgba(var(--color-success-rgb), 0.34)';
    if (r < 0.50) return 'rgba(var(--color-success-rgb), 0.48)';
    if (r < 0.65) return 'rgba(var(--color-success-rgb), 0.62)';
    if (r < 0.80) return 'rgba(var(--color-success-rgb), 0.76)';
    if (r < 0.92) return 'rgba(var(--color-success-rgb), 0.88)';
    return 'var(--color-success)';
}

// ── Legend ──

function renderLegend(colorFn, maxVal) {
    var steps = [0, 0.08, 0.18, 0.32, 0.48, 0.65, 0.80, 0.95];
    var h = '<div class="disc-hm15-legend">';
    h += '<span>Less</span><div class="disc-hm15-legend__bar">';
    for (var i = 0; i < steps.length; i++) {
        h += '<div class="disc-hm15-legend__swatch" style="background:' + colorFn(Math.round(steps[i] * maxVal), maxVal) + ';"></div>';
    }
    h += '</div><span>More</span></div>';
    return h;
}

// ── Tooltip ──

function bindHeatmapTooltips(container) {
    var tip = actTip();
    var cells = container.querySelectorAll('.disc-hm15__cell');
    cells.forEach(function(el) {
        el.addEventListener('mouseenter', function() {
            var day = el.getAttribute('data-day');
            var slot = el.getAttribute('data-slot');
            var val = el.getAttribute('data-val');
            tip.innerHTML = '<b>' + day + '</b> ' + slot + '<br><span style="color:var(--brand-primary);font-weight:700;">' + val + '</span> <span style="color:var(--color-text-disabled);">' + (discActivityView === 'activity' ? 'interactions' : 'sightings') + '</span>';
            tip.classList.add('disc-scatter-tooltip--visible');
        });
        el.addEventListener('mousemove', function(e) {
            tip.style.left = (e.clientX + 14) + 'px';
            tip.style.top = (e.clientY - 8) + 'px';
        });
        el.addEventListener('mouseleave', function() {
            tip.classList.remove('disc-scatter-tooltip--visible');
        });
    });
}

// ── Formatting ──

function mToTime(m) {
    m = ((m % 1440) + 1440) % 1440;
    var h = Math.floor(m / 60), mn = m % 60;
    var s = h < 12 ? ' AM' : ' PM', h12 = h === 0 ? 12 : h > 12 ? h - 12 : h;
    return h12 + ':' + (mn < 10 ? '0' : '') + mn + s;
}
function fmtH(h) {
    if (h === 0) return '12:00 AM';
    if (h < 12) return h + ':00 AM';
    if (h === 12) return '12:00 PM';
    return (h - 12) + ':00 PM';
}
