<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <title>ER Diagram</title>
    <!-- Include d3.js -->
    <script src="https://d3js.org/d3.v6.min.js"></script>
    <style>
        body {
            margin: 0;
        }

        .table {
            font-family: Arial, sans-serif;
            font-size: 14px;
            cursor: pointer;
        }

        .table-name {
            font-weight: bold;
            font-size: 16px;
        }

        .foreign-key {
            fill: #b30000;
        }

        .link {
            stroke: #999;
            stroke-opacity: 0.6;
            stroke-width: 2px;
            fill: none;
        }

        .link-curved-path {
            pointer-events: none;
        }
    </style>
</head>

<body>
    <div id="er-diagram"></div>
    <script>
        // Generate ER diagram
        const tables = {{tables}};
        const links = {{links}};

        const width = window.innerWidth;
        const height = window.innerHeight;

        const tableElemWidth = 120;
        const tableElemHeight = d => 20 * (d.columns.length + 1);

        let svg = d3.select("#er-diagram")
            .append("svg")
            .attr("width", width)
            .attr("height", height);

        let g = svg.append("g");

        let linkGroup = g.selectAll(".link")
            .data(links)
            .join("path")
            .attr("class", "link");

        let tableGroup = g.selectAll(".table")
            .data(tables)
            .join("g")
            .attr("class", "table")
            .classed("collapsed", false)
            .on("click", (event, d) => {
                d3.select(event.currentTarget).classed("collapsed", !d3.select(event.currentTarget).classed("collapsed"));
            });

        let zoomBehavior = d3.zoom()
            .scaleExtent([0.1, 4])
            .on("zoom", function (event) {
                g.attr("transform", event.transform);
            });

        svg.call(zoomBehavior);

        let rect = tableGroup.append("rect")
            .attr("width", tableElemWidth)
            .attr("height", tableElemHeight)
            .attr("fill", "#eee");

        let text = tableGroup.append("text")
            .attr("class", "table-name")
            .attr("x", 10)
            .attr("y", 20)
            .text(d => d.name);

        let columnText = tableGroup.selectAll(".column")
            .data(d => d.columns.map(col => ({name: col, is_foreign_key: d.foreign_keys.some(fk => fk.from === col)})))
            .join("text")
            .attr("class", d => d.is_foreign_key ? "column foreign-key" : "column")
            .attr("x", 10)
            .attr("y", (d, i) => 40 + i * 20)
            .text(d => d.name);

        // Physics simulation and force layout
        let simulation = d3.forceSimulation(tables)
            .force("link", d3.forceLink(links).id(d => d.name).distance(200))
            .force("charge", d3.forceManyBody().strength(-800))
            .force("x", d3.forceX(width / 2).strength(0.1))
            .force("y", d3.forceY(height / 2).strength(0.1))
            .on("tick", () => {
                tableGroup.attr("transform", d => `translate(${d.x}, ${d.y})`);
                linkGroup.attr("d", d => {
                    const srcX = d.source.x + tableElemWidth;
                    const srcY = d.source.y + 40 + d.source.columns.findIndex(c => c === d.source_col) * 20;
                    const tgtX = d.target.x;
                    const tgtY = d.target.y + 40 + d.target.columns.findIndex(c => c === d.target_col) * 20;
                    const deltaX = tgtX - srcX;
                    const deltaY = tgtY - srcY;
                    const curveFactor = 50;
                    const curveY = deltaY < 0 ? -curveFactor : curveFactor;
                    return `M${srcX},${srcY}C${srcX + deltaX / 2},${srcY + curveY} ${tgtX - deltaX / 2},${tgtY - curveY} ${tgtX},${tgtY}`;
                });
                columnText.style("display", (d, i, nodes) => {
                    return d3.select(nodes[i].parentNode).classed("collapsed") ? "none" : null;
                });
            });
    </script>
</body>

</html>
