// Swarm Singularity UI - 3D Force Graph Telemetry

const HIVE_NODE_ID = "hive-mind-core";

let swarmGraph = null;
const swarmData = {
    nodes: [{ id: HIVE_NODE_ID, name: "Hive Memory Singularity", group: 1, val: 50 }],
    links: []
};

// Track agent nodes
const connectedAgents = new Set();
const msgLog = [];

function initSwarmGraph() {
    if (swarmGraph) return;

    const elem = document.getElementById('3d-graph');
    
    // Initialize the 3D Force Graph
    swarmGraph = ForceGraph3D()(elem)
        .graphData(swarmData)
        .nodeLabel('name')
        .nodeAutoColorBy('group')
        .nodeVal('val')
        .linkDirectionalParticles(2)
        .linkDirectionalParticleSpeed(d => d.value * 0.01)
        .linkDirectionalParticleWidth(1.5)
        .linkColor(() => 'rgba(255, 255, 255, 0.2)')
        .backgroundColor('#000011')
        // Glow effect
        .nodeThreeObject(node => {
            if (node.id === HIVE_NODE_ID) {
                // Hive Memory is a large glowing sphere
                const sprite = new THREE.Sprite(
                    new THREE.SpriteMaterial({ color: '#00ffff' })
                );
                sprite.scale.set(30, 30, 1);
                return sprite;
            } else {
                // Agents are smaller glowing spheres
                const sprite = new THREE.Sprite(
                    new THREE.SpriteMaterial({ color: '#ff00ff' })
                );
                sprite.scale.set(10, 10, 1);
                return sprite;
            }
        });

    // Make the graph spin slowly like a galaxy
    let angle = 0;
    setInterval(() => {
        if (!swarmGraph) return;
        swarmGraph.cameraPosition({
            x: 400 * Math.sin(angle),
            z: 400 * Math.cos(angle)
        });
        angle += Math.PI / 600;
    }, 20);
}

function logTelemetryEvent(agentId, action) {
    const logEl = document.getElementById('swarm-log');
    if (!logEl) return;
    
    const time = new Date().toLocaleTimeString();
    const color = action === 'write' ? '#ffaa00' : '#00aaff';
    const text = `<span style="color:${color}">[${time}] ${agentId} -> ${action.toUpperCase()}</span>`;
    
    msgLog.unshift(text);
    if (msgLog.length > 5) msgLog.pop();
    
    logEl.innerHTML = msgLog.join('<br/>');
}

function handleTelemetryEvent(payload) {
    if (!payload || !payload.agent_id) return;
    const agentId = payload.agent_id;
    const action = payload.action || 'read'; // 'read' or 'write'

    // Add node if it doesn't exist
    if (!connectedAgents.has(agentId)) {
        swarmData.nodes.push({ id: agentId, name: `Agent: ${agentId}`, group: 2, val: 10 });
        swarmData.links.push({ source: agentId, target: HIVE_NODE_ID, id: `${agentId}-hive` });
        connectedAgents.add(agentId);
        
        // Update DOM stats
        document.getElementById('swarm-stats').innerText = `Nodes: ${swarmData.nodes.length} | Links: ${swarmData.links.length}`;
    }

    // Determine signal direction and color
    // Read: Hive -> Agent
    // Write: Agent -> Hive
    const sourceNode = action === 'read' ? HIVE_NODE_ID : agentId;
    const targetNode = action === 'read' ? agentId : HIVE_NODE_ID;
    
    // Add a temporary glowing link particle to simulate the electrical signal
    const tempLinkId = `pulse-${Date.now()}-${Math.random()}`;
    const pulseLink = {
        source: sourceNode,
        target: targetNode,
        id: tempLinkId,
        value: 2, // Speed modifier
        color: action === 'read' ? 'rgba(0, 255, 255, 0.8)' : 'rgba(255, 170, 0, 0.8)'
    };

    // Briefly add the link to the graph to trigger the particle, then remove it
    swarmData.links.push(pulseLink);
    swarmGraph.graphData(swarmData);

    // Remove the pulse link after 2 seconds (particle traversal time)
    setTimeout(() => {
        swarmData.links = swarmData.links.filter(l => l.id !== tempLinkId);
        swarmGraph.graphData(swarmData);
    }, 2000);

    logTelemetryEvent(agentId, action);
}

// Hook into the tab switcher to initialize the graph ONLY when the tab is visible
// (Otherwise Three.js gets bad canvas dimensions)
document.addEventListener('DOMContentLoaded', () => {
    // Listen for tab changes
    document.querySelectorAll('.nav-link').forEach(link => {
        link.addEventListener('click', (e) => {
            const tabId = e.currentTarget.getAttribute('data-tab');
            if (tabId === 'swarm') {
                setTimeout(initSwarmGraph, 100);
            }
        });
    });

    // Also inject our handler into the existing Dashboard WebSocket (ws.js usually handles this)
    // We will hook into the window event bus if one exists, or just hijack the WS onmessage.
});

// Expose globally for the WebSocket handler
window.handleSwarmTelemetry = handleTelemetryEvent;
