import { useState, useCallback } from 'react' import type { Section, EditorSelection } from '../types' interface DragSource { sourceSection: number sourceRow: number sourceCol: number sourceBlock: number } interface DragTarget { sectionIndex: number rowIndex: number colIndex: number blockIndex: number } interface UseDragDropOptions { sections: Section[] commitChange: (newSections: Section[]) => void setSelection: (sel: EditorSelection | null) => void } interface UseDragDropReturn { dragState: DragSource | null dragOverTarget: DragTarget | null setDragOverTarget: React.Dispatch> handleDragStart: ( sectionIndex: number, rowIndex: number, colIndex: number, blockIndex: number ) => void handleDragOver: ( e: React.DragEvent, sectionIndex: number, rowIndex: number, colIndex: number, blockIndex: number ) => void handleDrop: ( e: React.DragEvent, targetSection: number, targetRow: number, targetCol: number, targetBlock: number ) => void handleDragEnd: () => void } export function useDragDrop({ sections, commitChange, setSelection, }: UseDragDropOptions): UseDragDropReturn { const [dragState, setDragState] = useState(null) const [dragOverTarget, setDragOverTarget] = useState(null) const handleDragStart = useCallback( (sectionIndex: number, rowIndex: number, colIndex: number, blockIndex: number) => { setDragState({ sourceSection: sectionIndex, sourceRow: rowIndex, sourceCol: colIndex, sourceBlock: blockIndex, }) }, [] ) const handleDragOver = useCallback( ( e: React.DragEvent, sectionIndex: number, rowIndex: number, colIndex: number, blockIndex: number ) => { e.preventDefault() setDragOverTarget({ sectionIndex, rowIndex, colIndex, blockIndex }) }, [] ) const handleDrop = useCallback( ( e: React.DragEvent, targetSection: number, targetRow: number, targetCol: number, targetBlock: number ) => { e.preventDefault() if (!dragState) return const { sourceSection, sourceRow, sourceCol, sourceBlock } = dragState // Get the block being moved const block = sections[sourceSection]?.rows[sourceRow]?.columns[sourceCol]?.[sourceBlock] if (!block) return // Remove from source let newSections = sections.map((section, si) => { if (si !== sourceSection) return section return { ...section, rows: section.rows.map((row, ri) => { if (ri !== sourceRow) return row return { ...row, columns: row.columns.map((col, ci) => { if (ci !== sourceCol) return col return col.filter((_, bi) => bi !== sourceBlock) }), } }), } }) // Adjust target index if removing from same column before target let adjustedTargetBlock = targetBlock if ( sourceSection === targetSection && sourceRow === targetRow && sourceCol === targetCol && sourceBlock < targetBlock ) { adjustedTargetBlock -= 1 } // Insert at target newSections = newSections.map((section, si) => { if (si !== targetSection) return section return { ...section, rows: section.rows.map((row, ri) => { if (ri !== targetRow) return row return { ...row, columns: row.columns.map((col, ci) => { if (ci !== targetCol) return col return [ ...col.slice(0, adjustedTargetBlock), block, ...col.slice(adjustedTargetBlock), ] }), } }), } }) commitChange(newSections) setDragState(null) setDragOverTarget(null) setSelection({ sectionIndex: targetSection, rowIndex: targetRow, columnIndex: targetCol, blockIndex: adjustedTargetBlock, }) }, [dragState, sections, commitChange, setSelection] ) const handleDragEnd = useCallback(() => { setDragState(null) setDragOverTarget(null) }, []) return { dragState, dragOverTarget, setDragOverTarget, handleDragStart, handleDragOver, handleDrop, handleDragEnd, } }