import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import {
  ViewListIcon,
  ViewGridIcon,
  IconFileStack,
  RefreshIcon,
  MinusVerticalIcon,
  InfoIcon,
} from '../ui/icons';
import BreadcrumbTrail from '../ui/BreadcrumbTrail';
import createWorkspaceSurfaceConfig from './workspaceHeader';
import DetailPanel from '../detail/DetailPanel';
import DocumentsGrid from './DocumentsGrid';
import DocumentsList from './DocumentsList';
import { isTagTransferEvent } from './tagTransfer';

const DEFAULT_GRID_ICON_SIZE = 144;

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

const DocumentsPanel = ({
  currentFolderName,
  breadcrumbs,
  onRefresh,
  subfolders,
  documents,
  searchResults,
  isFilterActive = false,
  onFolderSelect,
  onFolderDrop,
  onFolderDragOver,
  onFolderDragLeave,
  onFolderDragStart,
  onFolderDragEnd,
  draggedFolderId,
  onFolderDelete,
  onFolderRename,
  selectedFolderIds = [],
  onDocumentOpen,
  selectedDocumentIds = [],
  focusedRowKey,
  draggingDocumentIds = [],
  onDocumentDragStart,
  onDocumentDragEnd,
  onDocumentDelete,
  onDocumentRename,
  onRowSelection = null,
  onOpenDetailPanel = null,
  tagLookupById,
  activeCorrespondentIds = [],
  onDocumentListFocus,
  onDocumentListKeyDown,
  onFocusedRowChange,
  ensureAssetUrl = null,
  getDocumentAsset = () => null,
  getDownloadHref,
  onTagClick,
  onCorrespondentClick,
  isSearchLoading = false,
  onDocumentTagDrop,
  viewMode = 'list',
  onViewModeChange,
  onClearSelection,
  showHeader = true,
}) => {
  const showingSearchResults = searchResults !== null;
  const rows = showingSearchResults ? searchResults : documents;

  const entries = useMemo(() => {
    const list = [];
    if (!showingSearchResults) {
      subfolders.forEach((folder) => {
        if (!folder || !folder.id) {
          return;
        }
        list.push({ type: EntryType.folder, id: folder.id, key: `folder:${folder.id}`, folder });
      });
    }
    rows.forEach((doc) => {
      if (!doc || !doc.id) {
        return;
      }
      list.push({ type: EntryType.document, id: doc.id, key: `document:${doc.id}`, document: doc });
    });
    return list;
  }, [showingSearchResults, subfolders, rows]);

  const selectedSet = useMemo(
    () => new Set(selectedDocumentIds),
    [selectedDocumentIds],
  );
  const selectedFolderSet = useMemo(
    () => new Set(selectedFolderIds || []),
    [selectedFolderIds],
  );
  const draggingSet = useMemo(
    () => new Set(draggingDocumentIds || []),
    [draggingDocumentIds],
  );
  const activeCorrespondentIdSet = useMemo(
    () => new Set(activeCorrespondentIds || []),
    [activeCorrespondentIds],
  );
  const scrollRef = useRef(null);
  const suppressDocumentClickRef = useRef(false);
  const [, forceVisibilityTick] = useState(0);
  const lastScrollNodeRef = useRef(null);
  const assignScrollRef = useCallback((node) => {
    if (lastScrollNodeRef.current === node) {
      return;
    }
    lastScrollNodeRef.current = node;
    scrollRef.current = node;
    if (node) {
      forceVisibilityTick((value) => value + 1);
    }
  }, []);
  const isGridView = viewMode === 'grid';
  const isDeskView = viewMode === 'desk';
  const isListView = viewMode === 'list';
  const gridIconSize = DEFAULT_GRID_ICON_SIZE;
  const handleSetViewMode = useCallback(
    (nextMode) => {
      if (!onViewModeChange) {
        return;
      }
      onViewModeChange(nextMode);
      if (scrollRef.current) {
        scrollRef.current.scrollTop = 0;
      }
    },
    [onViewModeChange],
  );
  useEffect(() => {
    if (scrollRef.current) {
      scrollRef.current.scrollTop = 0;
    }
  }, [viewMode]);
  const isTagDragEvent = useCallback((event) => isTagTransferEvent(event), []);
  const ensureFocusedRowVisible = useCallback(() => {
    if (!focusedRowKey) return;
    const container = scrollRef.current;
    if (!container) return;
    let selector = null;
    if (focusedRowKey.startsWith('document:')) {
      selector = `#document-row-${focusedRowKey.slice('document:'.length)}`;
    } else if (focusedRowKey.startsWith('folder:')) {
      selector = `#folder-row-${focusedRowKey.slice('folder:'.length)}`;
    }
    if (!selector) {
      return;
    }
    const row = container.querySelector(selector);
    if (!row || !container.contains(row)) {
      return;
    }

    const header = container.querySelector('thead');
    const headerHeight = header ? header.getBoundingClientRect().height : 0;
    const rowTop = row.offsetTop;
    const rowBottom = rowTop + row.offsetHeight;
    const visibleTop = container.scrollTop + headerHeight;
    const visibleBottom = container.scrollTop + container.clientHeight;

    if (rowTop < visibleTop) {
      container.scrollTop = Math.max(rowTop - headerHeight, 0);
      return;
    }

    if (rowBottom > visibleBottom) {
      const nextScrollTop = rowBottom - container.clientHeight;
      container.scrollTop = Math.max(nextScrollTop, 0);
    }
  }, [focusedRowKey]);

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

  const activeDescendantId = useMemo(() => {
    if (!focusedRowKey) return undefined;
    if (focusedRowKey.startsWith('document:')) {
      return `document-row-${focusedRowKey.slice('document:'.length)}`;
    }
    if (focusedRowKey.startsWith('folder:')) {
      return `folder-row-${focusedRowKey.slice('folder:'.length)}`;
    }
    return undefined;
  }, [focusedRowKey]);

  const handleDocumentTagDragOver = useCallback(
    (event) => {
      if (!isTagDragEvent(event)) {
        return;
      }
      event.preventDefault();
      event.dataTransfer.dropEffect = 'copy';
      event.currentTarget.classList.add('tag-drop-target');
    },
    [isTagDragEvent],
  );

  const handleDocumentTagDragLeave = useCallback(
    (event) => {
      if (!isTagDragEvent(event)) {
        return;
      }
      if (event.relatedTarget && event.currentTarget.contains(event.relatedTarget)) {
        return;
      }
      event.currentTarget.classList.remove('tag-drop-target');
    },
    [isTagDragEvent],
  );

  const handleDocumentTagDrop = useCallback(
    (event, documentId) => {
      if (!isTagDragEvent(event)) {
        return;
      }
      event.preventDefault();
      event.stopPropagation();
      event.currentTarget.classList.remove('tag-drop-target');
      const payload =
        event.dataTransfer.getData('application/x-papercrate-tag') ||
        event.dataTransfer.getData('text/papercrate-tag');
      if (!payload) {
        return;
      }
      try {
        const parsed = JSON.parse(payload);
        if (parsed?.id && onDocumentTagDrop) {
          onDocumentTagDrop(documentId, parsed);
        }
      } catch (error) {
        console.warn('[documents] Failed to parse tag drop payload', error);
      }
    },
    [isTagDragEvent, onDocumentTagDrop],
  );

  const handleEntryClick = useCallback(
    (entry, event) => {
      if (!entry || !entry.id) {
        return;
      }
      if (entry.type === EntryType.document && suppressDocumentClickRef.current) {
        return;
      }

      const rowKey = entry.type === EntryType.document ? `document:${entry.id}` : `folder:${entry.id}`;

      if (rowKey && typeof onRowSelection === 'function') {
        onRowSelection(rowKey, event);
      }

      if (entry.type === EntryType.document) {
        const hasModifier = Boolean(
          event && (event.shiftKey || event.metaKey || event.ctrlKey || event.altKey),
        );
        if (!hasModifier && typeof onOpenDetailPanel === 'function') {
          onOpenDetailPanel();
        }
        return;
      }

      if (entry.type === EntryType.folder) {
        const hasModifier = Boolean(
          event && (event.shiftKey || event.metaKey || event.ctrlKey || event.altKey),
        );
        const isPrimaryClick = Boolean(event && event.type === 'click' && event.button === 0);
        if (!hasModifier && isPrimaryClick && typeof onFolderSelect === 'function') {
          onFolderSelect(entry.id);
        }
        if (scrollRef.current) {
          scrollRef.current.focus({ preventScroll: true });
        }
        onFocusedRowChange?.(rowKey);
      }
    },
    [onRowSelection, onOpenDetailPanel, onFocusedRowChange, onFolderSelect],
  );

  const handleDocumentClick = useCallback(
    (doc, event) => {
      if (!doc) {
        return;
      }
      handleEntryClick({ type: EntryType.document, id: doc.id, document: doc }, event);
    },
    [handleEntryClick],
  );

  const handleFolderClick = useCallback(
    (folder, event) => {
      if (!folder) {
        return;
      }
      handleEntryClick({ type: EntryType.folder, id: folder.id, folder }, event);
    },
    [handleEntryClick],
  );

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

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

  const hasDocumentEntries = useMemo(
    () => entries.some((entry) => entry.type === EntryType.document),
    [entries],
  );
  const showTableRows = entries.length > 0;
  const showDefaultEmptyState = !showingSearchResults && !isFilterActive && entries.length === 0;
  const showListSearchEmptyState = showingSearchResults && !hasDocumentEntries && !isGridView && !isSearchLoading;
  const showGridSearchEmptyState = isGridView && showingSearchResults && !hasDocumentEntries && !isSearchLoading;
  const showSearchHint = showingSearchResults && rows.length > 0;
  const breadcrumbEntries = useMemo(() => (Array.isArray(breadcrumbs) ? breadcrumbs.filter(Boolean) : []), [breadcrumbs]);
  const trailEntries = useMemo(() => {
    if (!breadcrumbEntries.length) {
      return [{ id: 'current-folder', label: currentFolderName }];
    }
    const lastIndex = breadcrumbEntries.length - 1;
    return breadcrumbEntries.map((crumb, index) => ({
      id: crumb.id ?? index,
      label: crumb.name ?? crumb.label ?? crumb.title ?? '',
      onClick: index < lastIndex && onFolderSelect
        ? () => onFolderSelect(crumb.id)
        : null,
    }));
  }, [breadcrumbEntries, currentFolderName, onFolderSelect]);

  return (
    <section
      className={`documents-panel documents-panel--view-${isGridView ? 'grid' : 'list'}`}
    >
      {showHeader ? (
        <div className="panel-section__header">
          <div className="panel-section__titles">
            <h2 className="documents-panel__title">
              <BreadcrumbTrail
                entries={trailEntries}
                className="documents-panel__breadcrumbs"
                separator="/"
              />
            </h2>
            {showingSearchResults && (
              <div className="panel-section__subtitle">Search results</div>
            )}
          </div>
          <div className="header-actions">
            <div className="view-toggle" role="group" aria-label="Change view">
              <button
                type="button"
                className={`view-toggle__button${isListView ? ' active' : ''}`}
                onClick={() => handleSetViewMode('list')}
                aria-pressed={isListView}
                title="List view"
              >
                <ViewListIcon className="view-toggle__icon" size={18} />
              </button>
              <button
                type="button"
                className={`view-toggle__button${isGridView ? ' active' : ''}`}
                onClick={() => handleSetViewMode('grid')}
                aria-pressed={isGridView}
                title="Icons view"
              >
                <ViewGridIcon className="view-toggle__icon" size={18} />
              </button>
              <button
                type="button"
                className={`view-toggle__button${isDeskView ? ' active' : ''}`}
                onClick={() => handleSetViewMode('desk')}
                aria-pressed={isDeskView}
                title="Desk view"
              >
                <IconFileStack className="view-toggle__icon" size={18} />
              </button>
            </div>
            <button className="secondary" onClick={onRefresh}>
              Refresh
            </button>
          </div>
        </div>
      ) : null}
      {showDefaultEmptyState ? (
        <div className="panel-section__body">
          <div className="empty-state">
            Drop files anywhere or onto a folder to upload documents.
          </div>
        </div>
      ) : showGridSearchEmptyState ? (
        <div className="panel-section__body">
          <div className="empty-state empty-state--global">
            No documents match the current filters.
          </div>
        </div>
      ) : showListSearchEmptyState ? (
        <div className="panel-section__body">
          <div className="empty-state">No documents match the current filters.</div>
        </div>
      ) : (
        <div className="panel-section__body">
          <div
            ref={assignScrollRef}
            className="documents-scroll"
            tabIndex={0}
            onFocus={(event) => {
              if (event.target === scrollRef.current) {
                onDocumentListFocus?.();
              }
            }}
            onKeyDown={(event) => {
              if (event.target !== scrollRef.current) {
                return;
              }
              if (onDocumentListKeyDown) {
                onDocumentListKeyDown(event);
              }
            }}
            onClick={(event) => {
              if (event.target === event.currentTarget) {
                onClearSelection?.();
              }
            }}
            aria-activedescendant={isGridView ? undefined : activeDescendantId}
          >
            {isGridView ? (
              <DocumentsGrid
                entries={entries}
                selectedDocumentIdsSet={selectedSet}
                selectedFolderIdsSet={selectedFolderSet}
                draggingDocumentIdsSet={draggingSet}
                draggedFolderId={draggedFolderId}
                onFolderClick={handleFolderClick}
                onFolderSelect={onFolderSelect}
                onFolderDragOver={onFolderDragOver}
                onFolderDragLeave={onFolderDragLeave}
                onFolderDrop={onFolderDrop}
                onFolderDragStart={onFolderDragStart}
                onFolderDragEnd={onFolderDragEnd}
                onDocumentClick={handleDocumentClick}
                onDocumentOpen={onDocumentOpen}
                onDocumentDragStart={handleDocumentDragStartLocal}
                onDocumentDragEnd={handleDocumentDragEndLocal}
                onDocumentTagDragOver={handleDocumentTagDragOver}
                onDocumentTagDragLeave={handleDocumentTagDragLeave}
                onDocumentTagDrop={handleDocumentTagDrop}
                ensureAssetUrl={ensureAssetUrl}
                getDocumentAsset={getDocumentAsset}
                gridIconSize={gridIconSize}
                tagLookupById={tagLookupById}
                onTagClick={onTagClick}
                scrollRef={scrollRef}
                onCorrespondentClick={onCorrespondentClick}
                activeCorrespondentIdSet={activeCorrespondentIdSet}
                onClearSelection={onClearSelection}
              />
            ) : !showTableRows ? null : (
              <DocumentsList
                entries={entries}
                focusedRowKey={focusedRowKey}
                selectedDocumentIdsSet={selectedSet}
                selectedFolderIdsSet={selectedFolderSet}
                draggingDocumentIdsSet={draggingSet}
                draggedFolderId={draggedFolderId}
                ensureAssetUrl={ensureAssetUrl}
                getDocumentAsset={getDocumentAsset}
                getDownloadHref={getDownloadHref}
                onFolderClick={handleFolderClick}
                onFolderSelect={onFolderSelect}
                onFolderDragOver={onFolderDragOver}
                onFolderDragLeave={onFolderDragLeave}
                onFolderDrop={onFolderDrop}
                onFolderDragStart={onFolderDragStart}
                onFolderDragEnd={onFolderDragEnd}
                onFolderRename={onFolderRename}
                onFolderDelete={onFolderDelete}
                onDocumentClick={handleDocumentClick}
                onDocumentOpen={onDocumentOpen}
                onDocumentDragStart={handleDocumentDragStartLocal}
                onDocumentDragEnd={handleDocumentDragEndLocal}
                onDocumentTagDragOver={handleDocumentTagDragOver}
                onDocumentTagDragLeave={handleDocumentTagDragLeave}
                onDocumentTagDrop={handleDocumentTagDrop}
                onDocumentRename={onDocumentRename}
                onDocumentDelete={onDocumentDelete}
                tagLookupById={tagLookupById}
                onTagClick={onTagClick}
                onCorrespondentClick={onCorrespondentClick}
                activeCorrespondentIdSet={activeCorrespondentIdSet}
                scrollRef={scrollRef}
              />
            )}
          </div>
          {showSearchHint && (
            <div className="search-hint">
              Showing {rows.length} document{rows.length === 1 ? '' : 's'} in {currentFolderName} and subfolders.
            </div>
          )}
        </div>
      )}
    </section>
  );
};

export default DocumentsPanel;

export const createDocumentsTableHeaderActions = ({
  viewMode,
  onViewModeChange,
  onRefresh,
  onShowDeskHelp = null,
}) => {
  const isListView = viewMode === 'list';
  const isGridView = viewMode === 'grid';
  const isDeskView = viewMode === 'desk';

  return (
    <>
      <div className="view-toggle" role="group" aria-label="Change view">
        <button
          type="button"
          className={`view-toggle__button${isListView ? ' active' : ''}`}
          onClick={() => onViewModeChange?.('list')}
          aria-pressed={isListView}
          title="List view"
        >
          <ViewListIcon className="view-toggle__icon" size={18} />
        </button>
        <button
          type="button"
          className={`view-toggle__button${isGridView ? ' active' : ''}`}
          onClick={() => onViewModeChange?.('grid')}
          aria-pressed={isGridView}
          title="Icons view"
        >
          <ViewGridIcon className="view-toggle__icon" size={18} />
        </button>
        <button
          type="button"
          className={`view-toggle__button${isDeskView ? ' active' : ''}`}
          onClick={() => onViewModeChange?.('desk')}
          aria-pressed={isDeskView}
          title="Desk view"
        >
          <IconFileStack className="view-toggle__icon" size={18} />
        </button>
      </div>
      <span className="main-content__actions-divider" aria-hidden="true">
        <MinusVerticalIcon />
      </span>
      <button
        type="button"
        className="icon-button"
        onClick={onRefresh}
        aria-label="Refresh"
        title="Refresh"
      >
        <RefreshIcon />
      </button>
      {isDeskView && typeof onShowDeskHelp === 'function' ? (
        <button
          type="button"
          className="icon-button"
          onClick={onShowDeskHelp}
          aria-label="Show desk view tips"
          title="Show desk view tips"
        >
          <InfoIcon />
        </button>
      ) : null}
    </>
  );
};

export const createDocumentsSurface = ({
  tableProps,
  parentBreadcrumb,
  onNavigateParent,
  renderSidebarToggle,
  detailProps,
  detailOpen = false,
}) => {
  const {
    currentFolderName,
    breadcrumbs,
    searchResults,
    viewMode,
    onViewModeChange,
    onRefresh,
  } = tableProps;

  const title = Array.isArray(searchResults) ? 'Search results' : currentFolderName;
  const subtitle = Array.isArray(searchResults)
    ? `${searchResults.length} matching document${searchResults.length === 1 ? '' : 's'}`
    : null;

  const actions = createDocumentsTableHeaderActions({
    viewMode,
    onViewModeChange,
    onRefresh,
  });

  const sidebarToggle = renderSidebarToggle ? renderSidebarToggle() : null;
  const detail = detailOpen && detailProps ? <DetailPanel {...detailProps} /> : null;

  const surfaceConfig = createWorkspaceSurfaceConfig({
    key: 'documents',
    variant: 'documents',
    title,
    subtitle,
    sidebarToggle,
    parentBreadcrumb,
    onNavigateParent,
    actions,
    breadcrumbs,
    content: <DocumentsPanel {...tableProps} showHeader={false} />,
    detail,
  });

  return surfaceConfig;
};
