
/**
 *  Graph Rendering (Vis.js) - Interaktionen zwischen Usern
 */
var MembersConnectionGraph = (function() {
    'use strict';

    let network = null;

    const defaults = {
        gravity: -3000,
        springLength: 250,
        nodeSize: 25,
        fontSize: 12,
        edgeSmooth: 'continuous',
        physicsEnabled: false
    };

    function buildControlsPanel() {
        const slider = (id, label, min, max, value, step) =>
            `<label style="display:flex;align-items:center;gap:6px;white-space:nowrap;">
                ${label}
                <input type="range" id="graph-ctrl-${id}" min="${min}" max="${max}" value="${value}" step="${step || 1}"
                    oninput="document.getElementById('graph-val-${id}').textContent=this.value; MembersConnectionGraph.updateParam('${id}', Number(this.value))">
                <span id="graph-val-${id}" style="min-width:50px;text-align:right;font-weight:bold">${value}</span>
            </label>`;

        return `<div id="graph-controls" style="display:flex;flex-wrap:wrap;gap:10px 20px;padding:6px 10px;
                    border:1px solid var(--color-border);border-radius:var(--radius-sm);margin-bottom:4px;background:var(--color-bg-secondary);font-size:12px;align-items:center;">
            ${slider('gravity', 'Gravity', -30000, -100, defaults.gravity, 100)}
            ${slider('springLength', 'Spring Length', 30, 800, defaults.springLength, 10)}
            ${slider('nodeSize', 'Node Size', 5, 80, defaults.nodeSize, 1)}
            ${slider('fontSize', 'Font Size', 4, 32, defaults.fontSize, 1)}
            <label style="display:flex;align-items:center;gap:6px;white-space:nowrap;">
                Edge Smooth
                <select id="graph-ctrl-edgeSmooth" onchange="MembersConnectionGraph.updateParam('edgeSmooth', this.value)" style="font-size:12px;">
                    <option value="continuous" ${defaults.edgeSmooth==='continuous'?'selected':''}>continuous</option>
                    <option value="dynamic" ${defaults.edgeSmooth==='dynamic'?'selected':''}>dynamic</option>
                    <option value="cubicBezier" ${defaults.edgeSmooth==='cubicBezier'?'selected':''}>cubicBezier</option>
                    <option value="false">straight</option>
                </select>
            </label>
            <label style="display:flex;align-items:center;gap:6px;white-space:nowrap;">
                Physics
                <input type="checkbox" id="graph-ctrl-physics" ${defaults.physicsEnabled?'checked':''}
                    onchange="MembersConnectionGraph.updateParam('physicsEnabled', this.checked)">
            </label>
            <button onclick="MembersConnectionGraph.restabilize()" style="font-size:12px;padding:2px 8px;">Re-stabilize</button>
        </div>`;
    }

    function updateParam(key, value) {
        if (!network) return;
        switch (key) {
            case 'gravity':
                network.setOptions({ physics: { barnesHut: { gravitationalConstant: value } } });
                break;
            case 'springLength':
                network.setOptions({ physics: { barnesHut: { springLength: value } } });
                break;
            case 'nodeSize':
                network.setOptions({ nodes: { size: value } });
                // update existing nodes
                network.body.data.nodes.forEach(n => {
                    network.body.data.nodes.update({ id: n.id, size: value });
                });
                break;
            case 'fontSize':
                network.setOptions({ nodes: { font: { size: value } } });
                break;
            case 'edgeSmooth':
                if (value === 'false') {
                    network.setOptions({ edges: { smooth: false } });
                } else {
                    network.setOptions({ edges: { smooth: { type: value } } });
                }
                break;
            case 'physicsEnabled':
                network.setOptions({ physics: { enabled: value } });
                break;
        }
    }

    function restabilize() {
        if (!network) return;
        network.stabilize(100);
    }

    function buildLegend() {
        const legend = document.createElement('div');
        legend.style.cssText = 'position:absolute;top:5px;right:10px;background:var(--color-bg-primary);' +
            'padding:6px 10px;border-radius:var(--radius-sm);z-index:10;font-size:11px;line-height:1.6;' +
            'border:1px solid var(--color-border);pointer-events:none;';

        // Edge legend items (colored dashes)
        const edgeLine = (color, label) =>
            `<span style="display:inline-flex;align-items:center;gap:4px;margin-right:10px;">` +
            `<span style="display:inline-block;width:18px;height:3px;background:${color};border-radius:1px;"></span>` +
            `<span>${label}</span></span>`;

        // Node legend items (colored circles)
        const nodeCircle = (borderColor, bgColor, label) =>
            `<span style="display:inline-flex;align-items:center;gap:4px;margin-right:10px;">` +
            `<span style="display:inline-block;width:10px;height:10px;border-radius:50%;background:${bgColor};border:2px solid ${borderColor};"></span>` +
            `<span>${label}</span></span>`;

        legend.innerHTML =
            `<div style="margin-bottom:2px;font-weight:600;color:var(--color-text-disabled);">Edges</div>` +
            `<div>${edgeLine('#e74c3c', 'Likes')}${edgeLine('#3498db', 'Comments')}</div>` +
            `<div style="margin-top:4px;margin-bottom:2px;font-weight:600;color:var(--color-text-disabled);">Nodes</div>` +
            `<div>${nodeCircle('#e74c3c', '#fadbd8', 'Admin')}${nodeCircle('#f39c12', '#fef5e7', 'Moderator')}${nodeCircle('#3498db', '#ebf5fb', 'Member')}</div>`;

        return legend;
    }

    /**
     * Loads and renders the interaction graph.
     * Nodes = users with profile images
     * Edges = likes (red) + comments (blue) to the post author
     * @param {HTMLElement} container - Container for the graph
     * @param {Array} filteredMembers - Filtered members (skool_ids are used)
     */
    async function loadAndRenderInteractionGraph(container, filteredMembers) {
        lib.showLoading('graphing');
        container.innerHTML = '<p style="padding:20px">Loading graph data...</p>';

        const skoolIds = filteredMembers.map(m => m.skool_id);
        const res = await post('/api/graph/interactions', {
            skool_ids: skoolIds,
            community: currentCommunity
        });
        lib.hideLoading();
        if (!res.ok) {
            container.innerHTML = '<p style="padding:20px;color:var(--color-error)">Error loading graph data</p>';
            return;
        }

        const { nodes, like_edges, comment_edges } = res.data;

        if (nodes.length === 0) {
            container.innerHTML = '<p style="padding:20px">No users found</p>';
            return;
        }

        const hideVal = await ConfigEntry.get("hide_profile_images");
        const hideImages = hideVal === "1";

        const visNodes = nodes.map(n => {
            const node = {
                id: n.id,
                label: n.name,
                size: defaults.nodeSize,
                title: `@${n.name}\nRole: ${n.role}`,
                group: n.role,
                borderWidth: 2
            };
            if (hideImages || !n.id) {
                node.shape = 'dot';
            } else {
                node.shape = 'circularImage';
                node.image = `/api/image/${n.id}`;
            }
            return node;
        });

        const visEdges = [
            ...like_edges.map(e => ({
                from: e.source,
                to: e.target,
                value: e.weight,
                color: { color: '#e74c3c', highlight: '#c0392b' },
                title: `${e.weight} Like${e.weight > 1 ? 's' : ''}`,
                arrows: 'to'
            })),
            ...comment_edges.map(e => ({
                from: e.source,
                to: e.target,
                value: e.weight,
                color: { color: '#3498db', highlight: '#2980b9' },
                title: `${e.weight} Comment${e.weight > 1 ? 's' : ''}`,
                arrows: 'to'
            }))
        ];

        // Controls + Stats + Graph
        container.innerHTML = buildControlsPanel();

        const stats = document.createElement('small');
        stats.style.cssText = 'position:absolute;top:5px;left:10px;background:var(--color-bg-primary);padding:4px 8px;border-radius:var(--radius-sm);z-index:10';
        stats.textContent = `${nodes.length} Users | ${like_edges.length} Like-Verbindungen (rot) | ${comment_edges.length} Comment-Verbindungen (blau)`;

        const graphWrap = document.createElement('div');
        graphWrap.style.cssText = 'width:100%;flex:1;position:relative;min-height:0';
        graphWrap.appendChild(stats);
        graphWrap.appendChild(buildLegend());

        const graphDiv = document.createElement('div');
        graphDiv.style.cssText = 'width:100%;height:100%';
        graphWrap.appendChild(graphDiv);

        container.appendChild(graphWrap);

        network = new vis.Network(graphDiv, { nodes: visNodes, edges: visEdges }, {
            nodes: {
                font: { size: defaults.fontSize },
                scaling: { min: 20, max: 40 }
            },
            edges: {
                smooth: { type: defaults.edgeSmooth },
                scaling: { min: 1, max: 8 }
            },
            physics: {
                enabled: true,
                stabilization: { iterations: 50, fit: true },
                barnesHut: {
                    gravitationalConstant: defaults.gravity,
                    springLength: defaults.springLength
                }
            },
            groups: {
                admin: { color: { border: '#e74c3c', background: '#fadbd8' } },
                moderator: { color: { border: '#f39c12', background: '#fef5e7' } },
                member: { color: { border: '#3498db', background: '#ebf5fb' } }
            }
        });

        // Stabilize once with physics, then disable so the graph is static by default.
        // Users can re-enable physics via the toggle checkbox.
        network.once('stabilizationIterationsDone', () => {
            network.setOptions({ physics: { enabled: false } });
        });
    }

    return {
        loadAndRenderInteractionGraph: loadAndRenderInteractionGraph,
        updateParam: updateParam,
        restabilize: restabilize
    };
}());