// ═══════════════════════════════════════════════════════
// CVC Dashboard — Hive Singularity UI (God-Level Swarm)
// ZERO-LAG ARCHITECTURE
// ═══════════════════════════════════════════════════════

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: []
};

const connectedAgents = new Map();
let totalPackets = 0;

function initSwarmGraph() {
    if (swarmGraph) return;

    const elem = document.getElementById('3d-graph');
    if (!elem) return;

    // We use UnrealBloomPass directly if we had imports, 
    // but 3d-force-graph supports basic post-processing.
    // We will use native Three.js Torus/Icosahedron meshes for a high-tech look.

    swarmGraph = ForceGraph3D()(elem)
        .graphData(swarmData)
        .nodeLabel('name')
        .nodeVal('val')
        // Hide the actual link lines slightly, we just want to see the particles
        .linkColor(() => 'rgba(0, 255, 204, 0.1)')
        .linkWidth(0.5)
        .backgroundColor('#03030b')
        // Customize Nodes with 3D Geometries
        .nodeThreeObject(node => {
            if (node.id === HIVE_NODE_ID) {
                // The Singularity: A glowing wireframe Icosahedron inside a Torus
                const group = new THREE.Group();
                
                const coreGeo = new THREE.IcosahedronGeometry(15, 2);
                const coreMat = new THREE.MeshBasicMaterial({ color: '#00ffff', wireframe: true, transparent: true, opacity: 0.8 });
                const core = new THREE.Mesh(coreGeo, coreMat);
                
                const ringGeo = new THREE.TorusGeometry(22, 0.5, 16, 100);
                const ringMat = new THREE.MeshBasicMaterial({ color: '#00ffcc', transparent: true, opacity: 0.5 });
                const ring = new THREE.Mesh(ringGeo, ringMat);
                
                // Add a glowing sprite inside
                const glowMat = new THREE.SpriteMaterial({ color: '#00ffff', transparent: true, opacity: 0.3, blending: THREE.AdditiveBlending });
                const glow = new THREE.Sprite(glowMat);
                glow.scale.set(40, 40, 1);
                
                group.add(core);
                group.add(ring);
                group.add(glow);

                // Animation hook attached directly to the object
                group.__userData = { 
                    animate: () => {
                        core.rotation.x += 0.01;
                        core.rotation.y += 0.02;
                        ring.rotation.x -= 0.01;
                        ring.rotation.z -= 0.005;
                    } 
                };
                return group;
            } else {
                // Agent Nodes: Floating Octahedrons
                const group = new THREE.Group();
                
                const geo = new THREE.OctahedronGeometry(4, 0);
                const mat = new THREE.MeshBasicMaterial({ color: '#ff00ff', wireframe: true, transparent: true, opacity: 0.8 });
                const mesh = new THREE.Mesh(geo, mat);
                
                // Add a small core glow
                const glowMat = new THREE.SpriteMaterial({ color: '#ff00ff', transparent: true, opacity: 0.5, blending: THREE.AdditiveBlending });
                const glow = new THREE.Sprite(glowMat);
                glow.scale.set(10, 10, 1);
                
                group.add(mesh);
                group.add(glow);

                group.__userData = { 
                    animate: () => {
                        mesh.rotation.y += 0.05;
                        mesh.rotation.z += 0.02;
                    } 
                };
                return group;
            }
        });

    // Particle settings for emitParticle() calls
    swarmGraph.linkDirectionalParticleWidth(2);
    swarmGraph.linkDirectionalParticleSpeed(0.015);
    swarmGraph.linkDirectionalParticleColor(link => link.color);

    // Global Animation Loop for custom node rotations + Camera orbiting
    let angle = 0;
    setInterval(() => {
        if (!swarmGraph) return;

        // Animate custom 3D objects
        const nodes = swarmGraph.graphData().nodes;
        nodes.forEach(n => {
            if (n.__threeObj && n.__threeObj.__userData && n.__threeObj.__userData.animate) {
                n.__threeObj.__userData.animate();
            }
        });

        // Rotate camera slowly like a galaxy
        swarmGraph.cameraPosition({
            x: 600 * Math.sin(angle),
            z: 600 * Math.cos(angle)
        });
        angle += Math.PI / 1200;
    }, 16); // ~60 FPS
}

function updateUI(agentId, action, category) {
    totalPackets++;
    document.getElementById('swarm-agent-count').innerText = connectedAgents.size;
    document.getElementById('swarm-link-count').innerText = connectedAgents.size * 2;
    document.getElementById('swarm-packet-count').innerText = totalPackets;

    // Update Terminal Feed
    const logEl = document.getElementById('swarm-terminal-log');
    if (logEl) {
        const time = new Date().toLocaleTimeString('en-US', { hour12: false });
        const colorCls = action === 'write' ? 'log-action write' : 'log-action read';
        
        const entry = document.createElement('div');
        entry.className = 'log-entry';
        entry.innerHTML = `
            <span class="log-time">[${time}]</span>
            <span class="log-agent">${agentId}</span> 
            <span class="log-action" style="color: ${action==='write'?'#ffaa00':'#00ffff'}">>> ${action.toUpperCase()}</span> 
            <span style="color:rgba(255,255,255,0.4)">(${category || 'general'})</span>
        `;
        
        logEl.prepend(entry);
        if (logEl.children.length > 50) logEl.removeChild(logEl.lastChild);
    }
}

function ensureAgentExists(agentId) {
    if (connectedAgents.has(agentId)) return true;

    // Create the node
    const newNode = { id: agentId, name: `Agent: ${agentId}`, group: 2, val: 10 };
    
    // We create TWO invisible tracks for particles: 
    // 1. Hive -> Agent (for reads)
    // 2. Agent -> Hive (for writes)
    const readTrack = { source: HIVE_NODE_ID, target: agentId, id: `read-${agentId}`, color: '#00ffff' };
    const writeTrack = { source: agentId, target: HIVE_NODE_ID, id: `write-${agentId}`, color: '#ffaa00' };

    // Update Graph Data ONCE per new agent.
    const { nodes, links } = swarmGraph.graphData();
    swarmGraph.graphData({
        nodes: [...nodes, newNode],
        links: [...links, readTrack, writeTrack]
    });

    connectedAgents.set(agentId, { readId: readTrack.id, writeId: writeTrack.id });

    // Add to left panel list
    const listEl = document.getElementById('swarm-agent-list');
    if (listEl) {
        const li = document.createElement('div');
        li.className = 'agent-item';
        li.innerHTML = `<span class="agent-icon">⬡</span> ${agentId}`;
        listEl.appendChild(li);
    }

    return false; // Tells the caller it was just created
}

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

    // Ensure agent exists in graph
    ensureAgentExists(agentId);

    // Update Dashboard DOM
    updateUI(agentId, action, category);

    // ZERO-LAG TELEMETRY: We do NOT update the graphData array.
    // We simply find the specific invisible track link and shoot a particle down it!
    const { links } = swarmGraph.graphData();
    const trackId = action === 'read' ? `read-${agentId}` : `write-${agentId}`;
    const link = links.find(l => l.id === trackId);
    
    if (link) {
        swarmGraph.emitParticle(link);
    }
}

document.addEventListener('DOMContentLoaded', () => {
    document.querySelectorAll('.nav-link').forEach(link => {
        link.addEventListener('click', (e) => {
            const tabId = e.currentTarget.getAttribute('data-tab');
            if (tabId === 'swarm') {
                // Ensure the container is fully visible before initializing
                setTimeout(initSwarmGraph, 200);
            }
        });
    });
});

window.handleSwarmTelemetry = handleTelemetryEvent;
