import React, {Children, forwardRef, createContext, useMemo, useRef, useState, useCallback, useEffect} from 'react';
import Links from './Links';
import useBlocks from './useBlocks';


export const Context = createContext();
export default forwardRef(({children, onUnselect}, ref) => {
    const childsArray = Children.toArray(children),
        childsKey = childsArray.reduce((s, ch) => `${s}-${ch.key}`, ''),
        [selected, setSelected] = useState(null),
        _prevSelected = useRef(null),
        $links = useRef(null),
        onBlocksChange = blocks => $links.current && $links.current.onBlocksUpdate(blocks),
        [getBlocks, registerBlock, _unregisterBlock, updateBlock] = useBlocks(onBlocksChange),
        unregisterBlock = useCallback(bix => {
            const blocks = getBlocks(),
                bid = (([,,{id}]) => id)(blocks.find(([ix]) => ix === bix) || {});
            ($links.current?.getLinks() || [])
                .filter(([,,,{relations}]) => (relations || []).indexOf(bid) > -1)
                .forEach(([, bbix, rix]) => (([,,{removeRelation}]) => removeRelation(rix, bid))(blocks.find(([bix]) => bix === bbix)));
            return _unregisterBlock(bix);
        }, [childsKey]),
        sorted = useMemo(() => selected && selected[0] === 'b'
            ? (prevSorted => prevSorted.sort((a, b) => (a[0] === selected[1])
                    ? 1
                    : (b[0] === selected[1] ? -1 : 0)
                ).reduce((list, [k]) => ( iix => [...list, childsArray[iix]])(getBlocks().findIndex(([iiix]) => iiix === k)), []))(sorted || getBlocks().slice())
            : childsArray, [childsKey, (selected || []).join('-')]),
        // registerLinks, unRegisterLinks, updateLinks, getLinks,
        callLinksMethod = useCallback(mName => function() { 
            return $links.current && $links.current[mName].apply($links.current, arguments);
        });
    useEffect(() => {
        if(ref) {
            ref.current = {setSelected};
            return () => {
                ref.current = null;
            }
        } 
    }, []);
    useEffect(() => {
        if(!selected && _prevSelected.current && onUnselect) {
            onUnselect();
        }
        _prevSelected.current = selected;
    }, [selected && selected[0], selected && selected[1]]);
    return (<>
        <Links 
            ref={$links}
            getBlocks={getBlocks}
            onSelect={setSelected}
            selected={selected}
        />
        <Context.Provider
            value={{
                onSelect: setSelected,
                selected,
                registerBlock, 
                unregisterBlock,
                updateBlock,
                getBlocks,

                onAnchorDragStart: callLinksMethod('onAnchorDragStart'),
                onAnchorDragEnd: callLinksMethod('onAnchorDragEnd'),
                onAnchorDrag: callLinksMethod('onAnchorDrag'),

                onDragOver: callLinksMethod('onDragOver'),
                onDragOut: callLinksMethod('onDragOut'),

                registerLinks: callLinksMethod('registerLinks'),
                unRegisterLinks: callLinksMethod('unRegisterLinks'),                      
                updateLinks: callLinksMethod('updateLinks'),
                getLinks: callLinksMethod('getLinks')
            }}
        >{sorted}</Context.Provider>
    </>);
});