import Icon from "../Icon";
import SvgIcon from "../SvgIcon";

const { __ } = wp.i18n;
const { useState, useEffect, useMemo, useRef } = wp.element;


const SortableLayers = ( {
    elements,
    tree,
    selectedLayer,
    onLayerDragged,
    onOrderChanged,
    onLayerSelected,
    onHovering,
    onElementDataChange,
    onAddNewCondition,
    isMouseDown,
    infoHelper,
    onDuplicateLayer,
    onDeleteLayer,
    ...props
} ) => {
    const [items, setItems] = useState( tree || [] );
    const [theSelectedLayer, setTheSelectedLayer] = useState( selectedLayer );
    const [isEditingLabel, setIsEditingLabel] = useState( false );
    const [editingLabel, setEditingLabel] = useState( null );

    const [draggingItem, setDraggingItem] = useState( null );
    const [dropTargetId, setDropTargetId] = useState( null );
    const [dropAsChild, setDropAsChild] = useState( false );

    const [dropZone, setDropZone] = useState( null );

    const containerRef = useRef( null );

    // const flattenedItems = useMemo( () => flattenTree( items ), [items] );

    // const childableTypes = ['condition', 'container', 'layergroup'];
    const childableTypes = ['condition', 'conditional', 'container', 'layergroup'];

    useEffect( () => {
        // console.log(tree);
        if ( tree === undefined ) {
            return;
        }

        if ( elements && JSON.stringify( items ) !== JSON.stringify( tree ) ) {
            setItems( tree );
        }
        if ( selectedLayer !== theSelectedLayer ) {
            setTheSelectedLayer( selectedLayer );
        }

    }, [tree, selectedLayer] ); //run this code when the value of template changes

    const renderItem = ( treeItem ) => {
        // Find the associated element by its id
        const item = elements.find( element => element.id.toLowerCase() == treeItem.id.toLowerCase() );

        if ( !item ) {
            return;
        }

        const isDropTarget = dropTargetId === treeItem.id;

        let styles = {
            opacity: isDropTarget && dropZone === 'inside' ? 0.75 : 1,
        }

        if ( isDropTarget && dropZone === 'inside' ) {
            styles.boxShadow = 'inset 0 0 6px #292929';
            styles.backgroundColor = '#676767';
        }

        let classes = [
            'safi-layer',
            ( theSelectedLayer == item.id.toLowerCase() ? '--selected' : '' ),
            '--layer-' + item.type.toLowerCase(),
            item.locked ? '--locked' : '',
            item.dynamic ? '--dynamic' : '',
            item.collapsed ? '--collapsed' : '',
            item.hidden ? '--invisible' : '',
            isEditingLabel !== false ? '--is-editing' : '',
        ];


        return (
            <div
                className={classes.filter( item => { return item !== '' } ).join( ' ' )}
                // className={`safi-layer ${isDropTarget ? ( dropAsChild ? 'drop-child' : 'drop-sibling' ) : ''}`}
                key={treeItem.id.toLowerCase()}
                onDragStart={( e ) => handleDragStart( e, item )}
                onDragOver={( e ) => handleDragOver( e, item )}
                onDrop={( e ) => handleDrop( e, item )}
                onDragEnd={handleDragEnd}
                draggable
                // data-id={treeItem.id}
                data-layer-id={item.id.toLowerCase()}
                data-layer-label
                onClick={selectLayer}
                onMouseOver={( e ) => {
                    e.target.closest( '.safi-layer' ).dataset.layerId == item.id.toLowerCase() &&
                        // item.type !== 'container' && item.type !== 'columns' &&
                        onHovering( item.id.toLowerCase() )
                }}
                onMouseOut={() => { onHovering( null ) }}
            >
                <div
                    className="safi-layer-container"
                    data-id={treeItem.id}
                    style={styles}
                >
                    {isDropTarget && dropZone === 'above' &&
                        <div className="safi-layer-drop-zone --above"></div>
                    }
                    {isDropTarget && dropZone === 'below' &&
                        <div className="safi-layer-drop-zone --below"></div>
                    }
                    {
                        ( item.type === 'conditional' || item.type === 'columns' || item.type === 'layergroup' ) &&
                        <div onClick={() => onElementDataChange( item.id.toLowerCase(), { collapsed: !item.collapsed } )} >
                            <Icon icon={!item.collapsed ? 'expand_less' : 'expand_more'} />
                        </div>
                    }
                    <SvgIcon className="safi-layer-icon" icon={item.type.toLowerCase()} />
                    {
                        isEditingLabel !== item.id.toLowerCase() &&
                        <div
                            className="safi-layer-label"
                            onDoubleClick={() => startEditingLabel( item )}
                        >{item.label}</div>
                    }
                    {
                        isEditingLabel === item.id.toLowerCase() &&
                        <div className="safi-layer-label-edit">
                            <input type="text"
                                autoFocus
                                onFocus={( e ) => e.target.select()}
                                value={editingLabel}
                                onChange={( e ) => setEditingLabel( e.target.value )}
                                onKeyDown={( e ) => handleLabelChange( e, item )}
                                onBlur={( e ) => handleLabelOut( e, item )}
                            // onBlur={() => setIsEditingLabel( false )}
                            />
                        </div>
                    }
                    <div className="safi-layer-controls">
                        {item.type !== 'container' && item.type !== 'columns' && item.type !== 'conditional' && item.type !== 'condition' &&
                            <div className="safi-layer-control safi-eye"
                                onClick={() => onElementDataChange( item.id.toLowerCase(), { hidden: !item.hidden } )}
                                title={!item.hidden ? __( "Hide", "wpjoli-safi" ) : __( "Unhide", "wpjoli-safi" )}
                            >
                                <SvgIcon className="safi-layer-icon" icon={!item.hidden ? 'eye' : 'eye_off'} />
                            </div>
                        }
                        {item.type !== 'container' && item.type !== 'columns' && item.type !== 'conditional' && item.type !== 'condition' &&
                            <div className="safi-layer-control safi-lock"
                                onClick={() => onElementDataChange( item.id.toLowerCase(), { locked: !item.locked } )}
                                title={!item.locked ? __( "Lock position & disable on-canvas selection", "wpjoli-safi" ) : __( "Unlock layer", "wpjoli-safi" )}
                            >
                                <SvgIcon className="safi-layer-icon" icon={!item.locked ? 'lock_open' : 'lock'} />
                            </div>
                        }
                        {( item.type === 'text' || item.type === 'image' || item.type === 'icon' || item.type === 'svg' ) &&
                            <div className="safi-layer-control safi-dynamic"
                                onClick={() => onElementDataChange( item.id.toLowerCase(), { dynamic: !item.dynamic } )}
                                title={!item.dynamic ? __( "Make dynamic", "wpjoli-safi" ) : __( "Make static", "wpjoli-safi" )}
                            >
                                <SvgIcon className="safi-layer-icon" icon={!item.dynamic ? 'bolt' : 'bolt'} />
                            </div>
                        }
                        {/* {item.type !== 'container' && item.type !== 'columns' &&
                            <div className="safi-delete-layer"
                                onClick={() => onElementDataChange( item.id, { locked: !item.locked } )}
                            >
                                <SvgIcon className="safi-layer-icon" icon={!item.locked ? 'lock_open' : 'lock'} />
                            </div>
                        } */}
                        { }
                    </div>
                </div>
                {treeItem.children && treeItem.children.length > 0 && (
                    <div className="safi-layer-children">
                        {treeItem.children.map( child => renderItem( child ) )}
                    </div>
                )}
                {( ( !treeItem.children || !treeItem.children?.length ) && ( item.type === 'condition' || item.type === 'container' || item.type === 'layergroup' ) ) &&
                    <div className="safi-layer-tip">Drop layers here</div>
                }
                {isDropTarget && dropZone === 'below-children' &&
                    <div className="safi-layer-drop-zone --below-children"></div>
                }
            </div>
        );
    }
    // function flattenTree( items, parentId = null, depth = 0 ) {
    //   return items.reduce( ( acc, item, index ) => {
    //     return [
    //       ...acc,
    //       { ...item, parentId, depth, index },
    //       ...flattenTree( item.children || [], item.id, depth + 1 ),
    //     ];
    //   }, [] );
    // }

    const containerPosition = useMemo( () => {
        if ( !containerRef.current ) return null;

        const bounding = containerRef.current.getBoundingClientRect();
        return {
            top: bounding.top,
            left: bounding.left,
            width: bounding.width,
            height: bounding.height,
        };
    } )

    const draggedItemPosition = useRef( null );

    function getItemPosition( item ) {
        if ( !item ) return null;
        const itemRect = item.getBoundingClientRect();
        return {
            top: itemRect.top - containerPosition.top,
            left: itemRect.left - containerPosition.left,
            width: itemRect.width,
            height: itemRect.height
        }
    }
    function handleDragStart( e, item ) {
        e.stopPropagation()
        setDraggingItem( item );
        e.dataTransfer.effectAllowed = 'move';

        const targetItem = e.target.closest( '.safi-layer-container' );
        const itemPosition = getItemPosition( targetItem );
        draggedItemPosition.current = itemPosition;

        // console.log( 'containerPosition', containerPosition );
        // console.log( 'draggedItemPosition', draggedItemPosition.current );
    }

    function handleDragOver( e, targetItem ) {
        e.preventDefault(); // Needed to allow drop
        e.stopPropagation()

        const isOverLayerGroup = e.target.closest( '.--layer-layergroup' ) !== null;
        // const isOverConditional = e.target.closest( '.--layer-conditional' ) !== null;
        const isOverCondition = e.target.closest( '.--layer-condition' ) !== null;

        // console.log(isOverLayerGroup, e.target.closest( '.--layer-layergroup' ));
        // console.log(draggingItem,draggingItem.type);
        if ( draggingItem && draggingItem.type === 'layergroup' && isOverLayerGroup ) return;
        if ( draggingItem && ( draggingItem.type === 'condition' || draggingItem.type === 'conditional' ) && isOverCondition ) return;

        let mayHaveChildren = false;
        let hoveredItem = e.target.closest( '.safi-layer-container' );
        const isDroppableArea = e.target.closest( '.safi-layer-tip' ) !== null;

        //if the cursor is not on a layer (maybe the cursor is on the parent) This will let us move layers below or after parents 
        if ( !hoveredItem ) {
            hoveredItem = e.target.closest( '.safi-layer' );
            mayHaveChildren = true;
            // console.log( 'hoveredItem', hoveredItem );
        };

        if ( !hoveredItem ) return;

        const hoveredItemPosition = getItemPosition( hoveredItem );
        // const hoveredItemId = hoveredItem.dataset.id;

        // Calculate mouse position relative to the hoveredItem
        const relativeMousePosition = {
            x: e.clientX - containerPosition.left - hoveredItemPosition.left,
            y: e.clientY - containerPosition.top - hoveredItemPosition.top,
        }

        // console.log( 'hoveredItemId', hoveredItemId, 'hoveredItemPosition', hoveredItemPosition, 'relativeMousePosition', relativeMousePosition );
        if ( !draggingItem || draggingItem.id === targetItem.id ) return;



        // Simple logic: drop as child if pointer is right, sibling if left
        let asChild = false;
        // const asChild = e.clientX - bounding.left > 30;

        if ( mayHaveChildren && !isDroppableArea ) {
            setDropZone( 'below-children' );
        }
        // console.log( targetItem.type, relativeMousePosition );
        // check if targetItem is of type within childableTypes
        else if ( childableTypes.includes( targetItem.type ) ) {
            if ( targetItem.type !== 'condition' && relativeMousePosition.y < hoveredItemPosition.height / 3 ) {
                // Mouse is in the upper half part of the hovered item
                // console.log( 'above' );
                setDropZone( 'above' );
            }
            //below area
            else if ( !( targetItem.type === 'conditional' || targetItem.type === 'condition' || targetItem.type === 'layergroup' ) && relativeMousePosition.y > hoveredItemPosition.height / 3 * 2 ) {
                // Mouse is in the lower half part of the hovered item
                // console.log( 'below' );
                setDropZone( 'below' );
            }
            else if ( targetItem.type !== 'conditional' ) {
                // Mouse is in the middle part of the hovered item
                // console.log( 'inside' );
                asChild = true;
                setDropZone( 'inside' );
            }
        } else {
            if ( relativeMousePosition.y < hoveredItemPosition.height / 2 ) {
                setDropZone( 'above' );
            } else {
                setDropZone( 'below' );
            }
        }

        setDropAsChild( asChild );
        setDropTargetId( targetItem.id );
    }

    function handleDrop( e, targetItem ) {
        e.preventDefault();
        e.stopPropagation()

        if ( !draggingItem || draggingItem.id === targetItem.id ) return;

        // Prevent layergroups to nesting each other
        const isOverLayerGroup = e.target.closest( '.--layer-layergroup' ) !== null;
        // const isOverConditional = e.target.closest( '.--layer-conditional' ) !== null;
        const isOverCondition = e.target.closest( '.--layer-condition' ) !== null;

        // console.log(isOverLayerGroup, e.target.closest( '.--layer-layergroup' ));
        // console.log(draggingItem,draggingItem.type);
        if ( draggingItem && draggingItem.type === 'layergroup' && isOverLayerGroup ) return;
        if ( draggingItem && ( draggingItem.type === 'condition' || draggingItem.type === 'conditional' ) && isOverCondition ) return;


        // finir de determiner where to place the element
        // console.log( 'DROP', draggingItem.id, targetItem.id, dropAsChild );

        let newTree = [];
        if ( dropZone === 'inside' || dropAsChild ) {
            newTree = moveItemInTree( items, draggingItem.id, targetItem.id, 'child' );
        } else if ( dropZone === 'above' ) {
            // move item as a sibling, before the target item
            newTree = moveItemInTree( items, draggingItem.id, targetItem.id, 'before' );
        } else if ( dropZone === 'below' || dropZone === 'below-children' ) {
            // move item as a sibling, after the target item
            newTree = moveItemInTree( items, draggingItem.id, targetItem.id, 'after' );
        }

        // setItems( newTree );
        onOrderChanged( newTree, true );
        resetDragState();
        return;
    }

    function handleDragEnd() {
        resetDragState();
    }

    function resetDragState() {
        setDraggingItem( null );
        setDropTargetId( null );
        setDropAsChild( false );
    }
    function moveItemInTree( tree, draggedId, targetId, placement ) {
        const removeItem = ( items, id ) => {
            for ( let i = 0; i < items.length; i++ ) {
                if ( items[i].id === id ) {
                    return [items.splice( i, 1 )[0], items];
                } else if ( items[i].children ) {
                    const [found, updated] = removeItem( items[i].children, id );
                    if ( found ) {
                        items[i].children = updated;
                        return [found, items];
                    }
                }
            }
            return [null, items];
        };

        const insertItem = ( items, newItem, targetId, placement ) => {
            for ( let i = 0; i < items.length; i++ ) {
                const item = items[i];
                if ( item.id === targetId ) {
                    switch ( placement ) {
                        case 'before':
                            items.splice( i, 0, newItem );
                            break;
                        case 'after':
                            items.splice( i + 1, 0, newItem );
                            break;
                        case 'child':
                            item.children = item.children || [];
                            item.children.push( newItem );
                            break;
                    }
                    return [true, items];
                }
                if ( item.children ) {
                    const [inserted, updatedChildren] = insertItem( item.children, newItem, targetId, placement );
                    if ( inserted ) {
                        item.children = updatedChildren;
                        items[i] = item;
                        return [true, items];
                    }
                }
            }
            return [false, items];
        };

        const treeCopy = structuredClone( tree );
        const [draggedItem, reducedTree] = removeItem( treeCopy, draggedId );
        insertItem( reducedTree, draggedItem, targetId, placement );
        return reducedTree;
    }
    const selectLayer = ( e ) => {

        //special case
        const isControl = e.target.closest( '.safi-layer-controls' );

        if ( isControl ) {
            //does not select if we clicked a control button
            return;
        }

        const layer = e.target.closest( '.safi-layer' );
        // console.log(e.target);
        const layerId = layer.dataset.layerId;
        // console.log(layerId);

        if ( layerId ) {
            onLayerSelected( layerId );

            setTheSelectedLayer( layerId );
            // this.highlightActiveLayer(layer);

        }
    };

    const startEditingLabel = ( item ) => {
        setIsEditingLabel( item.id.toLowerCase() );
        setEditingLabel( item.label );
    }


    const handleLabelChange = ( e, item ) => {
        if ( e.keyCode === 27 ) { //esc
            setIsEditingLabel( false );
        }

        if ( e.keyCode === 13 ) { //enter
            if ( !editingLabel || editingLabel == "" ) {
                alert( "Label cannot be empty" );
                return false;
            }

            setIsEditingLabel( false );
            onElementDataChange( item.id.toLowerCase(), { label: editingLabel } );

        }
        // console.log( e, e.target.value );

    }

    const handleLabelOut = ( e, item ) => {
        if ( !editingLabel || editingLabel == "" ) {
            alert( "Label cannot be empty" );
            return false;
        }
        if ( editingLabel && editingLabel !== "" ) {
            onElementDataChange( item.id.toLowerCase(), { label: editingLabel } );
            setIsEditingLabel( false );
            // onLayerSelected( item.id );
            // setTheSelectedLayer( item.id );
        }

    }

    // console.log( flattenedItems );
    return (
        <div ref={containerRef} id="safi-layers">
            {/* {flattenedItems && flattenedItems.map( ( item ) => renderItem( item ) )} */}
            {items && items.map( ( item ) => renderItem( item ) )}
            {items.length === 0 &&
                <div className="no-layers flex flex-center" disabled>{__( "Select a tool to create a layer !", "wpjoli-safi" )}</div>
            }
        </div>
    )
}

export default SortableLayers;