import * as d3 from 'https://esm.sh/d3@7';

let simulation;

export function mount(containerId, data, dotNetHelper) {
    const container = document.getElementById(containerId);
    if (!container) return;

    const width = container.clientWidth || 400;
    const height = container.clientHeight || 400;

    // Create SVG
    const svg = d3.select(container).append("svg")
        .attr("viewBox", [0, 0, width, height])
        .attr("width", "100%")
        .attr("height", "100%");

    // Radial gradient for Nebula effect
    const defs = svg.append("defs");
    const radialGradient = defs.append("radialGradient")
        .attr("id", "nebulaGlow")
        .attr("cx", "50%")
        .attr("cy", "50%")
        .attr("r", "50%");
    radialGradient.append("stop").attr("offset", "0%").attr("stop-color", "var(--nexus-neon)").attr("stop-opacity", 1);
    radialGradient.append("stop").attr("offset", "100%").attr("stop-color", "var(--nexus-neon)").attr("stop-opacity", 0);

    // Root Group for Zoom
    const rootGroup = svg.append("g").attr("class", "zoom-containment");

    // Attach Zoom Behavior
    const zoom = d3.zoom()
        .scaleExtent([0.5, 4])
        .on("zoom", (e) => rootGroup.attr("transform", e.transform));
    svg.call(zoom);

    // Subtle Link Distance & Charge
    simulation = d3.forceSimulation(data.nodes)
        .force("link", d3.forceLink(data.links).id(d => d.id).distance(60))
        .force("charge", d3.forceManyBody().strength(-150))
        .force("center", d3.forceCenter(width / 2, height / 2))
        .force("collide", d3.forceCollide().radius(25));

    // Links
    const link = rootGroup.append("g")
        .selectAll("line")
        .data(data.links)
        .join("line")
        .attr("stroke", "#444")
        .attr("stroke-opacity", 0.6)
        .attr("stroke-width", 1.5);

    // Nodes
    const node = rootGroup.append("g")
        .selectAll("g")
        .data(data.nodes)
        .join("g")
        .style("cursor", "pointer")
        .on("click", (e, d) => {
            // Remove active state from all, add to clicked
            node.select("circle.node-core").classed("nexus-node-active", false);
            d3.select(e.currentTarget).select("circle.node-core").classed("nexus-node-active", true);
            dotNetHelper.invokeMethodAsync('OnNodeClicked', d.id);
        })
        .call(drag(simulation));

    // Outer glow for nodes
    node.append("circle")
        .attr("r", 14)
        .attr("fill", "url(#nebulaGlow)")
        .attr("opacity", 0.4);

    // Core circle
    node.append("circle")
        .attr("class", "node-core")
        .attr("r", 6)
        .attr("fill", "#888")
        .attr("stroke", "#222")
        .attr("stroke-width", 2);

    // Labels
    node.append("text")
        .text(d => d.label)
        .attr("x", 12)
        .attr("y", 4)
        .attr("fill", "#ccc")
        .attr("font-family", "var(--nexus-font-sans)")
        .attr("font-size", "0.75rem");

    simulation.on("tick", () => {
        link
            .attr("x1", d => d.source.x)
            .attr("y1", d => d.source.y)
            .attr("x2", d => d.target.x)
            .attr("y2", d => d.target.y);

        node.attr("transform", d => `translate(${d.x},${d.y})`);
    });
}

function drag(simulation) {
    function dragstarted(event) {
        if (!event.active) simulation.alphaTarget(0.3).restart();
        event.subject.fx = event.subject.x;
        event.subject.fy = event.subject.y;
    }
    function dragged(event) {
        event.subject.fx = event.x;
        event.subject.fy = event.y;
    }
    function dragended(event) {
        if (!event.active) simulation.alphaTarget(0);
        event.subject.fx = null;
        event.subject.fy = null;
    }
    return d3.drag()
        .on("start", dragstarted)
        .on("drag", dragged)
        .on("end", dragended);
}

export function unmount(containerId) {
    if (simulation) {
        simulation.stop();
    }
    const container = document.getElementById(containerId);
    if (container) {
        container.innerHTML = ''; // clear svg
    }
}

export function scrollToNode(id) {
    const el = document.getElementById(id);
    if (el) {
        el.scrollIntoView({ behavior: 'smooth', block: 'center' });
    }
}

export function pause() {
    if (simulation) {
        simulation.stop();
    }
}

export function resume() {
    if (simulation) {
        // give it a gentle kick to settle if moved
        simulation.alphaTarget(0.1).restart();
    }
}
