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

<head>
    <meta charset="UTF-8">
    <title>Transaction Layer Tree</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js"></script>
    <script src="https://d3js.org/d3.v7.min.js"></script>
    <style>
    body {
        font-family: Arial, sans-serif;
    }

    #upload {
        margin: 20px;
    }

    svg {
        border: 1px solid #ccc;
        cursor: grab;
    }

    .node circle {
        fill: steelblue;
        cursor: pointer;
    }

    .node text {
        font-size: 12px;
    }

    .link {
        fill: none;
        stroke: #999;
        stroke-width: 2px;
    }
    </style>
</head>

<body>
    <h2>Transaction Tree Viewer</h2>
    <input type="file" id="upload" />
    <div id="tree"></div>

    <script>
    document.getElementById("upload").addEventListener("change", handleFile, false);

    function handleFile(event) {
        const file = event.target.files[0];
        const reader = new FileReader();

        reader.onload = function(e) {
            const data = new Uint8Array(e.target.result);
            const workbook = XLSX.read(data, {
                type: "array"
            });
            const sheet = workbook.Sheets[workbook.SheetNames[0]];
            const jsonData = XLSX.utils.sheet_to_json(sheet);

            const treeData = buildTree(jsonData);
            drawTree(treeData);
        };

        reader.readAsArrayBuffer(file);
    }

    function buildTree(data) {
        let root = {
            name: "Transactions",
            children: []
        };
        let layerMap = {};
        let counter = 1; // for numbering nodes

        data.forEach(row => {
            const layer = row["Layer"];
            const ack = row["Acknowledgement No."];
            const txnId = row["Transaction Id / UTR Number"];
            const amount = row["Transaction Amount"];
            const bank = row["Bank/FIs"];

            if (!layerMap[layer]) {
                layerMap[layer] = {
                    name: counter++ + " - Layer " + layer,
                    children: []
                };
                root.children.push(layerMap[layer]);
            }

            let ackNode = layerMap[layer].children.find(c => c.original === ack);
            if (!ackNode) {
                ackNode = {
                    name: counter++ + " - Ack: " + ack,
                    original: ack,
                    children: []
                };
                layerMap[layer].children.push(ackNode);
            }

            ackNode.children.push({
                name: counter++ + ` - Txn: ${txnId} (₹${amount}, Bank: ${bank})`
            });
        });

        return root;
    }

    function drawTree(treeData) {
        d3.select("#tree").selectAll("*").remove(); // Clear old

        const width = 1400,
            height = 900;

        const svg = d3.select("#tree").append("svg")
            .attr("width", width)
            .attr("height", height)
            .call(
                d3.zoom().on("zoom", (event) => {
                    g.attr("transform", event.transform);
                })
            )
            .append("g")
            .attr("transform", "translate(50,50)");

        const root = d3.hierarchy(treeData);
        const treeLayout = d3.tree().size([height - 100, width - 300]);
        treeLayout(root);

        // Links
        svg.selectAll(".link")
            .data(root.links())
            .enter().append("path")
            .attr("class", "link")
            .attr("d", d3.linkHorizontal()
                .x(d => d.y)
                .y(d => d.x));

        // Nodes
        const node = svg.selectAll(".node")
            .data(root.descendants())
            .enter().append("g")
            .attr("class", "node")
            .attr("transform", d => `translate(${d.y},${d.x})`);

        node.append("circle")
            .attr("r", 6);

        node.append("text")
            .attr("dy", 3)
            .attr("x", d => d.children ? -10 : 10)
            .style("text-anchor", d => d.children ? "end" : "start")
            .text(d => d.data.name);
    }
    </script>
</body>

</html>