'use client';
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
/**
 * Section Tree component - Left panel showing hierarchical field structure
 * With drag-and-drop support for reordering
 *
 * Multi-section support: sections appear as top-level nodes
 */
import { useMemo, useState, useCallback } from 'react';
import { DndContext, DragOverlay, useDraggable, useDroppable, closestCenter, PointerSensor, useSensor, useSensors, } from '@dnd-kit/core';
import { HiChevronRight, HiChevronDown, HiFolder, HiFolderOpen, HiPencil, HiDocumentText, HiCheckCircle, HiCollection, HiCalendar, HiTable, HiCloudUpload, } from 'react-icons/hi';
import { LuChevronDown, LuGripVertical } from 'react-icons/lu';
import { FaLayerGroup } from 'react-icons/fa';
import { useTemplateGenerator } from '../context.js';
import { build_tree_nodes, is_section_path, parse_path } from '../utils/template_utils.js';
import { cn } from '../../../utils/cn.js';
// Icon map for component types
const COMPONENT_ICONS = {
    'HazoCollabFormInputbox': HiPencil,
    'HazoCollabFormTextArea': HiDocumentText,
    'HazoCollabFormCheckbox': HiCheckCircle,
    'HazoCollabFormRadio': HiCollection,
    'HazoCollabFormCombo': LuChevronDown,
    'HazoCollabFormDate': HiCalendar,
    'HazoCollabFormDataTable': HiTable,
    'HazoCollabFormDoc': HiCloudUpload,
};
export function SectionTree({ readonly = false }) {
    const { state, actions } = useTemplateGenerator();
    const [expanded_nodes, set_expanded_nodes] = useState(new Set(['s0'])); // Expand first section by default
    const [active_drag_id, set_active_drag_id] = useState(null);
    const [drag_over_id, set_drag_over_id] = useState(null);
    const [drop_position, set_drop_position] = useState(null);
    // Configure sensors for drag-and-drop
    const sensors = useSensors(useSensor(PointerSensor, {
        activationConstraint: {
            distance: 8, // Require 8px of movement before starting drag
        },
    }));
    // Build tree from sections
    const tree_nodes = useMemo(() => {
        return build_tree_nodes(state.sections);
    }, [state.sections]);
    // Count total items (groups + fields, not sections)
    const total_items = useMemo(() => {
        let count = 0;
        const count_items = (nodes) => {
            for (const node of nodes) {
                if (node.type !== 'section')
                    count++;
                if (node.children)
                    count_items(node.children);
            }
        };
        count_items(tree_nodes);
        return count;
    }, [tree_nodes]);
    // Get node by path
    const get_node_by_path = useCallback((path) => {
        const find_node = (nodes, target_path) => {
            for (const node of nodes) {
                if (node.path === target_path)
                    return node;
                if (node.children) {
                    const found = find_node(node.children, target_path);
                    if (found)
                        return found;
                }
            }
            return null;
        };
        return find_node(tree_nodes, path);
    }, [tree_nodes]);
    // Toggle expansion
    const toggle_expand = useCallback((path) => {
        set_expanded_nodes((prev) => {
            const next = new Set(prev);
            if (next.has(path)) {
                next.delete(path);
            }
            else {
                next.add(path);
            }
            return next;
        });
    }, []);
    // Handle node click
    const handle_node_click = useCallback((path) => {
        actions.select_item(path);
    }, [actions]);
    // Handle drag start
    const handle_drag_start = useCallback((event) => {
        set_active_drag_id(event.active.id);
    }, []);
    // Handle drag over
    const handle_drag_over = useCallback((event) => {
        const { active, over } = event;
        if (!over) {
            set_drag_over_id(null);
            set_drop_position(null);
            return;
        }
        const over_id = over.id;
        const active_id = active.id;
        // Don't allow dropping on itself
        if (over_id === active_id) {
            set_drag_over_id(null);
            set_drop_position(null);
            return;
        }
        // Parse the drop target - format is "path:position" or just "path"
        const [target_path, position] = over_id.includes(':')
            ? over_id.split(':')
            : [over_id, 'inside'];
        // Don't allow dropping a parent into its own child
        if (target_path.startsWith(active_id + '.')) {
            set_drag_over_id(null);
            set_drop_position(null);
            return;
        }
        set_drag_over_id(target_path);
        set_drop_position(position);
    }, []);
    // Handle drag end
    const handle_drag_end = useCallback((event) => {
        const { active, over } = event;
        set_active_drag_id(null);
        set_drag_over_id(null);
        set_drop_position(null);
        if (!over)
            return;
        const active_path = active.id;
        const over_id = over.id;
        console.log('[handle_drag_end] Drag ended:', { active_path, over_id });
        // Parse the drop target
        const [target_path, position] = over_id.includes(':')
            ? over_id.split(':')
            : [over_id, 'inside'];
        console.log('[handle_drag_end] Parsed:', { target_path, position });
        // Don't allow dropping on itself or its children
        if (target_path === active_path || target_path.startsWith(active_path + '.')) {
            console.log('[handle_drag_end] Rejected: dropping on self or child');
            return;
        }
        // Check if this is a section drag (sections can only be reordered among themselves)
        if (is_section_path(active_path)) {
            if (is_section_path(target_path)) {
                // Section-to-section move
                const { section_index: from_index } = parse_path(active_path);
                const { section_index: to_index } = parse_path(target_path);
                console.log('[handle_drag_end] Moving section', from_index, 'to', to_index);
                actions.move_section(from_index, position === 'before' ? to_index : to_index + 1);
            }
            return;
        }
        // Get the target node to determine valid drop position
        const target_node = get_node_by_path(target_path);
        console.log('[handle_drag_end] Target node:', target_node?.label, 'type:', target_node?.type);
        // If target is a section, can drop inside it
        if (target_node?.type === 'section' && position === 'inside') {
            console.log('[handle_drag_end] Dropping inside section');
            actions.move_field(active_path, target_path, 'inside');
            return;
        }
        // If dropping "inside" but target is not a group or section, drop "after" instead
        let final_position = position;
        if (position === 'inside' && target_node?.type !== 'group' && target_node?.type !== 'section') {
            final_position = 'after';
            console.log('[handle_drag_end] Converted inside to after (target not a group)');
        }
        console.log('[handle_drag_end] Final call: move_field(', active_path, ',', target_path, ',', final_position, ')');
        // Perform the move
        actions.move_field(active_path, target_path, final_position);
    }, [actions, get_node_by_path]);
    // Get the active node for overlay
    const active_node = active_drag_id ? get_node_by_path(active_drag_id) : null;
    return (_jsxs("div", { className: "flex flex-col h-full", children: [_jsxs("div", { className: "p-3 border-b bg-muted/30", children: [_jsx("h3", { className: "font-medium text-sm", children: "Structure" }), _jsxs("p", { className: "text-xs text-muted-foreground mt-0.5", children: [state.sections.length, " section", state.sections.length !== 1 ? 's' : ''] })] }), _jsx("div", { className: "flex-1 overflow-auto p-2", children: tree_nodes.length === 0 ? (_jsxs("div", { className: "text-center text-muted-foreground text-sm py-8", children: [_jsx("p", { children: "No sections yet." }), _jsx("p", { className: "mt-2", children: "Click \"+ Section\" to add one." })] })) : (_jsxs(DndContext, { sensors: sensors, collisionDetection: closestCenter, onDragStart: handle_drag_start, onDragOver: handle_drag_over, onDragEnd: handle_drag_end, children: [_jsx("div", { className: "space-y-0.5", children: tree_nodes.map((node, index) => (_jsx(TreeNodeItem, { node: node, selected_path: state.selected_path, expanded_nodes: expanded_nodes, on_toggle_expand: toggle_expand, on_select: handle_node_click, validation_errors: state.validation_errors, depth: 0, readonly: readonly, drag_over_id: drag_over_id, drop_position: drop_position, is_first: index === 0, is_last: index === tree_nodes.length - 1 }, node.path))) }), _jsx(DragOverlay, { children: active_node && (_jsx(DragOverlayItem, { node: active_node })) })] })) }), _jsxs("div", { className: "px-3 py-2 border-t bg-muted/30 text-xs text-muted-foreground flex items-center justify-between", children: [_jsxs("span", { children: [total_items, " item", total_items !== 1 ? 's' : ''] }), state.validation_errors.length > 0 ? (_jsxs("span", { className: "text-destructive", children: [state.validation_errors.length, " error", state.validation_errors.length !== 1 ? 's' : ''] })) : (_jsx("span", { className: "text-green-600", children: "Valid" }))] })] }));
}
function TreeNodeItem({ node, selected_path, expanded_nodes, on_toggle_expand, on_select, validation_errors, depth, readonly, drag_over_id, drop_position, is_first = false, is_last = false, }) {
    const is_expanded = expanded_nodes.has(node.path);
    const is_selected = selected_path === node.path;
    const has_children = node.children && node.children.length > 0;
    const has_error = validation_errors.some((e) => e.field_path === node.path);
    const is_section = node.type === 'section';
    const is_group = node.type === 'group';
    // Draggable hook
    const { attributes, listeners, setNodeRef: setDraggableRef, isDragging, } = useDraggable({
        id: node.path,
        disabled: readonly,
    });
    // Droppable hook for "inside" drop (for groups and sections)
    const { setNodeRef: setDroppableInsideRef, isOver: isOverInside, } = useDroppable({
        id: node.path,
        disabled: readonly || (node.type !== 'group' && node.type !== 'section'),
    });
    // Droppable hook for "before" drop (not for sections - they use section reordering)
    const { setNodeRef: setDroppableBeforeRef, isOver: isOverBefore, } = useDroppable({
        id: `${node.path}:before`,
        disabled: readonly || is_section,
    });
    // Droppable hook for "after" drop (not for sections)
    const { setNodeRef: setDroppableAfterRef, isOver: isOverAfter, } = useDroppable({
        id: `${node.path}:after`,
        disabled: readonly || is_section,
    });
    // Get icon for the node
    const Icon = is_section
        ? FaLayerGroup
        : is_group
            ? (is_expanded ? HiFolderOpen : HiFolder)
            : (node.field_config?.component_type
                ? COMPONENT_ICONS[node.field_config.component_type] || HiPencil
                : HiPencil);
    // Check if we should show drop indicators
    const show_before_indicator = drag_over_id === node.path && drop_position === 'before';
    const show_after_indicator = drag_over_id === node.path && drop_position === 'after';
    const show_inside_indicator = drag_over_id === node.path && drop_position === 'inside' && (is_group || is_section);
    return (_jsxs("div", { className: cn(isDragging && 'opacity-50'), children: [!is_section && (_jsx("div", { ref: setDroppableBeforeRef, className: cn('h-1 -my-0.5 mx-2 rounded transition-colors', (isOverBefore || show_before_indicator) && 'bg-primary h-1'), style: { marginLeft: `${depth * 16 + 8}px` } })), _jsxs("div", { ref: (el) => {
                    setDraggableRef(el);
                    if (is_group || is_section) {
                        setDroppableInsideRef(el);
                    }
                }, className: cn('flex items-center gap-1 px-2 py-1.5 rounded cursor-pointer text-sm group', 'hover:bg-muted/50', is_selected && 'bg-primary/10 text-primary', has_error && 'text-destructive', is_section && 'font-semibold bg-blue-50 dark:bg-blue-950/30 border-l-3 border-l-blue-400/40 mt-1 first:mt-0', (isOverInside || show_inside_indicator) && 'ring-2 ring-primary ring-inset'), style: { paddingLeft: `${depth * 16 + 8}px` }, onClick: () => on_select(node.path), children: [!readonly && (_jsx("button", { ...attributes, ...listeners, className: "p-0.5 hover:bg-muted rounded cursor-grab opacity-0 group-hover:opacity-100 transition-opacity", onClick: (e) => e.stopPropagation(), children: _jsx(LuGripVertical, { className: "w-4 h-4 text-muted-foreground" }) })), has_children || is_section ? (_jsx("button", { onClick: (e) => {
                            e.stopPropagation();
                            on_toggle_expand(node.path);
                        }, className: "p-0.5 hover:bg-muted rounded", children: is_expanded ? (_jsx(HiChevronDown, { className: "w-4 h-4" })) : (_jsx(HiChevronRight, { className: "w-4 h-4" })) })) : (_jsx("span", { className: "w-5" }) // Spacer
                    ), _jsx(Icon, { className: cn('w-4 h-4 shrink-0', is_section && 'text-blue-600', !is_section && is_group && 'text-amber-600', has_error && 'text-destructive') }), _jsx("span", { className: "truncate flex-1", children: node.label || node.id || 'Untitled' }), is_section && (_jsx("span", { className: "text-xs text-blue-600 dark:text-blue-400 bg-blue-100 dark:bg-blue-900/50 px-1.5 py-0.5 rounded", children: "Section" })), node.field_config?.required && (_jsx("span", { className: "text-destructive text-xs", children: "*" })), node.field_config?.dependency && (_jsx("span", { className: "text-xs text-muted-foreground", title: "Has dependency", children: "\u27E8\u27E9" })), ((node.field_config?.accept_public_files && node.field_config.accept_public_files !== 'none') || (node.field_config?.accept_private_files && node.field_config.accept_private_files !== 'none') || (node.section?.accept_public_files && node.section.accept_public_files !== 'none') || (node.section?.accept_private_files && node.section.accept_private_files !== 'none')) && (_jsx("span", { className: "text-xs text-muted-foreground", title: "Accepts files", children: "\uD83D\uDCCE" }))] }), !is_section && (!has_children || !is_expanded) && (_jsx("div", { ref: setDroppableAfterRef, className: cn('h-1 -my-0.5 mx-2 rounded transition-colors', (isOverAfter || show_after_indicator) && 'bg-primary h-1'), style: { marginLeft: `${depth * 16 + 8}px` } })), (has_children || is_section) && is_expanded && (_jsxs("div", { children: [(node.children ?? []).map((child, index) => (_jsx(TreeNodeItem, { node: child, selected_path: selected_path, expanded_nodes: expanded_nodes, on_toggle_expand: on_toggle_expand, on_select: on_select, validation_errors: validation_errors, depth: depth + 1, readonly: readonly, drag_over_id: drag_over_id, drop_position: drop_position, is_first: index === 0, is_last: index === (node.children?.length ?? 0) - 1 }, child.path))), !is_section && (_jsx("div", { ref: setDroppableAfterRef, className: cn('h-1 -my-0.5 mx-2 rounded transition-colors', (isOverAfter || show_after_indicator) && 'bg-primary h-1'), style: { marginLeft: `${depth * 16 + 8}px` } }))] }))] }));
}
// Drag overlay item (what's shown while dragging)
function DragOverlayItem({ node }) {
    const is_section = node.type === 'section';
    const is_group = node.type === 'group';
    const Icon = is_section
        ? FaLayerGroup
        : is_group
            ? HiFolderOpen
            : (node.field_config?.component_type
                ? COMPONENT_ICONS[node.field_config.component_type] || HiPencil
                : HiPencil);
    return (_jsxs("div", { className: "flex items-center gap-2 px-3 py-2 rounded bg-background border shadow-lg text-sm", children: [_jsx(Icon, { className: cn('w-4 h-4 shrink-0', is_section && 'text-blue-600', !is_section && is_group && 'text-amber-600') }), _jsx("span", { className: "truncate", children: node.label || node.id || 'Untitled' })] }));
}
//# sourceMappingURL=section_tree.js.map