import React, { CSSProperties, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import useFloatingMenu from '../ui/useFloatingMenu';
import {
    ArrowLeftIcon,
    FolderIcon,
    FolderMoveIcon,
} from '../ui/icons';
import type { FolderTreeNode } from '../lib/apiTypes';
import type { DocumentId } from '../types/identifiers';

export interface SelectionFolderMenuProps {
    label: React.ReactNode;
    folderTree?: FolderTreeNode[];
    onSelectFolder?: (folderId: DocumentId | null) => Promise<void> | void;
    disabled?: boolean;
    className?: string;
    triggerContent?: React.ReactNode;
    triggerClassName?: string;
    placeholder?: string;
    emptyMessage?: string;
    onOpenMenu?: () => void;
    positionStrategy?: 'absolute' | 'fixed';
    rootTitle?: string;
}

const SelectionFolderMenu: React.FC<SelectionFolderMenuProps> = ({
    label,
    folderTree = [],
    onSelectFolder,
    disabled = false,
    className,
    triggerContent = null,
    triggerClassName = 'quick-add__chip quick-add__trigger panel-floating-actions__trigger',
    placeholder = 'Search folders…',
    emptyMessage = 'No folders',
    onOpenMenu,
    positionStrategy = 'absolute',
    rootTitle = 'Folders',
}) => {
    const anchorRef = useRef<HTMLButtonElement | null>(null);
    const inputRef = useRef<HTMLInputElement | null>(null);
    const [query, setQuery] = useState('');
    const [currentFolderId, setCurrentFolderId] = useState<DocumentId | null>(null);
    const [pending, setPending] = useState(false);

    const {
        isOpen,
        toggle,
        close,
        menuRef,
        menuStyle,
        updatePosition,
    } = useFloatingMenu({
        anchorRef,
        align: 'center',
        positionStrategy,
        minWidth: 260,
    }) as {
        isOpen: boolean;
        toggle: () => void;
        close: () => void;
        menuRef: React.MutableRefObject<HTMLDivElement | null>;
        menuStyle: CSSProperties | null;
        updatePosition: () => void;
    };

    useEffect(() => {
        if (disabled && isOpen) {
            close();
        }
    }, [disabled, isOpen, close]);

    useEffect(() => {
        if (!isOpen) {
            return undefined;
        }
        setQuery('');
        setCurrentFolderId(null);
        setPending(false);
        const frame = requestAnimationFrame(() => {
            updatePosition();
            if (inputRef.current) {
                inputRef.current.focus();
            }
        });
        return () => cancelAnimationFrame(frame);
    }, [isOpen, updatePosition]);

    // Build a flat map for easy lookup
    const { nodeMap, parentMap } = useMemo(() => {
        const nMap = new Map<DocumentId, FolderTreeNode>();
        const pMap = new Map<DocumentId, DocumentId>();

        const traverse = (nodes: FolderTreeNode[], parentId: DocumentId | null) => {
            nodes.forEach((node) => {
                nMap.set(node.id, node);
                if (parentId) {
                    pMap.set(node.id, parentId);
                }
                if (node.children) {
                    traverse(node.children, node.id);
                }
            });
        };
        traverse(folderTree, null);
        return { nodeMap: nMap, parentMap: pMap };
    }, [folderTree]);

    const currentChildren = useMemo(() => {
        const currentFolder = currentFolderId ? nodeMap.get(currentFolderId) : null;
        return currentFolder ? currentFolder.children || [] : folderTree;
    }, [currentFolderId, nodeMap, folderTree]);

    const currentFolder = currentFolderId ? nodeMap.get(currentFolderId) : null;

    // Filter items based on search query
    // If searching, we might want to show flattened results matching the query?
    // Or just filter current level?
    // Usually, search implies searching the whole tree.
    const isSearching = query.trim().length > 0;

    const displayedItems = useMemo(() => {
        if (isSearching) {
            const search = query.trim().toLowerCase();
            const results: FolderTreeNode[] = [];
            nodeMap.forEach((node) => {
                if (node.name.toLowerCase().includes(search)) {
                    results.push(node);
                }
            });
            return results;
        }
        return currentChildren;
    }, [isSearching, query, currentChildren, nodeMap]);

    const handleTriggerClick = useCallback(() => {
        if (disabled) {
            return;
        }
        if (!isOpen) {
            onOpenMenu?.();
        }
        toggle();
    }, [disabled, isOpen, onOpenMenu, toggle]);

    const handleSelect = useCallback(
        async (folderId: DocumentId | null) => {
            if (!onSelectFolder) return;
            setPending(true);
            try {
                await onSelectFolder(folderId);
                close();
            } catch (error) {
                console.error('Failed to move to folder', error);
            } finally {
                setPending(false);
            }
        },
        [onSelectFolder, close]
    );

    const handleNavigate = (folderId: DocumentId) => {
        setCurrentFolderId(folderId);
        setQuery(''); // Clear search on navigation
        if (inputRef.current) {
            inputRef.current.focus();
        }
    };

    const handleUp = () => {
        if (!currentFolderId) return;
        const parentId = parentMap.get(currentFolderId) || null;
        setCurrentFolderId(parentId);
    };

    return (
        <div className={className ? `selection-assignment ${className}` : 'selection-assignment'}>
            <button
                type="button"
                ref={anchorRef}
                className={triggerClassName}
                onClick={handleTriggerClick}
                aria-haspopup="menu"
                aria-expanded={isOpen}
                disabled={disabled}
            >
                {triggerContent ? triggerContent : (
                    <span className="quick-add__chip-label">
                        {label}
                    </span>
                )}
            </button>
            {isOpen ? (
                <div
                    className="menu menu--floating selection-assignment__menu"
                    ref={menuRef}
                    style={menuStyle || undefined}
                    role="menu"
                    data-floating-position
                >
                    <div className="selection-assignment__header">
                        {/* Search Bar */}
                        <div className="selection-assignment__form">
                            <input
                                ref={inputRef}
                                type="text"
                                value={query}
                                onChange={(event) => setQuery(event.target.value)}
                                placeholder={placeholder}
                                aria-label={placeholder}
                                disabled={pending}
                            />
                        </div>

                        {/* Navigation Header (only if not searching) */}
                        {!isSearching && (
                            <div className="selection-assignment__header-nav">
                                <div className="selection-assignment__nav-title">
                                    {currentFolderId ? (
                                        <button
                                            type="button"
                                            className="icon-button"
                                            onClick={handleUp}
                                            aria-label="Go up"
                                            title="Go up"
                                        >
                                            <ArrowLeftIcon size="1em" />
                                        </button>
                                    ) : null}
                                    <span
                                        className="selection-assignment__folder-name"
                                    >
                                        {currentFolder ? currentFolder.name : rootTitle}
                                    </span>
                                </div>

                                <div className="selection-assignment__nav-actions">
                                    <button
                                        type="button"
                                        className="icon-button"
                                        onClick={() => handleSelect(currentFolderId)}
                                        disabled={pending}
                                        title="Move here"
                                        aria-label="Move here"
                                    >
                                        <FolderMoveIcon size="1em" />
                                    </button>
                                </div>
                            </div>
                        )}
                    </div>

                    <div className="selection-assignment__list" role="presentation">
                        {displayedItems.length ? (
                            displayedItems.map((item) => {
                                const hasChildren = item.children && item.children.length > 0;
                                return (
                                    <div
                                        key={item.id}
                                        className={`menu__item selection-assignment__item${!hasChildren ? ' selection-assignment__item--empty' : ''}`}
                                        role="menuitem"
                                    >
                                        {/* Clickable area to navigate down */}
                                        <button
                                            type="button"
                                            className="selection-assignment__item-content"
                                            onClick={() => hasChildren && handleNavigate(item.id)}
                                            style={{ cursor: hasChildren ? 'pointer' : 'default' }}
                                        >
                                            <FolderIcon className="selection-assignment__icon" aria-hidden="true" />
                                            <span className="selection-assignment__folder-name">
                                                {item.name}
                                                {isSearching && parentMap.get(item.id) && (
                                                    <span className="selection-assignment__folder-path">
                                                        (in {nodeMap.get(parentMap.get(item.id)!)?.name})
                                                    </span>
                                                )}
                                            </span>
                                        </button>

                                        {/* Move Button for this specific folder */}
                                        <div className="selection-assignment__item-actions">
                                            <button
                                                type="button"
                                                className="icon-button"
                                                onClick={(e) => {
                                                    e.stopPropagation();
                                                    handleSelect(item.id);
                                                }}
                                                title={`Move to ${item.name}`}
                                                aria-label={`Move to ${item.name}`}
                                            >
                                                <FolderMoveIcon size="1em" />
                                            </button>
                                        </div>
                                    </div>
                                );
                            })
                        ) : (
                            <div className="menu__empty selection-assignment__empty">{emptyMessage}</div>
                        )}
                    </div>
                </div>
            ) : null}
        </div>
    );
};

export default SelectionFolderMenu;
