"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MiniMap = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
/**
 * MiniMap Component
 *
 * A miniature view of the workflow builder canvas
 */
const react_1 = require("react");
const prop_types_1 = __importDefault(require("prop-types"));
/**
 * MiniMap component for workflow builder
 * @param {Object} props - Component props
 * @param {Object} props.workflow - Workflow data
 * @param {Object} props.viewport - Current viewport information
 * @param {Function} props.onViewportChange - Viewport change handler
 * @param {number} props.scale - Scale factor for the minimap (default: 0.15)
 * @param {string} props.position - Position of the minimap (default: 'bottom-right')
 * @param {boolean} props.draggable - Whether the minimap can be dragged (default: true)
 * @param {boolean} props.collapsible - Whether the minimap can be collapsed (default: true)
 * @param {boolean} props.defaultCollapsed - Default collapsed state (default: false)
 * @param {string} props.className - Additional CSS classes
 * @param {Object} props.style - Additional inline styles
 * @returns {React.ReactElement} MiniMap component
 */
const MiniMap = ({ workflow = { nodes: [], edges: [] }, viewport = { x: 0, y: 0, zoom: 1, width: 1000, height: 700 }, onViewportChange, scale = 0.15, position = 'bottom-right', draggable = true, collapsible = true, defaultCollapsed = false, className = '', style = {}, ...rest }) => {
    // State
    const [isDragging, setIsDragging] = (0, react_1.useState)(false);
    const [dragStart, setDragStart] = (0, react_1.useState)({ x: 0, y: 0 });
    const [collapsed, setCollapsed] = (0, react_1.useState)(defaultCollapsed);
    const [minimapSize, setMinimapSize] = (0, react_1.useState)({ width: 200, height: 150 });
    // Refs
    const minimapRef = (0, react_1.useRef)(null);
    const viewportRectRef = (0, react_1.useRef)(null);
    // Calculate minimap properties
    (0, react_1.useEffect)(() => {
        if (!workflow.nodes || workflow.nodes.length === 0)
            return;
        // Calculate bounds of all nodes
        let minX = Infinity;
        let minY = Infinity;
        let maxX = -Infinity;
        let maxY = -Infinity;
        workflow.nodes.forEach(node => {
            const nodeLeft = node.position.x;
            const nodeTop = node.position.y;
            const nodeRight = nodeLeft + (node.width || 150);
            const nodeBottom = nodeTop + (node.height || 80);
            minX = Math.min(minX, nodeLeft);
            minY = Math.min(minY, nodeTop);
            maxX = Math.max(maxX, nodeRight);
            maxY = Math.max(maxY, nodeBottom);
        });
        // Add padding
        const padding = 50;
        minX -= padding;
        minY -= padding;
        maxX += padding;
        maxY += padding;
        // Calculate workflow dimensions
        const workflowWidth = maxX - minX;
        const workflowHeight = maxY - minY;
        // Calculate minimap dimensions with aspect ratio
        const maxMinimapWidth = 200;
        const maxMinimapHeight = 150;
        const widthRatio = maxMinimapWidth / workflowWidth;
        const heightRatio = maxMinimapHeight / workflowHeight;
        const adjustedScale = Math.min(widthRatio, heightRatio);
        const minimapWidth = workflowWidth * adjustedScale;
        const minimapHeight = workflowHeight * adjustedScale;
        setMinimapSize({
            width: minimapWidth,
            height: minimapHeight,
            adjustedScale,
            workflowWidth,
            workflowHeight,
            minX,
            minY,
            maxX,
            maxY
        });
    }, [workflow]);
    // Get positioning style
    const getPositionStyle = () => {
        switch (position) {
            case 'top-left':
                return { top: '16px', left: '16px' };
            case 'top-right':
                return { top: '16px', right: '16px' };
            case 'bottom-left':
                return { bottom: '16px', left: '16px' };
            case 'bottom-right':
            default:
                return { bottom: '16px', right: '16px' };
        }
    };
    // Calculate viewport rectangle dimensions
    const getViewportRect = () => {
        if (!minimapSize.adjustedScale)
            return { width: 0, height: 0, x: 0, y: 0 };
        // Calculate viewport rectangle
        const rectWidth = (viewport.width / viewport.zoom) * minimapSize.adjustedScale;
        const rectHeight = (viewport.height / viewport.zoom) * minimapSize.adjustedScale;
        // Calculate position based on viewport center
        const viewportCenterX = viewport.x + (viewport.width / viewport.zoom) / 2;
        const viewportCenterY = viewport.y + (viewport.height / viewport.zoom) / 2;
        // Translate to minimap coordinates
        const rectX = (viewportCenterX - minimapSize.minX) * minimapSize.adjustedScale - rectWidth / 2;
        const rectY = (viewportCenterY - minimapSize.minY) * minimapSize.adjustedScale - rectHeight / 2;
        return {
            width: rectWidth,
            height: rectHeight,
            x: rectX,
            y: rectY
        };
    };
    // Draw nodes on minimap
    const renderNodes = () => {
        if (!workflow.nodes || !minimapSize.adjustedScale)
            return null;
        return workflow.nodes.map(node => {
            // Calculate node position in minimap
            const nodeX = (node.position.x - minimapSize.minX) * minimapSize.adjustedScale;
            const nodeY = (node.position.y - minimapSize.minY) * minimapSize.adjustedScale;
            const nodeWidth = (node.width || 150) * minimapSize.adjustedScale;
            const nodeHeight = (node.height || 80) * minimapSize.adjustedScale;
            // Get node color based on type
            const getNodeColor = () => {
                switch (node.type) {
                    case 'input':
                        return '#6366F1'; // Indigo
                    case 'output':
                        return '#10B981'; // Emerald
                    case 'process':
                        return '#F59E0B'; // Amber
                    case 'decision':
                        return '#EF4444'; // Red
                    default:
                        return '#6B7280'; // Gray
                }
            };
            return ((0, jsx_runtime_1.jsx)("div", { className: `bf-minimap__node bf-minimap__node--${node.type}`, style: {
                    position: 'absolute',
                    left: `${nodeX}px`,
                    top: `${nodeY}px`,
                    width: `${nodeWidth}px`,
                    height: `${nodeHeight}px`,
                    backgroundColor: getNodeColor(),
                    opacity: 0.7,
                    borderRadius: '2px'
                } }, node.id));
        });
    };
    // Draw edges on minimap
    const renderEdges = () => {
        if (!workflow.edges || !minimapSize.adjustedScale)
            return null;
        // Create an SVG element for edges
        return ((0, jsx_runtime_1.jsx)("svg", { className: "bf-minimap__edges", style: {
                position: 'absolute',
                top: 0,
                left: 0,
                width: '100%',
                height: '100%',
                pointerEvents: 'none'
            }, children: workflow.edges.map(edge => {
                // Find source and target nodes
                const sourceNode = workflow.nodes.find(node => node.id === edge.source);
                const targetNode = workflow.nodes.find(node => node.id === edge.target);
                if (!sourceNode || !targetNode)
                    return null;
                // Calculate edge coordinates
                const sourceX = (sourceNode.position.x - minimapSize.minX + (sourceNode.width || 150) / 2) * minimapSize.adjustedScale;
                const sourceY = (sourceNode.position.y - minimapSize.minY + (sourceNode.height || 80) / 2) * minimapSize.adjustedScale;
                const targetX = (targetNode.position.x - minimapSize.minX + (targetNode.width || 150) / 2) * minimapSize.adjustedScale;
                const targetY = (targetNode.position.y - minimapSize.minY + (targetNode.height || 80) / 2) * minimapSize.adjustedScale;
                return ((0, jsx_runtime_1.jsx)("line", { x1: sourceX, y1: sourceY, x2: targetX, y2: targetY, stroke: "#9CA3AF", strokeWidth: "1", strokeOpacity: "0.6" }, edge.id));
            }) }));
    };
    // Handle mouse down on minimap
    const handleMinimapMouseDown = (e) => {
        if (!draggable)
            return;
        // Only handle left mouse button
        if (e.button !== 0)
            return;
        // Prevent text selection
        e.preventDefault();
        // Get minimap bounds
        const minimapRect = minimapRef.current.getBoundingClientRect();
        // Calculate click position relative to minimap
        const x = e.clientX - minimapRect.left;
        const y = e.clientY - minimapRect.top;
        // Check if click was on viewport rectangle
        const viewportRect = getViewportRect();
        const clickedViewport = x >= viewportRect.x && x <= viewportRect.x + viewportRect.width &&
            y >= viewportRect.y && y <= viewportRect.y + viewportRect.height;
        // Set dragging state
        setIsDragging(true);
        if (clickedViewport) {
            // If clicked on viewport rectangle, start dragging from click position relative to viewport
            setDragStart({
                x: x - viewportRect.x,
                y: y - viewportRect.y
            });
        }
        else {
            // If clicked outside viewport rectangle, center viewport at click position
            const workflowX = (x / minimapSize.adjustedScale) + minimapSize.minX;
            const workflowY = (y / minimapSize.adjustedScale) + minimapSize.minY;
            // Calculate new viewport position
            const newViewport = {
                ...viewport,
                x: workflowX - (viewport.width / viewport.zoom) / 2,
                y: workflowY - (viewport.height / viewport.zoom) / 2
            };
            // Update viewport
            if (onViewportChange) {
                onViewportChange(newViewport);
            }
            // Start dragging from center of viewport
            setDragStart({
                x: viewportRect.width / 2,
                y: viewportRect.height / 2
            });
        }
        // Add mouse move and mouse up event listeners
        document.addEventListener('mousemove', handleMouseMove);
        document.addEventListener('mouseup', handleMouseUp);
    };
    // Handle mouse move during drag
    const handleMouseMove = (e) => {
        if (!isDragging || !draggable)
            return;
        // Get minimap bounds
        const minimapRect = minimapRef.current.getBoundingClientRect();
        // Calculate new position
        const x = e.clientX - minimapRect.left - dragStart.x;
        const y = e.clientY - minimapRect.top - dragStart.y;
        // Translate minimap coordinates to workflow coordinates
        const workflowX = (x / minimapSize.adjustedScale) + minimapSize.minX;
        const workflowY = (y / minimapSize.adjustedScale) + minimapSize.minY;
        // Calculate new viewport position
        const newViewport = {
            ...viewport,
            x: workflowX,
            y: workflowY
        };
        // Update viewport
        if (onViewportChange) {
            onViewportChange(newViewport);
        }
    };
    // Handle mouse up to end drag
    const handleMouseUp = () => {
        setIsDragging(false);
        // Remove event listeners
        document.removeEventListener('mousemove', handleMouseMove);
        document.removeEventListener('mouseup', handleMouseUp);
    };
    // Toggle collapsed state
    const toggleCollapsed = () => {
        setCollapsed(!collapsed);
    };
    // Classes
    const minimapClasses = [
        'bf-minimap',
        collapsed ? 'bf-minimap--collapsed' : '',
        isDragging ? 'bf-minimap--dragging' : '',
        className
    ].filter(Boolean).join(' ');
    // Styles
    const minimapStyle = {
        position: 'absolute',
        width: `${minimapSize.width}px`,
        height: `${minimapSize.height}px`,
        ...getPositionStyle(),
        backgroundColor: '#F3F4F6',
        border: '1px solid #D1D5DB',
        borderRadius: '4px',
        boxShadow: '0 2px 5px rgba(0, 0, 0, 0.1)',
        overflow: 'hidden',
        transition: 'transform 0.3s ease',
        transform: collapsed ? 'scale(0.3)' : 'scale(1)',
        transformOrigin: position,
        ...style
    };
    // Calculate viewport rectangle
    const viewportRect = getViewportRect();
    return ((0, jsx_runtime_1.jsxs)("div", { ref: minimapRef, className: minimapClasses, style: minimapStyle, onMouseDown: handleMinimapMouseDown, ...rest, children: [collapsible && ((0, jsx_runtime_1.jsx)("button", { className: "bf-minimap__collapse-button", onClick: toggleCollapsed, "aria-label": collapsed ? 'Expand minimap' : 'Collapse minimap', style: {
                    position: 'absolute',
                    top: '4px',
                    right: '4px',
                    width: '16px',
                    height: '16px',
                    backgroundColor: '#6B7280',
                    color: 'white',
                    border: 'none',
                    borderRadius: '50%',
                    fontSize: '10px',
                    display: 'flex',
                    alignItems: 'center',
                    justifyContent: 'center',
                    cursor: 'pointer',
                    zIndex: 2
                }, children: collapsed ? '+' : '-' })), renderEdges(), renderNodes(), (0, jsx_runtime_1.jsx)("div", { ref: viewportRectRef, className: "bf-minimap__viewport-rect", style: {
                    position: 'absolute',
                    left: `${viewportRect.x}px`,
                    top: `${viewportRect.y}px`,
                    width: `${viewportRect.width}px`,
                    height: `${viewportRect.height}px`,
                    border: '2px solid #3B82F6',
                    backgroundColor: 'rgba(59, 130, 246, 0.1)',
                    pointerEvents: 'none'
                } })] }));
};
exports.MiniMap = MiniMap;
exports.MiniMap.propTypes = {
    workflow: prop_types_1.default.shape({
        nodes: prop_types_1.default.arrayOf(prop_types_1.default.shape({
            id: prop_types_1.default.string.isRequired,
            type: prop_types_1.default.string,
            position: prop_types_1.default.shape({
                x: prop_types_1.default.number.isRequired,
                y: prop_types_1.default.number.isRequired
            }).isRequired,
            width: prop_types_1.default.number,
            height: prop_types_1.default.number
        })),
        edges: prop_types_1.default.arrayOf(prop_types_1.default.shape({
            id: prop_types_1.default.string.isRequired,
            source: prop_types_1.default.string.isRequired,
            target: prop_types_1.default.string.isRequired
        }))
    }),
    viewport: prop_types_1.default.shape({
        x: prop_types_1.default.number.isRequired,
        y: prop_types_1.default.number.isRequired,
        zoom: prop_types_1.default.number.isRequired,
        width: prop_types_1.default.number.isRequired,
        height: prop_types_1.default.number.isRequired
    }),
    onViewportChange: prop_types_1.default.func,
    scale: prop_types_1.default.number,
    position: prop_types_1.default.oneOf(['top-left', 'top-right', 'bottom-left', 'bottom-right']),
    draggable: prop_types_1.default.bool,
    collapsible: prop_types_1.default.bool,
    defaultCollapsed: prop_types_1.default.bool,
    className: prop_types_1.default.string,
    style: prop_types_1.default.object
};
exports.default = exports.MiniMap;
//# sourceMappingURL=MiniMap.js.map