import { Box, Menu } from "@mantine/core";
import { createContext, useEffect, useState } from "react";

interface ContextMenuProviderContextType {
    openContextMenu: (
        items : ContextMenuItem[], 
        noRenderStandardItems?: boolean, noRenderDisabledItems?: boolean) => void;
}

export const ContextMenuContext = createContext<ContextMenuProviderContextType|null>(null);

interface ContextMenuProviderProps {
    children: React.ReactNode;
}

export interface ContextMenuItem {
    label: string;
    action: () => void;
    icon: React.ReactNode;
    cond?: () => boolean | Promise<boolean>;
    __reserved_prerender_condition?: boolean;
}

const standardMenuItems: ContextMenuItem[] = [];

const animationDelay = 40;

export function ContextMenuProvider(props : ContextMenuProviderProps) {
    const [coords, setCoords] = useState({
        x: 0,
        y: 0
    });
    const [open, setOpen] = useState<boolean>(false);
    const [items, setItems] = useState<ContextMenuItem[]>([]);
    const [noRenderStandardItems, setNoRenderStandardItems] = useState<boolean>(false);
    const [standardItemsReady, setStandardItemsReady] = useState<ContextMenuItem[]>([]);



    useEffect(() => {
        document.removeEventListener('contextmenu', contextMenuHandler);
        document.removeEventListener('click', clickHandler);
        document.addEventListener('contextmenu',contextMenuHandler);
        document.addEventListener('click', clickHandler);
        return () => {
            document.removeEventListener('contextmenu', contextMenuHandler);
            document.removeEventListener('click', clickHandler);
        }
    }, [open]);

    useEffect(() => {
        (async () => {
            setStandardItemsReady(await translateConditionsToReservedField(standardMenuItems));
        })();
    }, [open]);

    const contextMenuHandler = (event) => {
        event.preventDefault();
        setOpen(true);
        setCoords({
            x: event.clientX,
            y: event.clientY
        });
    }

    const clickHandler = () => {
        if(open){
            setOpen(false);
            setTimeout(() => {
                /**
                 * Ждем завершения анимации
                 */
                setItems([]);
            }, animationDelay);
        }
    }    

    const translateConditionsToReservedField = async (fromItems : ContextMenuItem[], noRenderDisabledItems: boolean = false) : Promise<ContextMenuItem[]> => {
        const newItems: ContextMenuItem[] = [];
        for(const item of fromItems){
            if(!item.cond){
                newItems.push({
                    ...item,
                    __reserved_prerender_condition: true
                });
                continue;
            }
            const condResult = await item.cond();
            if(!condResult && noRenderDisabledItems){
                continue;
            }
            newItems.push({
                ...item,
                __reserved_prerender_condition: condResult
            });
        }
        return newItems;
    }

    const openContextMenu = async (
        items : ContextMenuItem[], 
        noRenderStandardItems: boolean = false,
        noRenderDisabledItems: boolean = false
    ) => {
        setItems(await translateConditionsToReservedField(items, noRenderDisabledItems));
        setNoRenderStandardItems(noRenderStandardItems);
        setOpen(true);
    }
    
    return (
        <>    
            <ContextMenuContext.Provider value={{
                openContextMenu
            }}>
                {standardItemsReady.length > 0 || items.length > 0 && (
            <Box style={{
                    position: 'absolute',
                    top: coords.y > window.innerHeight - (items.concat(standardMenuItems).length * 45) ? (window.innerHeight - (items.concat(standardMenuItems).length * 45)) + 'px' : coords.y + 'px',
                    left: coords.x > window.innerWidth - 210 ? (window.innerWidth - 210) + 'px' : coords.x + 'px',
                }}>
                    <Menu
                    trapFocus={false}
                    shadow="md" 
                    opened={open}
                    transitionProps={{
                        duration: animationDelay,
                        transition: 'pop-top-left',
                    }}
                    closeDelay={0}
                    styles={{
                        dropdown: {
                            position: 'absolute',
                            top: coords.y > window.innerHeight - (items.concat(standardMenuItems).length * 45) ? (window.innerHeight - (items.concat(standardMenuItems).length * 45)) + 'px' : coords.y + 'px',
                            left: coords.x > window.innerWidth - 210 ? (window.innerWidth - 210) + 'px' : coords.x + 'px',
                        }
                    }}
                    width={150}>
                    <Menu.Dropdown>
                        {items.map((item, index) => (
                            <Menu.Item fz={'xs'} fw={500} key={index} disabled={!item.__reserved_prerender_condition} leftSection={item.icon} onClick={() => {
                                item.action();
                                setOpen(false);
                            }}>
                                {item.label}
                            </Menu.Item>
                        ))}
                        {items.length > 0 && !noRenderStandardItems && standardMenuItems.length > 0 && <Menu.Divider></Menu.Divider>}
                        {!noRenderStandardItems && standardItemsReady.map((item, index) => ( 
                            <Menu.Item fz={'xs'} fw={500} key={index} disabled={!item.__reserved_prerender_condition} leftSection={item.icon} onClick={() => {
                                item.action();
                                setOpen(false);
                            }}>
                                {item.label}
                            </Menu.Item>
                        ))}
                    </Menu.Dropdown>
                </Menu>
                </Box>                          
                )}
                {props.children}
            </ContextMenuContext.Provider>   
        </>
    );
}