import { DndProvider } from 'react-dnd';
import { Tree, getBackendOptions, MultiBackend, getDescendants, NodeModel } from '@minoru/react-dnd-treeview';
import { useEffect, useState } from 'react';
import styles from '@/styles/tree.module.css';
import { coloredToast } from '@/lib/toast';
import { setPageTitle } from '../../../store/themeConfigSlice';
import { useDispatch } from 'react-redux';
import { CustomNode } from '@/pages/setting/menu/custom-node';
import { CssBaseline } from '@mui/material';
import PopupModal from './popUpModal';
import { CustomNodeMobile } from '@/pages/setting/menu/custom-node-mobile';

interface MenuItemData {
    id?: number;
    parent?: number;
    droppable?: boolean;
    text?: string;
    url_path?: string;
    class_name?: string;
    is_active?: boolean;
    image?: string;
    order_id?: number;
    class_text?: string | null;
}

interface MenuItemMobileData {
    id?: number;
    parent?: number;
    droppable?: boolean;
    text?: string;
    url_path?: string;
    class_name?: string;
    is_active?: boolean;
    order_id?: number;
    class_text?: string | null;
}

type MenuItem = NodeModel<MenuItemData> & {
    children?: MenuItem[];
    _id?: string;
};
type MenuItemMobile = NodeModel<MenuItemMobileData> & {
    children?: MenuItemMobile[];
};

const CustomDragPreview = (props: any) => {
    return (
        <div
            style={{
                width: '200px',
                height: '2px',
                backgroundColor: '#1976d2',
                borderRadius: '1px',
                boxShadow: '0 2px 4px rgba(0,0,0,0.2)',
                pointerEvents: 'none',
            }}
        />
    );
};

const GetLastId = (treeData: MenuItem[] | MenuItemMobile[]) => {
    if (treeData.length === 0) return 0;
    const maxId = Math.max(...treeData.map((item) => Number(item.id) || 0));
    return maxId + 1;
};

const Placeholder = (props: any) => {
    const left = props.depth * 100;
    return (
        <div
            style={{
                position: 'absolute',
                left: left,
                width: '200px',
                height: '2px',
                backgroundColor: '#1976d2',
                borderRadius: '1px',
                boxShadow: '0 2px 4px rgba(0,0,0,0.2)',
                pointerEvents: 'none',
                zIndex: 1000,
            }}
        />
    );
};

const MenuSetting = () => {
    const [isMounted, setIsMounted] = useState(false);
    const [treeData, setTreeData] = useState<MenuItem[]>([]);
    const [treeDataMobile, setTreeDataMobile] = useState<MenuItemMobile[]>([]);
    const [loading, setLoading] = useState(false);
    const [open, setOpen] = useState(false);
    const [onEdit, setOnEdit] = useState<MenuItem | MenuItemMobile | null>(null);
    const [isCreateMode, setIsCreateMode] = useState(false);
    const [isMobileModal, setIsMobileModal] = useState(false);
    const [pendingChanges, setPendingChanges] = useState<{
        desktop: any[] | null;
        mobile: any[] | null;
    }>({ desktop: null, mobile: null });

    const dispatch = useDispatch();

    const handleDrop = (newTree: any, isMobile: boolean = false) => {
        const updatedTree = newTree.map((item: any, index: number) => {
            const siblings = newTree.filter((sibling: any) => sibling.parent === item.parent);
            const siblingIndex = siblings.findIndex((sibling: any) => sibling.id === item.id);

            return {
                ...item,
                order_id: siblingIndex + 1,
            };
        });

        if (isMobile) {
            setTreeDataMobile(updatedTree);
            setPendingChanges((prev) => ({ ...prev, mobile: updatedTree }));
        } else {
            setTreeData(updatedTree);
            setPendingChanges((prev) => ({ ...prev, desktop: updatedTree }));
        }
    };

    const handleTextChange = (id: string | number, value: string, isMobile: boolean = false) => {
        const setTreeFunction = isMobile ? setTreeDataMobile : setTreeData;
        const currentTree = isMobile ? treeDataMobile : treeData;

        const newTree = currentTree.map((node) => (node.id === id || (node as any)._id === id ? { ...node, text: value } : node));
        setTreeFunction(newTree);
    };

    const createMenuData = (item: any, isMobile: boolean, droppable?: boolean) => {
        const baseData = {
            ...((item as any)._id && { _id: (item as any)._id }),
            id: item.id,
            text: item.text || '',
            url_path: (item as any).url_path || '',
            class_name: (item as any).class_name || '',
            class_text: (item as any).class_text || '',
            is_active: (item as any).is_active || false,
            parent: item.parent || 0,
            order_id: (item as any).order_id || 1,
        };

        if (droppable !== undefined) {
            baseData.droppable = droppable;
        }

        if (!isMobile) {
            (baseData as any).image = (item as any).image || '';
        }

        return baseData;
    };

    const updateParentDroppableStatus = async (parentId: number, isMobile: boolean, shouldBeDroppable: boolean) => {
        if (parentId === 0) return;

        const currentTreeData = isMobile ? treeDataMobile : treeData;
        const parentItem = currentTreeData.find((item) => item.id === parentId);

        if (!parentItem) return;

        if (shouldBeDroppable && parentItem.droppable) return;
        if (!shouldBeDroppable && !parentItem.droppable) return;

        if (!shouldBeDroppable) {
            const hasChildren = currentTreeData.some((item) => item.parent === parentId);
            if (hasChildren) return;
        }

        const updatedParentData = createMenuData(parentItem, isMobile, shouldBeDroppable);

        try {
            await updateMenu(updatedParentData, isMobile);
        } catch (error) {
            console.error('Error updating parent to non-droppable:', error);
        }
    };

    // Generic delete handler
    const handleDelete = async (id: string | number, isMobile: boolean = false) => {
        try {
            const currentTreeData = isMobile ? treeDataMobile : treeData;
            const itemToDelete = currentTreeData.find((item) => item.id === id || (item as any)._id === id);
            const parentId = itemToDelete?.parent;

            await deleteMenu(id, isMobile);

            if (parentId && parentId !== 0) {
                await updateParentDroppableStatus(Number(parentId), isMobile, false);
            }

            await getMenu();
            coloredToast('warning', `Menu ${isMobile ? 'mobile' : 'desktop'} berhasil dihapus`);
        } catch (error) {
            console.error('Error deleting menu:', error);
            coloredToast('error', `Gagal menghapus menu ${isMobile ? 'mobile' : 'desktop'}`);
        }
    };

    // Generic edit handler
    const handleEdit = (id: string | number, isMobile: boolean = false) => {
        const currentTree = isMobile ? treeDataMobile : treeData;
        const targetNode = currentTree.find((n) => n.id === id || (n as any)._id === id);

        if (targetNode) {
            setOnEdit(targetNode);
            setIsCreateMode(false);
            setIsMobileModal(isMobile);
            setOpen(true);
        }
    };

    // Generic create handler
    const handleCreate = (isMobile: boolean = false, parentId: number = 0) => {
        const newMenuItem = {
            id: '',
            text: '',
            parent: parentId,
            droppable: false,
            order_id: '',
            url_path: '',
            class_name: '',
            class_text: '',
            ...(isMobile ? {} : { image: '' }),
            is_active: true,
        };
        setOnEdit(newMenuItem);
        setIsCreateMode(true);
        setIsMobileModal(isMobile);
        setOpen(true);
    };

    // Generic submit handler
    const handleSubmit = async (newNode: MenuItem | MenuItemMobile) => {
        try {
            const isMobile = isMobileModal;
            const currentTreeData = isMobile ? treeDataMobile : treeData;

            // Generate ID dan order_id untuk create mode
            const newId = isCreateMode ? GetLastId(currentTreeData) + 1 : newNode.id || '';
            const newOrderId = isCreateMode
                ? (() => {
                      const siblings = currentTreeData.filter((item) => item.parent === (newNode.parent || 0));
                      const maxOrderId = siblings.length > 0 ? Math.max(...siblings.map((item) => (item as any).order_id || 0)) : 0;
                      return maxOrderId + 1;
                  })()
                : (newNode.data as any)?.order_id || (newNode as any).order_id || 1;

            const menuData = {
                ...(isCreateMode ? {} : { _id: (newNode as any)._id }),
                id: newId,
                text: newNode.text || '',
                droppable: (newNode.data as any)?.droppable || (newNode as any).droppable || false,
                url_path: (newNode.data as any)?.url_path || (newNode as any).url_path || '',
                class_name: (newNode.data as any)?.class_name || (newNode as any).class_name || '',
                class_text: (newNode.data as any)?.class_text || (newNode as any).class_text || '',
                ...(isMobile
                    ? {}
                    : {
                          image: (newNode.data as any)?.image || (newNode as any).image || '',
                      }),
                is_active: (newNode.data as any)?.is_active || (newNode as any).is_active || false,
                parent: newNode.parent || 0,
                order_id: newOrderId,
            };

            console.log('data yang mau di update : ', menuData);

            if (isCreateMode) {
                await createMenu(menuData, isMobile);
                if (newNode.parent && newNode.parent !== 0) {
                    await updateParentDroppableStatus(Number(newNode.parent), isMobile, true);
                }

                coloredToast('success', `Menu ${isMobile ? 'mobile' : 'desktop'} berhasil ditambahkan`);
            } else {
                await updateMenu(menuData, isMobile);
                coloredToast('success', `Menu ${isMobile ? 'mobile' : 'desktop'} berhasil diperbarui`);
            }

            await getMenu();
            setOpen(false);
            setOnEdit(null);
            setIsCreateMode(false);
            setIsMobileModal(false);
        } catch (error) {
            console.error('Error submitting menu:', error);
            coloredToast('error', 'Gagal menyimpan menu');
        }
    };

    const handleCloseModal = () => {
        setOpen(false);
        setOnEdit(null);
        setIsCreateMode(false);
        setIsMobileModal(false);
    };

    // Save pending changes
    const handleSaveChanges = async () => {
        try {
            const promises = [];

            if (pendingChanges.desktop) {
                promises.push(
                    fetch(`${process.env.API_URL}api/setting/menu-list/reorder`, {
                        method: 'PATCH',
                        headers: { 'Content-Type': 'application/json' },
                        credentials: 'include',
                        body: JSON.stringify({
                            menuTree: pendingChanges.desktop,
                            is_mobile: false,
                        }),
                    })
                );
            }

            if (pendingChanges.mobile) {
                promises.push(
                    fetch(`${process.env.API_URL}api/setting/menu-list/reorder`, {
                        method: 'PATCH',
                        headers: { 'Content-Type': 'application/json' },
                        credentials: 'include',
                        body: JSON.stringify({
                            menuTree: pendingChanges.mobile,
                            is_mobile: true,
                        }),
                    })
                );
            }

            if (promises.length > 0) {
                await Promise.all(promises);
                setPendingChanges({ desktop: null, mobile: null });
                coloredToast('success', 'Semua perubahan menu berhasil disimpan');
            } else {
                coloredToast('info', 'Tidak ada perubahan untuk disimpan');
            }
        } catch (error) {
            console.error('Error saving changes:', error);
            coloredToast('error', 'Gagal menyimpan perubahan menu');
        }
    };

    // Reset pending changes
    const handleResetChanges = async () => {
        try {
            await getMenu();
            setPendingChanges({ desktop: null, mobile: null });
            coloredToast('info', 'Perubahan dibatalkan, data dikembalikan ke kondisi semula');
        } catch (error) {
            console.error('Error resetting changes:', error);
            coloredToast('error', 'Gagal mengembalikan data');
        }
    };

    // Process tree data from API
    const processTreeData = (data: any[], isMobile: boolean) => {
        if (!data || !Array.isArray(data)) {
            return [];
        }

        const processedData = data.map((item: any, index: number) => {
            const itemId = item.id || item._id;
            const parentId = item.parent || 0;

            const processedItem = {
                _id: item._id,
                id: parseInt(itemId),
                text: item.text || item.name,
                parent: parentId,
                droppable: item.droppable,
                order_id: item.order_id,
                url_path: item.url_path || '',
                class_name: item.class_name || '',
                class_text: item.class_text || '',
                image: item.image || '',
                is_active: item.is_active || false,
            };

            return processedItem;
        });

        const uniqueData = processedData.filter((item: any, index: number, self: any[]) => index === self.findIndex((t: any) => t.id === item.id || t._id === item._id));

        // Sort by parent first, then by order_id
        const sortedData = uniqueData.sort((a: any, b: any) => {
            if (a.parent !== b.parent) {
                return a.parent - b.parent;
            }
            return (a.order_id || 0) - (b.order_id || 0);
        });

        return sortedData;
    };

    // API functions
    const getMenu = async () => {
        try {
            setLoading(true);
            const response = await fetch(`${process.env.API_URL}api/setting/menu-list-new`);
            const data = await response.json();

            const desktopData = data.menuDesktop || [];
            const mobileData = data.menuMobile || [];

            const processedDesktopData = processTreeData(desktopData, false);
            const processedMobileData = processTreeData(mobileData, true);

            setTreeData(processedDesktopData);
            setTreeDataMobile(processedMobileData);
        } catch (error) {
            console.error('Error fetching menu:', error);
            coloredToast('error', 'Gagal mengambil data menu');
        } finally {
            setLoading(false);
        }
    };

    const createMenu = async (menuData: any, isMobile: boolean) => {
        const response = await fetch(`${process.env.API_URL}api/setting/menu-list/create`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ ...menuData, is_mobile: isMobile }),
            credentials: 'include',
        });

        if (!response.ok) throw new Error('Failed to create menu');
        return response.json();
    };

    const updateMenu = async (menuData: any, isMobile: boolean) => {
        const payload = { ...menuData, is_mobile: isMobile };
        const response = await fetch(`${process.env.API_URL}api/setting/menu-list/update`, {
            method: 'PATCH',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(payload),
            credentials: 'include',
        });

        if (!response.ok) throw new Error('Failed to update menu');
        return response.json();
    };

    const deleteMenu = async (id: string | number, isMobile: boolean) => {
        const response = await fetch(`${process.env.API_URL}api/setting/menu-list/delete`, {
            method: 'DELETE',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ id, is_mobile: isMobile }),
            credentials: 'include',
        });

        if (!response.ok) throw new Error('Failed to delete menu');
        return response.json();
    };

    useEffect(() => {
        setIsMounted(true);
        dispatch(setPageTitle('Menu Setting'));
        getMenu();
    }, []);

    return (
        <>
            {isMounted && (
                <div className="flex gap-2.5 px-24 xl:flex-row">
                    {/* Desktop Menu */}
                    <div className="w-1/2">
                        <div className="mb-4 text-xl">Desktop</div>
                        <button className="mb-6 rounded-md bg-blue-300 px-4 py-2 text-black hover:bg-blue-400" onClick={() => handleCreate(false)}>
                            + Add Menu
                        </button>

                        {loading ? (
                            <div className="mt-4 text-center">Loading...</div>
                        ) : (
                            <>
                                <CssBaseline />
                                <DndProvider backend={MultiBackend} options={getBackendOptions()}>
                                    <div className={styles.desktopApp}>
                                        <Tree
                                            tree={treeData}
                                            rootId={0}
                                            render={(node, { depth, isOpen, onToggle }) => (
                                                <CustomNode
                                                    node={node}
                                                    depth={depth}
                                                    isOpen={isOpen}
                                                    onToggle={onToggle}
                                                    onTextChange={(id, value) => handleTextChange(id, value, false)}
                                                    onDelete={(id) => handleDelete(id, false)}
                                                    onEdit={(id) => handleEdit(id, false)}
                                                    onCreateChild={(parentId) => handleCreate(false, parentId as number)}
                                                />
                                            )}
                                            dragPreviewRender={(monitorProps) => <CustomDragPreview monitorProps={monitorProps} />}
                                            onDrop={(newTree) => {
                                                handleDrop(newTree, false);
                                            }}
                                            classes={{
                                                root: styles.desktopTreeRoot,
                                                draggingSource: styles.desktopDraggingSource,
                                                dropTarget: styles.desktopDropTarget,
                                                placeholder: styles.desktopPlaceholderContainer,
                                            }}
                                            sort={false}
                                            enableAnimateExpand={true}
                                            insertDroppableFirst={false}
                                            canDrop={(tree, { dragSource, dropTargetId, dropTarget }) => {
                                                if (dragSource?.id === dropTargetId) {
                                                    return false;
                                                }
                                                return true;
                                            }}
                                            dropTargetOffset={5}
                                            placeholderRender={(node, { depth }) => <Placeholder node={node} depth={depth} />}
                                        />
                                    </div>
                                </DndProvider>
                            </>
                        )}
                    </div>

                    {/* Mobile Menu */}
                    <div className="w-1/2">
                        <div className="mb-4 text-xl">Mobile</div>
                        <button className="mb-6 rounded-md bg-blue-300 px-4 py-2 text-black hover:bg-blue-400" onClick={() => handleCreate(true)}>
                            + Add Menu
                        </button>

                        {loading ? (
                            <div className="mt-4 text-center">Loading...</div>
                        ) : (
                            <>
                                <CssBaseline />
                                <DndProvider backend={MultiBackend} options={getBackendOptions()}>
                                    <div className={styles.mobileApp}>
                                        <Tree
                                            tree={treeDataMobile}
                                            rootId={0}
                                            render={(node, { depth, isOpen, onToggle }) => (
                                                <CustomNodeMobile
                                                    node={node}
                                                    depth={depth}
                                                    isOpen={isOpen}
                                                    onToggle={onToggle}
                                                    onTextChange={(id, value) => handleTextChange(id, value, true)}
                                                    onDelete={(id) => handleDelete(id, true)}
                                                    onEdit={(id) => handleEdit(id, true)}
                                                    onCreateChild={(parentId) => handleCreate(true, parentId as number)}
                                                />
                                            )}
                                            dragPreviewRender={(monitorProps) => <CustomDragPreview monitorProps={monitorProps} />}
                                            onDrop={(newTree) => {
                                                handleDrop(newTree, true);
                                            }}
                                            classes={{
                                                root: styles.mobileTreeRoot,
                                                draggingSource: styles.mobileDraggingSource,
                                                dropTarget: styles.mobileDropTarget,
                                                placeholder: styles.mobilePlaceholderContainer,
                                            }}
                                            sort={false}
                                            enableAnimateExpand={true}
                                            insertDroppableFirst={false}
                                            canDrop={(tree, { dragSource, dropTargetId, dropTarget }) => {
                                                if (dragSource?.id === dropTargetId) {
                                                    return false;
                                                }
                                                return true;
                                            }}
                                            dropTargetOffset={5}
                                            placeholderRender={(node, { depth }) => <Placeholder node={node} depth={depth} />}
                                        />
                                    </div>
                                </DndProvider>
                            </>
                        )}
                    </div>

                    {(pendingChanges.desktop || pendingChanges.mobile) && (
                        <div className="fixed bottom-4 right-4 z-50 flex gap-2">
                            <button className="rounded-md bg-red-500 px-4 py-2 text-white shadow-lg hover:bg-red-600" onClick={handleResetChanges}>
                                Reset
                            </button>
                            <button className="rounded-md bg-blue-500 px-6 py-2 text-white shadow-lg hover:bg-blue-600" onClick={handleSaveChanges}>
                                Save Changes
                            </button>
                        </div>
                    )}

                    {/* Modal */}
                    {open && onEdit && (
                        <PopupModal
                            isOpen={open}
                            onClose={handleCloseModal}
                            onSubmit={handleSubmit}
                            onEdit={onEdit}
                            isCreateMode={isCreateMode}
                            isMobile={isMobileModal}
                            treeData={treeData}
                            treeDataMobile={treeDataMobile}
                        />
                    )}
                </div>
            )}
        </>
    );
};

export default MenuSetting;
