let currentGraphData = null;
let currentTraversingNode = null;
let resourceUrl = "";
let sandboxLoaded = false;
let buildStarted = false;
let elementPopup = null; // 用于跟踪当前打开的弹窗

// 拖动调整面板宽度功能
document.addEventListener('DOMContentLoaded', function() {
    const resizer1 = document.getElementById('resizer-1');
    const resizer2 = document.getElementById('resizer-2');
    const uiMapPanel = document.getElementById('ui-map-panel');
    const sandboxPanel = document.getElementById('sandbox-panel');
    const detailsPanel = document.getElementById('details-panel');
    const content = document.querySelector('.content');
    
    let isResizing = false;
    let currentResizer = null;
    let startX = 0;
    let startWidths = {};
    
    function initResize(e, resizer) {
        isResizing = true;
        currentResizer = resizer;
        startX = e.clientX;
        
        // 记录初始宽度
        startWidths.uiMap = uiMapPanel.offsetWidth;
        startWidths.sandbox = sandboxPanel.offsetWidth;
        startWidths.details = detailsPanel.offsetWidth;
        
        // 禁用用户选择
        document.body.style.userSelect = 'none';
        document.body.style.cursor = 'col-resize';
    }
    
    function resize(e) {
        if (!isResizing) return;
        
        const dx = e.clientX - startX;
        
        if (currentResizer === resizer1) {
            // 调整UI Map和Remote Sandbox之间的宽度
            const newUiMapWidth = startWidths.uiMap + dx;
            const newSandboxWidth = startWidths.sandbox - dx;
            
            // 确保最小宽度
            if (newUiMapWidth > 200 && newSandboxWidth > 200) {
                uiMapPanel.style.flex = `0 0 ${newUiMapWidth}px`;
                sandboxPanel.style.flex = `0 0 ${newSandboxWidth}px`;
            }
        } else if (currentResizer === resizer2) {
            // 调整Remote Sandbox和Node Details之间的宽度
            const newSandboxWidth = startWidths.sandbox + dx;
            const newDetailsWidth = startWidths.details - dx;
            
            // 确保最小宽度
            if (newSandboxWidth > 200 && newDetailsWidth > 200) {
                sandboxPanel.style.flex = `0 0 ${newSandboxWidth}px`;
                detailsPanel.style.flex = `0 0 ${newDetailsWidth}px`;
            }
        }
    }
    
    function stopResize() {
        isResizing = false;
        document.body.style.userSelect = '';
        document.body.style.cursor = '';
    }
    
    // 为调整器添加事件监听器
    resizer1.addEventListener('mousedown', (e) => initResize(e, resizer1));
    resizer2.addEventListener('mousedown', (e) => initResize(e, resizer2));
    
    document.addEventListener('mousemove', resize);
    document.addEventListener('mouseup', stopResize);
});

// Function to update the visualization
function updateVisualization() {
    fetch('/data')
        .then(response => response.json())
        .then(graphData => {
            // Check if there's a current traversing node
            if (graphData.current_traversing_node !== undefined) {
                currentTraversingNode = graphData.current_traversing_node;
                // Remove the special field to avoid issues with rendering
                delete graphData.current_traversing_node;
            }
            currentGraphData = graphData;
            renderGraph(graphData);
            updateStats(graphData);
            
            // Load sandbox only once
            if (!sandboxLoaded && graphData.resource_url) {
                resourceUrl = graphData.resource_url;
                document.getElementById('sandbox-iframe').src = resourceUrl;
                sandboxLoaded = true;
                // Enable start button when sandbox is loaded
                document.getElementById('start-build-btn').disabled = false;
            }
        })
        .catch(error => {
            console.error('Error loading graph data:', error);
        });
}

// Navigate back function
function navigateBack() {
    const backButton = document.getElementById('navigate-back-btn');
    const homeButton = document.getElementById('go-home-btn');
    
    // Disable buttons during request
    backButton.disabled = true;
    homeButton.disabled = true;
    backButton.textContent = "Executing...";
    
    fetch('/navigate_back', {method: 'POST'})
        .then(response => response.json())
        .then(data => {
            if (data.success) {
                console.log('Navigate back successful:', data.message);
            } else {
                console.error('Navigate back failed:', data.error);
            }
            // Re-enable buttons
            backButton.disabled = false;
            homeButton.disabled = false;
            backButton.textContent = "Navigate Back";
        })
        .catch(error => {
            console.error('Error during navigate back:', error);
            // Re-enable buttons
            backButton.disabled = false;
            homeButton.disabled = false;
            backButton.textContent = "Navigate Back";
        });
}

// Go home function
function goHome() {
    const backButton = document.getElementById('navigate-back-btn');
    const homeButton = document.getElementById('go-home-btn');
    
    // Disable buttons during request
    backButton.disabled = true;
    homeButton.disabled = true;
    homeButton.textContent = "Executing...";
    
    fetch('/go_home', {method: 'POST'})
        .then(response => response.json())
        .then(data => {
            if (data.success) {
                console.log('Go home successful:', data.message);
            } else {
                console.error('Go home failed:', data.error);
            }
            // Re-enable buttons
            backButton.disabled = false;
            homeButton.disabled = false;
            homeButton.textContent = "Go Home";
        })
        .catch(error => {
            console.error('Error during go home:', error);
            // Re-enable buttons
            backButton.disabled = false;
            homeButton.disabled = false;
            homeButton.textContent = "Go Home";
        });
}

// Start build function
function startBuild() {
    // Get configuration values
    const maxDepth = document.getElementById('max-depth').value;
    
    // Update configuration on server
    fetch('/update_config', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
        },
        body: JSON.stringify({
            max_depth: maxDepth
        })
    })
    .then(response => response.json())
    .then(configData => {
        if (configData.success) {
            console.log('Configuration updated:', configData.message);
            
            // Disable start button and update status
            document.getElementById('start-build-btn').disabled = true;
            document.getElementById('status-indicator').className = 'status-indicator status-building';
            document.getElementById('status-indicator').textContent = 'Building UI map...';
            buildStarted = true;
            
            // Send start build request
            fetch('/start_build', {method: 'POST'})
                .then(response => response.json())
                .then(data => {
                    if (data.success) {
                        console.log('Build started:', data.message);
                    } else {
                        console.error('Failed to start build:', data.error);
                        // Re-enable button on error
                        document.getElementById('start-build-btn').disabled = false;
                        document.getElementById('status-indicator').className = 'status-indicator status-ready';
                        document.getElementById('status-indicator').textContent = 'Ready to start building';
                        buildStarted = false;
                    }
                })
                .catch(error => {
                    console.error('Error during start build:', error);
                    // Re-enable button on error
                    document.getElementById('start-build-btn').disabled = false;
                    document.getElementById('status-indicator').className = 'status-indicator status-ready';
                    document.getElementById('status-indicator').textContent = 'Ready to start building';
                    buildStarted = false;
                });
        } else {
            console.error('Failed to update configuration:', configData.error);
        }
    })
    .catch(error => {
        console.error('Error updating configuration:', error);
    });
}

// Update visualization every 5 seconds
setInterval(updateVisualization, 5000);

// Initial load
updateVisualization();

function updateStats(graphData) {
    document.getElementById('node-count').textContent = Object.keys(graphData.nodes).length;
    document.getElementById('edge-count').textContent = graphData.edges.length;
}

function renderGraph(graphData) {
    const svg = d3.select("#ui-map-svg");
    const container = d3.select(".visualization-container");
    const width = container.node().getBoundingClientRect().width;
    const height = container.node().getBoundingClientRect().height - 48; // Subtract header height
    
    // Clear previous content
    svg.selectAll("*").remove();
    
    // Create a list of all unique nodes from the nodes object
    const allNodes = {};
    Object.values(graphData.nodes).forEach(node => {
        allNodes[node.node_id] = node;
    });
    
    // Create links from edges
    const links = graphData.edges.map(edge => ({
        source: allNodes[edge.source_id],
        target: allNodes[edge.target_id],
        action: edge.action
    })).filter(link => link.source && link.target); // Filter out invalid links
    
    // Convert to array format for d3
    const nodes = Object.values(allNodes);
    
    // Set up the simulation
    const simulation = d3.forceSimulation(nodes)
        .force("link", d3.forceLink(links).id(d => d.node_id).distance(150))
        .force("charge", d3.forceManyBody().strength(-200))
        .force("center", d3.forceCenter(width / 2, height / 2))
        .force("collision", d3.forceCollide().radius(30));
    
    // Create container for zooming and panning
    const g = svg.append("g");
    
    // Add zoom functionality
    const zoom = d3.zoom()
        .scaleExtent([0.1, 8])
        .on("zoom", (event) => {
            g.attr("transform", event.transform);
        });
    
    svg.call(zoom);
    
    // Draw links
    const link = g.append("g")
        .selectAll("line")
        .data(links)
        .enter()
        .append("line")
        .attr("class", "link")
        .attr("stroke", "#999")
        .attr("stroke-width", 2)
        .attr("marker-end", "url(#arrowhead)")
        .on("click", function(event, d) {
            showEdgeDetails(d);
        });
    
    // Add arrowhead markers
    svg.append("defs").append("marker")
        .attr("id", "arrowhead")
        .attr("viewBox", "-0 -5 10 10")
        .attr("refX", 25)
        .attr("refY", 0)
        .attr("orient", "auto")
        .attr("markerWidth", 10)
        .attr("markerHeight", 10)
        .attr("xoverflow", "visible")
        .append("svg:path")
        .attr("d", "M 0,-5 L 10,0 L 0,5")
        .attr("fill", "#999")
        .attr("stroke", "none");
    
    // Draw nodes
    const node = g.append("g")
        .selectAll("circle")
        .data(nodes)
        .enter()
        .append("circle")
        .attr("class", "node")
        .attr("r", d => 25)
        .attr("fill", d => {
            // If this is the current traversing node, color it orange
            if (currentTraversingNode && d.node_id === currentTraversingNode) {
                return "#FFA500"; // Orange color
            }
            return "#4CAF50"; // Default green color
        })
        .attr("stroke", "#fff")
        .attr("stroke-width", 2)
        .call(d3.drag()
            .on("start", dragstarted)
            .on("drag", dragged)
            .on("end", dragended)
        )
        .on("click", function(event, d) {
            showNodeDetails(d);
        });
    
    // Add labels
    const label = g.append("g")
        .selectAll("text")
        .data(nodes)
        .enter()
        .append("text")
        .attr("class", "node-label")
        .attr("text-anchor", "middle")
        .attr("dy", 5)
        .text(d => d.node_id.substring(0, 6))
        .attr("font-size", "10px")
        .attr("fill", "#000");
    
    // Update positions on each tick
    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("cx", d => d.x)
            .attr("cy", d => d.y);
        
        label
            .attr("x", d => d.x)
            .attr("y", d => d.y);
    });
    
    // Drag functions
    function dragstarted(event, d) {
        if (!event.active) simulation.alphaTarget(0.3).restart();
        d.fx = d.x;
        d.fy = d.y;
    }
    
    function dragged(event, d) {
        d.fx = event.x;
        d.fy = event.y;
    }
    
    function dragended(event, d) {
        if (!event.active) simulation.alphaTarget(0);
        d.fx = null;
        d.fy = null;
    }
    
    // Show node details
    function showNodeDetails(node) {
        const detailsContent = document.getElementById("details-content");
        detailsContent.innerHTML = `
            <div class="node-info-header">
                <h3>Node Information</h3>
                <p><strong>ID:</strong> ${node.node_id}</p>
                <p><strong>Elements:</strong> ${node.elements.length}</p>
            </div>
            <h4>Page Visualization:</h4>
            <div class="page-visualization-container">
                <div class="page-visualization" id="page-visualization"></div>
            </div>
            <h4>Elements Hierarchy:</h4>
            <div class="elements-hierarchy" id="elements-hierarchy"></div>
        `;
        
        // Render the page visualization
        renderPageVisualization(node);
        
        // Render elements hierarchy
        renderElementsHierarchy(node.elements, 'elements-hierarchy');
    }
    
    // Show edge details
    function showEdgeDetails(edge) {
        const detailsContent = document.getElementById("details-content");
        detailsContent.innerHTML = `
            <h3>Transition Information</h3>
            <div class="page-comparison-vertical">
                <div class="page-container">
                    <h4>Source: ${edge.source.node_id.substring(0, 8)}</h4>
                    <div class="page-visualization source-page" id="source-page"></div>
                </div>
                <div class="page-container">
                    <h4>Target: ${edge.target.node_id.substring(0, 8)}</h4>
                    <div class="page-visualization target-page" id="target-page"></div>
                </div>
                <div class="action-details">
                    <h4>Action Details</h4>
                    <p><strong>Text:</strong> ${edge.action.element_text || 'N/A'}</p>
                    <p><strong>Class:</strong> ${edge.action.element_class || 'N/A'}</p>
                    <p><strong>Tap:</strong> (${edge.action.tap_x || 'N/A'}, ${edge.action.tap_y || 'N/A'})</p>
                </div>
            </div>
        `;
        
        // Render both pages
        renderPageVisualization(edge.source, 'source-page');
        renderPageVisualization(edge.target, 'target-page');
        
        // Add tap position indicator on source page after a short delay
        setTimeout(() => {
            if (edge.action.tap_x !== undefined && edge.action.tap_y !== undefined) {
                const sourcePage = document.querySelector('.source-page');
                if (sourcePage) {
                    // Add tap indicator
                    const tapIndicator = document.createElement('div');
                    tapIndicator.className = 'tap-indicator';
                    tapIndicator.style.left = `${(edge.action.tap_x / 1080) * 100}%`;
                    tapIndicator.style.top = `${(edge.action.tap_y / 1920) * 100}%`;
                    sourcePage.appendChild(tapIndicator);
                }
            }
        }, 100);
    }
    
    // Render page visualization
    function renderPageVisualization(node, containerId = 'page-visualization') {
        const container = document.getElementById(containerId);
        if (!container) return;
        
        // Clear previous content
        container.innerHTML = '';
        
        // Set larger page dimensions to better utilize available space
        // Use responsive sizing based on container width
        const containerWidth = container.parentElement.clientWidth;
        const maxWidth = Math.min(containerWidth - 20, 700); // Increased max width
        const pageWidth = maxWidth;
        const pageHeight = Math.min(maxWidth * 2.0, 800); // Increased height proportionally and absolutely
        
        container.style.width = `${pageWidth}px`;
        container.style.height = `${pageHeight}px`;
        container.style.position = 'relative';
        container.style.border = '1px solid #e0e5ff';
        container.style.backgroundColor = '#ffffff';
        container.style.overflow = 'hidden';
        container.style.margin = '0 auto';
        container.style.borderRadius = '8px';
        
        // Process each UI element
        if (node.elements && Array.isArray(node.elements) && node.elements.length > 0) {
            node.elements.forEach(element => {
                createElementFromData(element, container, pageWidth, pageHeight);
            });
        }
    }
    
    // Helper function to check if an element is clickable
    function isElementClickable(elementObj) {
        // Only consider elements with type "clickable" as clickable
        return elementObj.type === 'clickable';
    }
    
    // Helper function to create an element from data
    function createElementFromData(elementObj, parentContainer, pageWidth, pageHeight) {
        // Extract bounds
        const bounds = elementObj.bounds;
        if (!bounds) {
            // Skip elements without bounds
            return;
        }
        
        // Parse bounds (format: "x1,y1,x2,y2")
        const coords = bounds.split(',').map(coord => parseInt(coord.trim(), 10));
        if (coords.length !== 4 || coords.some(isNaN)) {
            console.warn('Invalid bounds format:', bounds);
            return;
        }
        
        const [x1, y1, x2, y2] = coords;
        // Scale coordinates to fit visualization (assuming 1080x1920 screen)
        const width = (x2 - x1) * (pageWidth / 1080);
        const height = (y2 - y1) * (pageHeight / 1920);
        const left = x1 * (pageWidth / 1080);
        const top = y1 * (pageHeight / 1920);
        
        // Skip elements that are too small to be visible
        if (width < 2 || height < 2) {
            return;
        }
        
        // Create element visualization
        const elementDiv = document.createElement('div');
        elementDiv.className = 'page-element';
        elementDiv.style.position = 'absolute';
        elementDiv.style.left = `${left}px`;
        elementDiv.style.top = `${top}px`;
        elementDiv.style.width = `${width}px`;
        elementDiv.style.height = `${height}px`;
        
        // Style based on element type
        if (elementObj.className) {
            if (elementObj.className.includes('TextView')) {
                elementDiv.style.backgroundColor = '#e3f2fd';
                elementDiv.style.border = '1px solid #2196f3';
            } else if (elementObj.className.includes('ImageView')) {
                elementDiv.style.backgroundColor = '#fce4ec';
                elementDiv.style.border = '1px solid #e91e63';
            } else if (elementObj.className.includes('Button')) {
                elementDiv.style.backgroundColor = '#e8f5e9';
                elementDiv.style.border = '1px solid #4caf50';
            } else {
                elementDiv.style.backgroundColor = '#ffffff';
                elementDiv.style.border = '1px solid #9e9e9e';
            }
        } else {
            elementDiv.style.backgroundColor = '#ffffff';
            elementDiv.style.border = '1px solid #9e9e9e';
        }
        
        // Use the element's own text, resourceId, or className
        let displayText = elementObj.text || elementObj.resourceId || elementObj.className || '';
        
        // Add text if available
        if (displayText) {
            // Improved font size calculation for better visibility
            const minFontSize = 10; // Increased minimum font size
            const maxFontSize = 24; // Increased maximum font size
            
            // Calculate font size based on the smaller dimension to fit text better
            const baseSize = Math.min(width, height);
            let fontSize = Math.max(minFontSize, Math.min(maxFontSize, baseSize / 2)); // Adjusted scaling factor
            
            // Special handling for very wide but short elements (like bars/headers)
            if (width > height * 3) {
                fontSize = Math.max(minFontSize, Math.min(maxFontSize, height * 0.8));
            }
            
            // Special handling for very tall but narrow elements
            if (height > width * 3) {
                fontSize = Math.max(minFontSize, Math.min(maxFontSize, width * 0.8));
            }
            
            elementDiv.style.fontSize = `${fontSize}px`;
            elementDiv.style.padding = '1px';
            elementDiv.style.overflow = 'hidden';
            elementDiv.style.textOverflow = 'ellipsis';
            elementDiv.style.whiteSpace = 'nowrap';
            elementDiv.style.textAlign = 'center';
            elementDiv.style.display = 'flex';
            elementDiv.style.alignItems = 'center';
            elementDiv.style.justifyContent = 'center';
            elementDiv.style.boxSizing = 'border-box';
            
            // Adaptive text length based on both width and font size
            // Using a character width estimate of ~0.6 * font size
            const charWidth = fontSize * 0.6;
            const maxChars = Math.max(1, Math.floor(width / charWidth));
            elementDiv.textContent = displayText.substring(0, maxChars);
            
            // Set title attribute for browser's default tooltip with full text
            elementDiv.title = displayText;
        }
        
        // Add full details for custom tooltip
        const fullDetails = `${elementObj.className || 'Element'}<br>Text: ${displayText || 'N/A'}<br>Resource ID: ${elementObj.resourceId || 'N/A'}<br>Bounds: ${bounds}`;
        
        // Add click event listener to show element details
        elementDiv.addEventListener('click', function(e) {
            e.stopPropagation();
            showElementDetails(elementObj, e);
        });
        
        // Add hover event listeners for enhanced tooltip
        elementDiv.addEventListener('mouseenter', function(e) {
            showTooltip(e, fullDetails);
        });
        
        elementDiv.addEventListener('mouseleave', function() {
            hideTooltip();
        });
        
        elementDiv.addEventListener('mousemove', function(e) {
            updateTooltipPosition(e);
        });
        
        parentContainer.appendChild(elementDiv);
        
        // Add clickable indicator if element type is explicitly "clickable"
        // Only show green dot for elements with "type": "clickable"
        if (elementObj.type === 'clickable') {
            const clickableIndicator = document.createElement('div');
            clickableIndicator.className = 'clickable-indicator';
            clickableIndicator.style.position = 'absolute';
            clickableIndicator.style.right = '-3px';
            clickableIndicator.style.top = '-3px';
            clickableIndicator.style.width = '8px';
            clickableIndicator.style.height = '8px';
            clickableIndicator.style.backgroundColor = '#4CAF50';
            clickableIndicator.style.border = '1px solid white';
            clickableIndicator.style.borderRadius = '50%';
            clickableIndicator.style.pointerEvents = 'none';
            clickableIndicator.title = 'Clickable element';
            elementDiv.appendChild(clickableIndicator);
        }
        
        // Process children elements recursively
        // Now we show all children regardless of their clickable status
        if (elementObj.children && Array.isArray(elementObj.children) && elementObj.children.length > 0) {
            elementObj.children.forEach(child => {
                createElementFromData(child, parentContainer, pageWidth, pageHeight);
            });
        }
    }
    
    // Render elements hierarchy
    function renderElementsHierarchy(elements, containerId) {
        const container = document.getElementById(containerId);
        if (!container) return;
        
        const ul = document.createElement('ul');
        ul.className = 'elements-tree';
        
        function createTreeElement(element) {
            const li = document.createElement('li');
            const elementInfo = `${element.className || 'Element'}: ${element.text || 'No text'}`;
            li.textContent = elementInfo;
            
            // Add clickable indicator in the tree if element is clickable
            if (isElementClickable(element)) {
                const clickableMark = document.createElement('span');
                clickableMark.textContent = ' (clickable)';
                clickableMark.style.color = '#4CAF50';
                clickableMark.style.fontWeight = 'bold';
                li.appendChild(clickableMark);
            }
            
            if (element.children && Array.isArray(element.children) && element.children.length > 0) {
                const childUl = document.createElement('ul');
                element.children.forEach(child => {
                    childUl.appendChild(createTreeElement(child));
                });
                li.appendChild(childUl);
            }
            
            return li;
        }
        
        elements.forEach(element => {
            ul.appendChild(createTreeElement(element));
        });
        
        container.appendChild(ul);
    }
    
    // Tooltip functions
    function showTooltip(e, content) {
        // Create or update tooltip
        let tooltip = document.getElementById('element-tooltip');
        if (!tooltip) {
            tooltip = document.createElement('div');
            tooltip.id = 'element-tooltip';
            tooltip.style.position = 'fixed';
            tooltip.style.backgroundColor = 'rgba(0, 0, 0, 0.9)';
            tooltip.style.color = 'white';
            tooltip.style.padding = '8px';
            tooltip.style.borderRadius = '4px';
            tooltip.style.fontSize = '12px';
            tooltip.style.zIndex = '1000';
            tooltip.style.maxWidth = '200px';
            tooltip.style.wordWrap = 'break-word';
            document.body.appendChild(tooltip);
        }
        
        tooltip.innerHTML = content;
        updateTooltipPosition(e);
        tooltip.style.display = 'block';
    }
    
    function hideTooltip() {
        const tooltip = document.getElementById('element-tooltip');
        if (tooltip) {
            tooltip.style.display = 'none';
        }
    }
    
    function updateTooltipPosition(e) {
        const tooltip = document.getElementById('element-tooltip');
        if (tooltip) {
            tooltip.style.left = (e.pageX + 10) + 'px';
            tooltip.style.top = (e.pageY - 10) + 'px';
        }
    }
}