import React, { useEffect, useCallback } from 'react';
import { useDocumentViewLogic, DocumentViewLogic } from './hooks/useDocumentViewLogic';
import { useDocumentsNavigation } from './hooks/useDocumentsNavigation';
import { useWorkspaceSelectionContext } from '../app/WorkspaceSelectionContext';
import { usePreviewContext } from '../preview/PreviewContext';
import DocumentsListRow from './components/DocumentsListRow';
import DocumentsGridCard from './components/DocumentsGridCard';
import DocumentsListContainer from './components/DocumentsListContainer';
import DocumentsGridContainer from './components/DocumentsGridContainer';
import type { DocumentsViewProps } from './panel/DocumentsPanel';

interface AbstractDocumentsViewProps<CProps extends { clearSelection: () => void; children: React.ReactNode }> extends DocumentsViewProps {
    ContainerComponent: React.ComponentType<CProps>;
    ItemComponent: React.ComponentType<{ entry: any; viewLogic: DocumentViewLogic } & DocumentsViewProps>;
    containerProps?: Omit<CProps, 'children' | 'clearSelection'>;
    [key: string]: any;
}

const AbstractDocumentsView = <CProps extends { clearSelection: () => void; children: React.ReactNode }>({
    ContainerComponent,
    ItemComponent,
    containerProps,
    ...props
}: AbstractDocumentsViewProps<CProps>) => {
    const { entries, onDocumentRename, onFolderRename, onFolderSelect, scrollRef, viewId } = props;
    const { openPreview } = usePreviewContext();
    const viewLogic = useDocumentViewLogic({
        onDocumentRename,
        onFolderRename,
    });
    const { handleKeyDown, handleFocus } = useDocumentsNavigation({
        entries,
        onFolderSelect,
        onPreview: openPreview,
        viewMode: props.viewMode,
        scrollRef: props.scrollRef,
    });
    const { clearSelection } = viewLogic;

    useEffect(() => {
        if (scrollRef?.current) {
            scrollRef.current.scrollTop = 0;
        }
    }, [scrollRef, viewId]);

    const { focusedEntryKey } = useWorkspaceSelectionContext();

    const ensureFocusedEntryVisible = useCallback(() => {
        if (!focusedEntryKey) return;
        const container = scrollRef?.current;
        if (!container) return;
        let selector = null;
        if (focusedEntryKey.startsWith('document:')) {
            selector = `#document-${focusedEntryKey.slice('document:'.length)}`;
        } else if (focusedEntryKey.startsWith('folder:')) {
            selector = `#folder-${focusedEntryKey.slice('folder:'.length)}`;
        }
        if (!selector) {
            return;
        }
        const entry = container.querySelector(selector) as HTMLElement;
        if (!entry || !container.contains(entry)) {
            return;
        }

        entry.scrollIntoView({ block: 'nearest' });
    }, [focusedEntryKey, scrollRef]);

    useEffect(() => {
        ensureFocusedEntryVisible();
    }, [ensureFocusedEntryVisible]);

    return (
        <ContainerComponent
            clearSelection={clearSelection}
            onKeyDown={handleKeyDown}
            onFocus={handleFocus}
            tabIndex={0}
            {...(containerProps as any)}
        >
            {entries.map((entry) => (
                <ItemComponent
                    key={entry.key}
                    entry={entry}
                    viewLogic={viewLogic}
                    {...props}
                    onPreview={openPreview}
                />
            ))}
        </ContainerComponent>
    );
};

export const DocumentsList: React.FC<DocumentsViewProps> = (props) => {
    return (
        <AbstractDocumentsView
            ContainerComponent={DocumentsListContainer}
            ItemComponent={DocumentsListRow}
            viewMode="list"
            {...props}
        />
    );
};

export const DocumentsGrid: React.FC<DocumentsViewProps & { gridIconSize?: number }> = (props) => {
    return (
        <AbstractDocumentsView
            ContainerComponent={DocumentsGridContainer}
            ItemComponent={DocumentsGridCard}
            containerProps={{ gridIconSize: props.gridIconSize }}
            viewMode="grid"
            {...props}
        />
    );
};
