/**
 * Demo Oracle — activite temps reel : chronologie Chart.js + barres D3.
 * Lit sa configuration dans window.DemoOracleReport.realtime.
 *
 * Portage de modules/oracle/assets/js/report-realtime.js. Trois rappels de
 * filtrage ont disparu — fenetre, service, etat des sessions — parce que la
 * demonstration fige ces trois valeurs. Le choix de dimension et le filtre
 * croise restent.
 *
 * Les valeurs figees ne sont PAS envoyees dans l'URL : le point de donnees les
 * impose lui-meme, quoi qu'on lui passe.
 */
(function () {
'use strict';

var config = (window.DemoOracleReport && window.DemoOracleReport.realtime) || {};

/* ── Constants ───────────────────────────────────────────────────────────── */
var BASE_URL   = config.baseUrl   || '';
var SQL_DETAIL = config.sqlDetailUrl || '';
/* Le detail d'objet du module complet etait reste en dur — `/oracle/report/
   object/detail` — et rend un 404 la ou seule la demonstration est deployee.
   La section n'existe pas ici : l'entree est marquee, pas supprimee. */
var FULL_ONLY  = config.fullOnly || '';
var _dim   = config.dim         || 'wait_class';
var _cd    = 10;
var _iRef  = null, _iTick = null;
var _tlChart = null; // Chart.js timeline only
var _xfDim = null;
var _xfVal = null;

/* ── Palette (Tableau-20, same as ASH detail view) ───────────────────────── */
var PALETTE20 = [
    '#4e79a7','#a0cbe8','#f28e2b','#ffbe7d','#59a14f',
    '#8cd17d','#b6992d','#f1ce63','#499894','#86bcb6',
    '#e15759','#ff9d9a','#79706e','#bab0ac','#d37295',
    '#fabfd2','#b07aa1','#d4a6c8','#9d7660','#d7b5a6'
];

/* ── Wait-class colors for timeline (ASH standard) ───────────────────────── */
var WC = {
    'CPU':'#00BB00','Scheduler':'#78E078','User I/O':'#0043D0',
    'System I/O':'#0090E0','Network':'#989070','Commit':'#E06800',
    'Concurrency':'#801800','Configuration':'#606810','Application':'#FF0000',
    'Other':'#F071B0','Administrative':'#888888','Idle':'#cccccc',
    'ON CPU':'#00BB00','WAITING':'#801800'
};
var _pidx = {};
function wcColor(val) {
    if (WC[val] !== undefined) return WC[val];
    if (_pidx[val] === undefined) _pidx[val] = Object.keys(_pidx).length % PALETTE20.length;
    return PALETTE20[_pidx[val]];
}

/* ── Theme-aware text style ─────────────────────────────────────────────── */
function _textStyle() {
    var probe = document.querySelector('.card') || document.body;
    var color = getComputedStyle(probe).color;
    var m = color.match(/\d+/g);
    if (m && m.length >= 3) {
        var lum = (0.299 * +m[0] + 0.587 * +m[1] + 0.114 * +m[2]) / 255;
        if (lum > 0.5) return { fill: '#fff', stroke: 'rgba(0,0,0,.55)' };
    }
    return { fill: '#222', stroke: 'rgba(255,255,255,.7)' };
}

/* ── renderHBar — D3 horizontal bars with cross-filter support ───────────── */
function renderHBar(containerId, data, total, onRightClick, activeLabel, onLeftClick) {
    var container = document.getElementById(containerId);
    if (!container) return;
    container.innerHTML = '';
    if (!data.length) { container.innerHTML = '<p style="color:var(--color-text-muted);font-size:.82rem;margin:.5rem 0">Aucune donnée</p>'; return; }

    var isFiltered = activeLabel !== null && activeLabel !== undefined;
    var maxCnt = d3.max(data.filter(function(d){ return !d.isOther; }), function(d){ return d.cnt; }) || 1;
    var barH = 14, gap = 2;
    var margin = { top: 2, right: 6, bottom: 2, left: 2 };
    var W      = Math.max(container.clientWidth || 0, 260);
    var innerW = Math.max(W - margin.left - margin.right, 60);
    var H      = data.length * (barH + gap) + margin.top + margin.bottom;
    var xScale = d3.scaleLinear().domain([0, maxCnt]).range([0, innerW]);
    var ts     = _textStyle();

    var svg = d3.create('svg').attr('width', W).attr('height', H)
        .style('font-family', 'inherit').style('font-size', '10px');
    var g = svg.append('g').attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');

    data.forEach(function(d, i) {
        var isOther  = !!d.isOther;
        var isActive = isFiltered && d.label === activeLabel;
        var y   = i * (barH + gap);
        var bw  = Math.min(innerW, Math.max(2, xScale(d.cnt)));
        var pct = total > 0 ? (d.cnt / total * 100).toFixed(1) : '0.0';
        var col = isOther ? '#aaaaaa' : PALETTE20[i % PALETTE20.length];

        var row = g.append('g')
            .style('cursor', isOther ? 'default' : 'pointer')
            .attr('opacity', isFiltered && !isActive && !isOther ? 0.40 : 1);

        if (!isOther && onLeftClick) {
            row.on('click', function(event) {
                event.stopPropagation();
                onLeftClick(d.label);
            });
        }
        if (!isOther && onRightClick) {
            row.on('contextmenu', function(event) {
                event.preventDefault();
                onRightClick(d.label, event.clientX, event.clientY);
            });
        }

        var rect = row.append('rect')
            .attr('x', 0).attr('y', y)
            .attr('width', bw).attr('height', barH)
            .attr('fill', col).attr('rx', 2);

        if (isActive) {
            rect.attr('stroke', '#111').attr('stroke-width', 1.5);
        }

        row.append('text')
            .attr('x', 4).attr('y', y + barH * 0.76)
            .attr('fill', ts.fill)
            .attr('stroke', ts.stroke).attr('stroke-width', 2)
            .attr('stroke-linejoin', 'round')
            .style('paint-order', 'stroke fill')
            .style('font-weight', isOther ? '400' : '600')
            .text(d.label + ' — ' + pct + '%');
    });

    container.appendChild(svg.node());
}

/* ── SQL context menu ─────────────────────────────────────────────────── */
var _ctxEl = null;
function _hideCtx() {
    if (_ctxEl) { _ctxEl.remove(); _ctxEl = null; }
    document.removeEventListener('click',       _hideCtx);
    document.removeEventListener('contextmenu', _hideCtx);
}
function _showSqlCtx(sqlId, x, y) {
    _hideCtx();
    if (!sqlId || !/^[0-9a-z]{13}$/i.test(sqlId)) return;
    var menu = document.createElement('div');
    menu.style.cssText =
        'position:fixed;z-index:9999;'
        + 'background:var(--color-card-bg,#fff);'
        + 'border:1px solid var(--color-border,#ddd);border-radius:4px;'
        + 'box-shadow:0 2px 10px rgba(0,0,0,.18);padding:.2rem 0;min-width:200px;'
        + 'left:' + Math.min(x, window.innerWidth  - 210) + 'px;'
        + 'top:'  + Math.min(y, window.innerHeight -  80) + 'px';
    function _item(label, action) {
        var li = document.createElement('div');
        li.textContent = label;
        li.style.cssText = 'padding:.38rem .8rem;cursor:pointer;font-size:.84rem;white-space:nowrap;user-select:none';
        li.addEventListener('mouseenter', function(){ li.style.background='var(--color-primary,#4e79a7)'; li.style.color='#fff'; });
        li.addEventListener('mouseleave', function(){ li.style.background=''; li.style.color=''; });
        li.addEventListener('click',      function(){ _hideCtx(); action(); });
        menu.appendChild(li);
    }
    _item('🔍 Ouvrir le détail SQL', function() {
        window.open(SQL_DETAIL + '&sql_id=' + encodeURIComponent(sqlId), '_blank');
    });
    _item('📋 Copier le SQL_ID', function() {
        if (navigator.clipboard) {
            navigator.clipboard.writeText(sqlId).catch(function(){});
        } else {
            var ta = document.createElement('textarea');
            ta.value = sqlId; ta.style.cssText = 'position:fixed;opacity:0';
            document.body.appendChild(ta); ta.select();
            try { document.execCommand('copy'); } catch(e) {}
            document.body.removeChild(ta);
        }
    });
    document.body.appendChild(menu);
    _ctxEl = menu;
    setTimeout(function() {
        document.addEventListener('click',       _hideCtx, { once: true });
        document.addEventListener('contextmenu', _hideCtx, { once: true });
    }, 0);
}

/* ── Object context menu ─────────────────────────────────────────────── */
function _showObjCtx(objName, x, y) {
    _hideCtx();
    if (!objName) return;
    var menu = document.createElement('div');
    menu.style.cssText =
        'position:fixed;z-index:9999;'
        + 'background:var(--color-card-bg,#fff);'
        + 'border:1px solid var(--color-border,#ddd);border-radius:4px;'
        + 'box-shadow:0 2px 10px rgba(0,0,0,.18);padding:.2rem 0;min-width:200px;'
        + 'left:' + Math.min(x, window.innerWidth  - 210) + 'px;'
        + 'top:'  + Math.min(y, window.innerHeight -  80) + 'px';
    function _item(label, action) {
        var li = document.createElement('div');
        li.textContent = label;
        li.style.cssText = 'padding:.38rem .8rem;cursor:pointer;font-size:.84rem;white-space:nowrap;user-select:none';
        li.addEventListener('mouseenter', function(){ li.style.background='var(--color-primary,#4e79a7)'; li.style.color='#fff'; });
        li.addEventListener('mouseleave', function(){ li.style.background=''; li.style.color=''; });
        li.addEventListener('click',      function(){ _hideCtx(); action(); });
        menu.appendChild(li);
    }
    /* Entree inerte, marquee « version complete » : la section object/detail
       n'existe pas dans la demonstration. Aucun gestionnaire de clic — griser
       en laissant l'action derriere ne protegerait rien. */
    function _itemLocked(label) {
        var li = document.createElement('div');
        li.textContent = label + ' \uD83D\uDD12';
        li.title = FULL_ONLY;
        li.style.cssText = 'padding:.38rem .8rem;cursor:default;font-size:.84rem;white-space:nowrap;user-select:none;opacity:.55';
        menu.appendChild(li);
    }
    _itemLocked('🗂 Détail de l\'objet');
    _item('📋 Copier le nom', function() {
        if (navigator.clipboard) navigator.clipboard.writeText(objName).catch(function(){});
    });
    document.body.appendChild(menu);
    _ctxEl = menu;
    setTimeout(function() {
        document.addEventListener('click',       _hideCtx, { once: true });
        document.addEventListener('contextmenu', _hideCtx, { once: true });
    }, 0);
}

/* ── Cross-filter functions ──────────────────────────────────────────────── */
window.ashSetXFilter = function(dim, val) {
    if (_xfDim === dim && _xfVal === val) {
        _xfDim = null; _xfVal = null;
    } else {
        _xfDim = dim; _xfVal = val;
    }
    _renderXfBar();
    fetchData();
};
window.ashClearXFilter = function() {
    _xfDim = null; _xfVal = null;
    _renderXfBar();
    fetchData();
};
function _renderXfBar() {
    var bar = document.getElementById('ash-xf-bar');
    var lbl = document.getElementById('ash-xf-label');
    if (!bar) return;
    if (!_xfDim) { bar.style.display = 'none'; return; }
    bar.style.display = 'flex';
    var names = { sql_id:'SQL ID', event:'Événement', module:'Module',
                  action:'Action', machine:'Serveur client', inst_id:'Instance' };
    if (lbl) lbl.textContent = (names[_xfDim] || _xfDim) + ' = ' + _xfVal;
}

/* ── Library loading (D3 + Chart.js) ────────────────────────────────────── */
function loadLibs(cb) {
    var pending = 0;
    function done() { if (--pending === 0) cb(); }
    if (!window.d3) {
        pending++;
        var s1 = document.createElement('script');
        s1.src = config.cdnD3 || '';
        s1.onload = done;
        document.head.appendChild(s1);
    }
    if (!window.Chart) {
        pending++;
        var s2 = document.createElement('script');
        s2.src = config.cdnChartJs || '';
        s2.onload = done;
        document.head.appendChild(s2);
    }
    if (pending === 0) cb();
}

/* ── Data fetch ──────────────────────────────────────────────────────────── */
function fetchData() {
    // Fenetre, service et etat sont imposes cote serveur : les envoyer
    // n'aurait aucun effet, les omettre evite de laisser croire l'inverse.
    var url = BASE_URL + '&format=json'
        + '&dim=' + encodeURIComponent(_dim)
        + (_xfDim ? '&xf_dim=' + encodeURIComponent(_xfDim) + '&xf_val=' + encodeURIComponent(_xfVal) : '');
    fetch(url)
        .then(function(r) {
            var hit   = r.headers.get('X-Cache');
            var badge = document.getElementById('ash-cache-badge');
            if (badge) badge.innerHTML = hit === 'HIT'
                ? '<span style="color:#27ae60;font-size:.78rem">&#x25cf; cache</span>'
                : '<span style="color:#e67e22;font-size:.78rem">&#x21bb; requête</span>';
            return r.json();
        })
        .then(function(data) {
            if (data.error) { console.error('ASH:', data.error); return; }
            var el = document.getElementById('ash-updated');
            if (el) el.textContent = data.updated || '—';
            var total = data.total_samples || 0;
            renderTimeline(data);
            renderTopSql(data.top_sql || [], total);
            renderTopEvents(data.top_events || [], total);
            renderTopN('ash-top-modules',      data.top_modules      || [], total, 'module');
            renderTopN('ash-top-actions',      data.top_actions      || [], total, 'action');
            renderTopN('ash-top-services',     data.top_services     || [], total, null);
            renderTopN('ash-top-machines',     data.top_machines     || [], total, 'machine');
            renderTopN('ash-top-objects',      data.top_objects      || [], total, null,
                       function(label, x, y) { _showObjCtx(label, x, y); });
            renderTopN('ash-top-object-types', data.top_object_types || [], total, null);
            renderTopN('ash-top-instances',    data.top_instances    || [], total, 'inst_id');
            var pdbCard = document.getElementById('ash-top-pdbs-card');
            if (pdbCard) pdbCard.style.display = data.pdb_supported ? '' : 'none';
            if (data.pdb_supported) renderTopN('ash-top-pdbs', data.top_pdbs || [], total, null);
        })
        .catch(function(e) { console.error('ASH fetch:', e); });
}

/* ── Timeline (Chart.js stacked bar) ────────────────────────────────────── */
function renderTimeline(data) {
    var buckets  = data.buckets  || [];
    var dims     = data.dims     || [];
    var tl       = data.timeline || {};
    var labels   = buckets.map(function(b) { return b.slice(11); });
    var datasets = dims.map(function(d) {
        return {
            label:           d,
            data:            buckets.map(function(b) { return (tl[b] || {})[d] || 0; }),
            backgroundColor: wcColor(d),
            borderWidth:     0,
        };
    });
    var ctx = document.getElementById('ash-timeline').getContext('2d');
    if (_tlChart) _tlChart.destroy();
    _tlChart = new Chart(ctx, {
        type: 'bar',
        data: { labels: labels, datasets: datasets },
        options: {
            animation: false, responsive: true, maintainAspectRatio: false,
            plugins: {
                legend:  { position: 'bottom', labels: { boxWidth: 12, font: { size: 11 } } },
                tooltip: { mode: 'index', intersect: false },
            },
            scales: {
                x: { stacked: true, ticks: { maxRotation: 45, font: { size: 10 } } },
                y: { stacked: true, beginAtZero: true,
                     title: { display: true, text: 'Échantillons ASH', font: { size: 11 } } },
            },
        },
    });
}

/* ── Top SQL — clic gauche = filtre, clic droit = detail SQL ────────────── */
function renderTopSql(rows, total) {
    var data   = rows.map(function(r) { return { label: r.sql_id, cnt: r.samples }; });
    var active = (_xfDim === 'sql_id') ? _xfVal : null;
    renderHBar('ash-top-sql', data, total,
        function(sqlId, x, y) { _showSqlCtx(sqlId, x, y); },
        active,
        function(label) { window.ashSetXFilter('sql_id', label); }
    );
}

/* ── Top events — clic gauche = filtre ───────────────────────────────────── */
function renderTopEvents(rows, total) {
    var data   = rows.map(function(r) { return { label: r.event, cnt: r.samples }; });
    var active = (_xfDim === 'event') ? _xfVal : null;
    renderHBar('ash-top-events', data, total,
        null,
        active,
        function(label) { window.ashSetXFilter('event', label); }
    );
}

/* ── Generic top-N — xfDimForPanel=null means non-filterable panel ──────── */
function renderTopN(containerId, rows, total, xfDimForPanel, onRightClick) {
    var data    = rows.map(function(r) { return { label: r.label, cnt: r.samples }; });
    var active  = (xfDimForPanel && _xfDim === xfDimForPanel) ? _xfVal : null;
    var onClick = xfDimForPanel
        ? function(label) { window.ashSetXFilter(xfDimForPanel, label); }
        : null;
    renderHBar(containerId, data, total, onRightClick || null, active, onClick);
}

/* ── Auto-refresh ────────────────────────────────────────────────────────── */
function startRefresh() {
    if (_iRef)  clearInterval(_iRef);
    if (_iTick) clearInterval(_iTick);
    _cd   = 10;
    _iRef  = setInterval(function() { _cd = 10; fetchData(); }, 10000);
    _iTick = setInterval(function() {
        _cd = Math.max(0, _cd - 1);
        var el = document.getElementById('ash-countdown');
        if (el) el.textContent = _cd;
    }, 1000);
}

/* ── Rappel de filtrage ─────────────────────────────────────────────────── */
window.ashSetDim     = function(d) { _dim = d; fetchData(); };

/* ── Boot ────────────────────────────────────────────────────────────────── */
loadLibs(function() {
    fetchData();
    startRefresh();
});

})();
