import { useMemo, useCallback, useRef } from 'react';
import type { DocumentsPanelInnerProps } from './DocumentsPanel';
import { isPointerModifierEvent, isPrimaryPointerEvent } from '../features/selection/useEntryPointer';
import { useDocumentsFilter } from '../context/DocumentsFilterContext';
import { useWorkspaceSelectionContext } from '../../app/WorkspaceSelectionContext';
import type { Identifier } from '../../types/identifiers';
import { useTagInteractions } from '../interactions/useTagInteractions';

const EntryType = {
    folder: 'folder',
    document: 'document',
};

export const useDocumentsContextValues = (props: DocumentsPanelInnerProps) => {
    const {
        ensureAssetUrl,
        getDocumentAsset,
        isSearchLoading,
        searchQuery = '',
        activeTagFilters = [],
        activeCorrespondentFilters = [],
        selectedFolder = null,
        onDocumentDragStart,
        onDocumentDragEnd,
        onEntryPointer,
        activeCorrespondentIds = [],
        draggingDocumentIds = [],
        tagLookupById,
    } = props;

    const {
        setFocusedEntryKey,
    } = useWorkspaceSelectionContext();

    const {
        toggleTag: toggleTagFilter,
        toggleCorrespondent: toggleCorrespondentFilter,
    } = useDocumentsFilter();

    // Handlers
    const tagDragHandlers = useTagInteractions({
        onAssignTagToDocument: props.onDocumentTagAttach,
        onRemoveTagFromDocument: props.onDocumentTagDetach,
    });

    // Derived State
    const draggingDocumentIdsSet = useMemo(
        () => new Set(draggingDocumentIds || []),
        [draggingDocumentIds],
    );
    const activeCorrespondentIdSet = useMemo(
        () => new Set(activeCorrespondentIds || []),
        [activeCorrespondentIds],
    );
    const showingSearchResults = Array.isArray(props.searchResultIds);
    const hasDocumentEntries = (props.documents || []).length > 0 || (showingSearchResults && (props.searchResultIds || []).length > 0);

    const viewId = useMemo(() => {
        if (showingSearchResults) {
            const trimmedQuery = searchQuery.trim();
            const tagsKey = [...activeTagFilters].sort().join(',');
            const correspondentsKey = [...activeCorrespondentFilters].sort().join(',');
            return `search:${trimmedQuery}|tags:${tagsKey}|corr:${correspondentsKey}`;
        }
        const folderKey = selectedFolder && selectedFolder !== '' ? selectedFolder : 'root';
        return `folder:${folderKey}`;
    }, [
        showingSearchResults,
        searchQuery,
        activeTagFilters,
        activeCorrespondentFilters,
        selectedFolder,
    ]);

    // Refs
    const scrollRef = useRef<HTMLElement | null>(null);
    const suppressDocumentClickRef = useRef(false);

    const handleFolderClick = useCallback(
        (folder: any, event: any) => {
            if (!folder) {
                return;
            }

            if (onEntryPointer) {
                onEntryPointer(
                    { type: EntryType.folder, id: folder.id, key: `folder:${folder.id}`, folder },
                    event,
                );
            }

            if (
                !isPointerModifierEvent(event)
                && isPrimaryPointerEvent(event)
                && scrollRef.current
            ) {
                scrollRef.current.focus({ preventScroll: true });
                setFocusedEntryKey(`folder:${folder.id}`);
            }
        },
        [onEntryPointer, setFocusedEntryKey],
    );

    const handleDocumentDragStartLocal = useCallback(
        (event: any, doc: any) => {
            suppressDocumentClickRef.current = true;
            onDocumentDragStart?.(event, doc);
        },
        [onDocumentDragStart],
    );

    const handleDocumentDragEndLocal = useCallback(
        (event: any) => {
            onDocumentDragEnd?.(event);
            requestAnimationFrame(() => {
                suppressDocumentClickRef.current = false;
            });
        },
        [onDocumentDragEnd],
    );

    // Context Values Construction
    const assetContextValue = useMemo(() => ({
        ensureAssetUrl,
        getDocumentAsset,
    }), [ensureAssetUrl, getDocumentAsset]);

    const viewStateContextValue = useMemo(() => ({
        viewId,
        scrollRef,
        tagLookupById,
        activeCorrespondentIdSet,
        draggingDocumentIdsSet,
        draggedFolderId: props.draggedFolderId,
    }), [
        viewId,
        scrollRef,
        tagLookupById,
        activeCorrespondentIdSet,
        draggingDocumentIdsSet,
        props.draggedFolderId,
    ]);

    // Use refs to stabilize handlers and avoid massive dependency arrays
    const latestPropsRef = useRef(props);
    const latestHandlersRef = useRef({
        handleFolderClick,
        handleDocumentDragStartLocal,
        handleDocumentDragEndLocal,
        tagDragHandlers,
        toggleTagFilter,
        toggleCorrespondentFilter,
    });

    // Update refs on every render
    latestPropsRef.current = props;
    latestHandlersRef.current = {
        handleFolderClick,
        handleDocumentDragStartLocal,
        handleDocumentDragEndLocal,
        tagDragHandlers,
        toggleTagFilter,
        toggleCorrespondentFilter,
    };

    const commandContextValue = useMemo(() => ({
        folder: {
            onClick: (f: any, e: any) => latestHandlersRef.current.handleFolderClick(f, e),
            onSelect: (id: Identifier) => latestPropsRef.current.onFolderSelect?.(id),
            onRename: (id: Identifier, name: string) => latestPropsRef.current.onFolderRename?.(id, name),
            onDrag: {
                start: (e: any, f: any) => latestPropsRef.current.onFolderDragStart?.(e, f),
                end: (e: any) => latestPropsRef.current.onFolderDragEnd?.(e),
                over: (e: any, f: any) => latestPropsRef.current.onFolderDragOver?.(e, f),
                leave: (e: any) => latestPropsRef.current.onFolderDragLeave?.(e),
                drop: (e: any, f: any) => latestPropsRef.current.onFolderDrop?.(e, f),
            },
        },
        document: {
            onRename: (id: Identifier, name: string) => latestPropsRef.current.onDocumentRename?.(id, name),
            onDrag: {
                start: (e: any, d: any) => latestHandlersRef.current.handleDocumentDragStartLocal(e, d),
                end: (e: any) => latestHandlersRef.current.handleDocumentDragEndLocal(e),
            },
        },
        tags: {
            onAttach: (d: any, t: any) => latestPropsRef.current.onDocumentTagAttach?.(d, t),
            onDetach: (d: any, t: any) => latestPropsRef.current.onDocumentTagDetach?.(d, t),
            onClick: (t: any) => latestHandlersRef.current.toggleTagFilter(t),
        },
        correspondents: {
            onClick: (c: any) => latestHandlersRef.current.toggleCorrespondentFilter(c),
        },
        onEntryPointer: (entry: any, e: any) => latestPropsRef.current.onEntryPointer?.(entry, e),
    }), []);

    return {
        assetContextValue,
        viewStateContextValue,
        commandContextValue,
        tagDragHandlers,
        scrollRef,
        hasDocumentEntries,
        isSearchLoading,
        showingSearchResults,
        activeTagFilters,
        activeCorrespondentFilters,
    };
};
