import { startTransition, useDeferredValue, useEffect, useMemo, useState } from 'react';
import { driveData } from './data/driveData';
import { formatBytes } from './lib/fileSystemAccess';
import {
  checkLocalApiAvailability,
  clearSavedDirectoryPath,
  loadSavedDirectoryPath,
  saveDirectoryPath,
  scanLocalDirectory,
} from './lib/localDriveApi';

const ROOT_ID = 'root';
const DEMO_STORAGE_BYTES = 38.88 * 1024 * 1024 * 1024;
const STORAGE_CAPACITY_BYTES = 200 * 1024 * 1024 * 1024;

const viewModes = [
  { id: 'list', label: 'List', Icon: ListIcon },
  { id: 'grid', label: 'Grid', Icon: GridIcon },
];

const primaryNavItems = [
  { id: 'home', label: 'Home', Icon: HomeIcon },
  { id: 'drive', label: 'My Drive', Icon: DriveFolderIcon },
];

const secondaryNavItems = [
  { id: 'shared', label: 'Shared with me', Icon: SharedIcon },
  { id: 'recent', label: 'Recent', Icon: RecentIcon },
  { id: 'starred', label: 'Starred', Icon: StarIcon },
  { id: 'spam', label: 'Spam', Icon: SpamIcon },
  { id: 'bin', label: 'Bin', Icon: TrashIcon },
];

const filterChips = ['Type', 'People', 'Modified'];

const typeLabels = {
  doc: 'Document',
  sheet: 'Spreadsheet',
  slides: 'Presentation',
  image: 'Image',
  pdf: 'PDF',
  video: 'Video',
  zip: 'Archive',
  file: 'File',
};

const previewCopy = {
  folder: 'Browse the folder contents, inspect its structure, and jump deeper without leaving the current view.',
  doc: 'A draft or reference document stored alongside the rest of the workspace.',
  sheet: 'Structured data, planning, or tracking information in tabular form.',
  slides: 'A presentation deck prepared for review, handoff, or sharing.',
  image: 'A visual asset saved with the rest of the project materials.',
  pdf: 'A fixed-format file ready to share or archive.',
  video: 'A media file suitable for playback, review, or export.',
  zip: 'A bundled archive containing exported or packaged files.',
  file: 'A local file captured from the selected path.',
};

function defaultNotice(apiReady, apiChecked) {
  if (!apiChecked) {
    return {
      tone: 'info',
      title: 'Checking local bridge',
      body: 'Looking for the bundled filesystem API before loading a local folder.',
    };
  }

  if (!apiReady) {
    return {
      tone: 'warning',
      title: 'Demo source active',
      body: 'Start npm run dev or npm run start to browse a real local directory.',
    };
  }

  return {
    tone: 'info',
    title: 'Sample data loaded',
    body: 'Open Settings to replace the sample workspace with a local folder path.',
  };
}

function findItemById(node, targetId) {
  if (node.id === targetId) {
    return node;
  }

  for (const child of node.children ?? []) {
    const found = findItemById(child, targetId);
    if (found) {
      return found;
    }
  }

  return null;
}

function findPath(node, targetId, trail = []) {
  const nextTrail = [...trail, node];
  if (node.id === targetId) {
    return nextTrail;
  }

  for (const child of node.children ?? []) {
    const found = findPath(child, targetId, nextTrail);
    if (found) {
      return found;
    }
  }

  return null;
}

function flattenItems(node, path = []) {
  const nextPath = node.kind === 'folder' ? [...path, node] : path;
  const entries = [];

  for (const child of node.children ?? []) {
    entries.push({ item: child, path: nextPath });
    entries.push(...flattenItems(child, nextPath));
  }

  return entries;
}

function sortEntries(entries) {
  return [...entries].sort((left, right) => {
    if (left.item.kind !== right.item.kind) {
      return left.item.kind === 'folder' ? -1 : 1;
    }

    return left.item.name.localeCompare(right.item.name);
  });
}

function countDescendants(node) {
  if (typeof node.folderCount === 'number' && typeof node.fileCount === 'number') {
    return { folders: node.folderCount, files: node.fileCount };
  }

  return (node.children ?? []).reduce(
    (totals, child) => {
      if (child.kind === 'folder') {
        const childTotals = countDescendants(child);
        return {
          folders: totals.folders + childTotals.folders + 1,
          files: totals.files + childTotals.files,
        };
      }

      return {
        folders: totals.folders,
        files: totals.files + 1,
      };
    },
    { folders: 0, files: 0 },
  );
}

function typeLabel(type) {
  return typeLabels[type] ?? 'File';
}

function getPreviewCopy(item) {
  if (item.kind === 'folder') {
    return previewCopy.folder;
  }

  return previewCopy[item.type] ?? previewCopy.file;
}

function getFootprint(item) {
  if (item.kind !== 'folder') {
    return item.size;
  }

  const totals = countDescendants(item);
  if (!totals.folders && !totals.files) {
    return 'Empty folder';
  }

  return `${totals.folders} folders, ${totals.files} files`;
}

function getTableSize(item) {
  return item.kind === 'folder' ? '--' : item.size;
}

function formatLocation(path) {
  return path.map((item) => item.name).join(' / ');
}

function getInitialExpandedFolders(tree) {
  if (!tree) {
    return new Set([ROOT_ID]);
  }

  return new Set([ROOT_ID]);
}

function getOwnerLabel(sourceMode, item) {
  return sourceMode === 'local' ? 'Local' : item.owner;
}

function getAvatarInitials(label) {
  const cleaned = label.trim();
  if (!cleaned) {
    return 'DR';
  }

  const parts = cleaned.split(/\s+/).filter(Boolean);
  if (parts.length === 1) {
    return parts[0].slice(0, 2).toUpperCase();
  }

  return `${parts[0][0] ?? ''}${parts[1][0] ?? ''}`.toUpperCase();
}

function App() {
  const [driveTree, setDriveTree] = useState(driveData);
  const [currentFolderId, setCurrentFolderId] = useState(ROOT_ID);
  const [selectedItemId, setSelectedItemId] = useState(ROOT_ID);
  const [query, setQuery] = useState('');
  const deferredQuery = useDeferredValue(query);
  const [viewMode, setViewMode] = useState('list');
  const [sidebarOpen, setSidebarOpen] = useState(false);
  const [settingsOpen, setSettingsOpen] = useState(false);
  const [detailsOpen, setDetailsOpen] = useState(false);
  const [computersOpen, setComputersOpen] = useState(true);
  const [expandedFolders, setExpandedFolders] = useState(() => getInitialExpandedFolders(driveData));
  const [sourceMode, setSourceMode] = useState('demo');
  const [sourceName, setSourceName] = useState('Sample workspace');
  const [sourcePath, setSourcePath] = useState('');
  const [draftPath, setDraftPath] = useState('');
  const [isScanning, setIsScanning] = useState(false);
  const [apiReady, setApiReady] = useState(false);
  const [apiChecked, setApiChecked] = useState(false);
  const [sourceError, setSourceError] = useState('');
  const [connectionNotice, setConnectionNotice] = useState(() => defaultNotice(false, false));

  function resetExplorerState(tree) {
    setCurrentFolderId(ROOT_ID);
    setSelectedItemId(ROOT_ID);
    setQuery('');
    setDetailsOpen(false);
    setExpandedFolders(getInitialExpandedFolders(tree));
  }

  function openSettingsPanel() {
    setDetailsOpen(false);
    setSettingsOpen(true);
  }

  async function loadDirectoryFromPath(nextPath, options = {}) {
    const { persist = true, closeSettings = true, skipReadyCheck = false } = options;
    const trimmedPath = nextPath.trim();

    if (!trimmedPath) {
      setSourceError('Enter a directory path first.');
      setConnectionNotice({
        tone: 'warning',
        title: 'Directory path required',
        body: 'Enter a local directory path in Settings before trying to load the filesystem.',
      });
      return;
    }

    if (!apiReady && !skipReadyCheck) {
      const message = 'The local filesystem API is not running. Start the app with npm run dev or npm run start.';
      setSourceError(message);
      setConnectionNotice({
        tone: 'error',
        title: 'Local API unavailable',
        body: message,
      });
      return;
    }

    setIsScanning(true);
    setSourceError('');
    setConnectionNotice({
      tone: 'info',
      title: 'Scanning local path',
      body: `Reading ${trimmedPath} from the local filesystem.`,
    });

    try {
      const result = await scanLocalDirectory(trimmedPath);
      const { tree, directoryPath, truncated, scannedEntries } = result;

      if (persist) {
        saveDirectoryPath(directoryPath);
      }

      startTransition(() => {
        setDriveTree(tree);
        setSourceMode('local');
        setSourceName(tree.name);
        setSourcePath(directoryPath);
        setDraftPath(directoryPath);
        resetExplorerState(tree);
      });

      setConnectionNotice(
        truncated
          ? {
              tone: 'warning',
              title: 'Local path loaded with limits',
              body: `Browsing ${directoryPath}. The scan stopped after ${scannedEntries} entries to keep the app responsive.`,
            }
          : {
              tone: 'success',
              title: 'Local path connected',
              body: `Browsing ${directoryPath} directly from the local filesystem.`,
            },
      );

      if (closeSettings) {
        setSettingsOpen(false);
      }
    } catch (error) {
      const message = error instanceof Error ? error.message : 'Unable to scan the local directory.';
      setSourceError(message);
      setConnectionNotice({
        tone: 'error',
        title: 'Local path failed',
        body: message,
      });
    } finally {
      setIsScanning(false);
    }
  }

  async function refreshDirectory() {
    if (!sourcePath || isScanning) {
      return;
    }

    await loadDirectoryFromPath(sourcePath, { persist: true, closeSettings: false });
  }

  function handleSettingsSubmit(event) {
    event.preventDefault();
    void loadDirectoryFromPath(draftPath, { persist: true, closeSettings: true });
  }

  function useSampleData() {
    setDriveTree(driveData);
    setSourceMode('demo');
    setSourceName('Sample workspace');
    setSourcePath('');
    setDraftPath('');
    setSourceError('');
    resetExplorerState(driveData);
    clearSavedDirectoryPath();
    setConnectionNotice(defaultNotice(apiReady, true));
    setSettingsOpen(false);
  }

  useEffect(() => {
    let cancelled = false;

    async function initializeLocalBridge() {
      setConnectionNotice(defaultNotice(false, false));

      const available = await checkLocalApiAvailability();
      if (cancelled) {
        return;
      }

      setApiReady(available);
      setApiChecked(true);

      if (!available) {
        setConnectionNotice(defaultNotice(false, true));
        return;
      }

      const savedPath = loadSavedDirectoryPath();
      setDraftPath(savedPath);

      if (!savedPath) {
        setConnectionNotice(defaultNotice(true, true));
        return;
      }

      setIsScanning(true);
      try {
        const result = await scanLocalDirectory(savedPath);
        if (cancelled) {
          return;
        }

        startTransition(() => {
          setDriveTree(result.tree);
          setSourceMode('local');
          setSourceName(result.tree.name);
          setSourcePath(result.directoryPath);
          setDraftPath(result.directoryPath);
          resetExplorerState(result.tree);
        });

        setConnectionNotice(
          result.truncated
            ? {
                tone: 'warning',
                title: 'Saved path restored with limits',
                body: `Browsing ${result.directoryPath}. The restored scan stopped after ${result.scannedEntries} entries to keep the app responsive.`,
              }
            : {
                tone: 'success',
                title: 'Saved path restored',
                body: `Browsing ${result.directoryPath} directly from the local filesystem.`,
              },
        );
      } catch (error) {
        if (cancelled) {
          return;
        }

        const message = error instanceof Error ? error.message : 'Unable to restore the saved local directory.';
        setSourceError(message);
        setConnectionNotice({
          tone: 'warning',
          title: 'Saved path could not be restored',
          body: message,
        });
      } finally {
        if (!cancelled) {
          setIsScanning(false);
        }
      }
    }

    void initializeLocalBridge();

    return () => {
      cancelled = true;
    };
  }, []);

  const allEntries = useMemo(() => flattenItems(driveTree), [driveTree]);
  const currentFolder = findItemById(driveTree, currentFolderId) ?? driveTree;
  const breadcrumbs = findPath(driveTree, currentFolderId) ?? [driveTree];
  const selectedItem = findItemById(driveTree, selectedItemId) ?? currentFolder;
  const selectedPath = findPath(driveTree, selectedItem.id) ?? [driveTree];
  const normalizedQuery = deferredQuery.trim().toLowerCase();

  const searchResults = useMemo(() => {
    if (!normalizedQuery) {
      return [];
    }

    return sortEntries(
      allEntries.filter(({ item, path }) => {
        const searchable = [
          item.name,
          getOwnerLabel(sourceMode, item),
          item.kind === 'folder' ? 'folder' : item.type,
          path.map((entry) => entry.name).join(' '),
        ]
          .join(' ')
          .toLowerCase();

        return searchable.includes(normalizedQuery);
      }),
    );
  }, [allEntries, normalizedQuery, sourceMode]);

  const folderEntries = useMemo(() => {
    const children = currentFolder.children ?? [];
    return sortEntries(children.map((item) => ({ item, path: breadcrumbs })));
  }, [breadcrumbs, currentFolder]);

  const rootFolders = useMemo(
    () =>
      sortEntries((driveTree.children ?? []).map((item) => ({ item, path: [driveTree] })))
        .filter(({ item }) => item.kind === 'folder')
        .map(({ item }) => item),
    [driveTree],
  );

  const visibleEntries = normalizedQuery ? searchResults : folderEntries;
  const currentFoldersCount = folderEntries.filter(({ item }) => item.kind === 'folder').length;
  const currentFilesCount = folderEntries.length - currentFoldersCount;
  const rootTotals = useMemo(() => countDescendants(driveTree), [driveTree]);
  const storageBytes = sourceMode === 'local' ? driveTree.sizeBytes ?? 0 : DEMO_STORAGE_BYTES;
  const storagePercent = Math.max(6, Math.min(100, (storageBytes / STORAGE_CAPACITY_BYTES) * 100));
  const storageLabel = sourceMode === 'local' ? formatBytes(storageBytes) : '38.88 GB';
  const boardTitle = normalizedQuery ? 'Search in Drive' : currentFolder.name;
  const boardSummary = normalizedQuery
    ? `${visibleEntries.length} result${visibleEntries.length === 1 ? '' : 's'} for "${query.trim()}"`
    : `${currentFoldersCount} folder${currentFoldersCount === 1 ? '' : 's'}, ${currentFilesCount} file${currentFilesCount === 1 ? '' : 's'}`;
  const activeSourceTag = sourceMode === 'local' ? 'Local path' : 'Sample data';

  function openFolder(folderId) {
    const folder = findItemById(driveTree, folderId);
    if (!folder || folder.kind !== 'folder') {
      return;
    }

    setCurrentFolderId(folderId);
    setSelectedItemId(folderId);
    setQuery('');
    setSidebarOpen(false);
    setExpandedFolders((previous) => {
      const next = new Set(previous);
      const path = findPath(driveTree, folderId) ?? [];
      path.forEach((entry) => {
        if (entry.kind === 'folder') {
          next.add(entry.id);
        }
      });
      return next;
    });
  }

  function inspectItem(itemId) {
    setSelectedItemId(itemId);
    setDetailsOpen(true);
  }

  function activateEntry(item) {
    setSelectedItemId(item.id);

    if (item.kind === 'folder') {
      openFolder(item.id);
      return;
    }

    setDetailsOpen(true);
  }

  function toggleFolder(folderId) {
    setExpandedFolders((previous) => {
      const next = new Set(previous);
      if (next.has(folderId)) {
        next.delete(folderId);
      } else {
        next.add(folderId);
      }
      return next;
    });
  }

  return (
    <div className="drive-app">
      <aside className={`drive-sidebar ${sidebarOpen ? 'open' : ''}`}>
        <div className="drive-brand">
          <div className="drive-brand-mark" aria-hidden="true">
            <DriveLogo />
          </div>
          <strong>Drive</strong>
          <button className="mobile-close" type="button" onClick={() => setSidebarOpen(false)}>
            Close
          </button>
        </div>

        <button className="new-button" type="button" onClick={openSettingsPanel}>
          <PlusIcon />
          <span>New</span>
        </button>

        <nav className="drive-nav" aria-label="Primary navigation">
          {primaryNavItems.map(({ id, label, Icon }) => {
            const active = id === 'drive' && currentFolderId === ROOT_ID && !normalizedQuery;
            return (
              <button
                key={id}
                type="button"
                className={`drive-nav-item ${active ? 'active' : ''}`}
                onClick={() => openFolder(ROOT_ID)}
              >
                <Icon />
                <span>{label}</span>
              </button>
            );
          })}

          <button
            type="button"
            className={`drive-nav-item ${computersOpen ? 'expanded' : ''}`}
            onClick={() => setComputersOpen((open) => !open)}
          >
            <ComputerIcon />
            <span>Computers</span>
            <span className="nav-chevron" aria-hidden="true">
              <ChevronDownIcon />
            </span>
          </button>

          {computersOpen ? (
            <div className="drive-tree-block">
              <SidebarTree
                nodes={rootFolders}
                currentFolderId={currentFolderId}
                expandedFolders={expandedFolders}
                onOpenFolder={openFolder}
                onToggle={toggleFolder}
              />
            </div>
          ) : null}
        </nav>

        <div className="drive-nav secondary" aria-hidden="true">
          {secondaryNavItems.map(({ id, label, Icon }) => (
            <div className="drive-nav-item passive" key={id}>
              <Icon />
              <span>{label}</span>
            </div>
          ))}
        </div>

        <div className="storage-widget">
          <div className="storage-title-row">
            <CloudIcon />
            <span>Storage</span>
          </div>
          <div className="storage-bar" aria-hidden="true">
            <span style={{ width: `${storagePercent}%` }} />
          </div>
          <p className="storage-copy">{storageLabel} of 200 GB used</p>
          <button className="storage-button" type="button" onClick={openSettingsPanel}>
            Get more storage
          </button>
        </div>
      </aside>

      <main className="drive-main">
        <header className="drive-toolbar">
          <button className="sidebar-toggle" type="button" onClick={() => setSidebarOpen((open) => !open)}>
            <MenuIcon />
          </button>

          <label className="drive-search" htmlFor="drive-search">
            <SearchIcon />
            <input
              id="drive-search"
              type="search"
              value={query}
              onChange={(event) => setQuery(event.target.value)}
              placeholder="Search in Drive"
            />
            <span className="search-filter-icon" aria-hidden="true">
              <SlidersIcon />
            </span>
          </label>

          <div className="toolbar-actions">
            <span className="toolbar-icon" aria-hidden="true">
              <HelpIcon />
            </span>
            <button className="toolbar-icon" type="button" onClick={openSettingsPanel} aria-label="Open settings">
              <GearIcon />
            </button>
            <span className="toolbar-icon" aria-hidden="true">
              <SparkleIcon />
            </span>
            <span className="toolbar-icon" aria-hidden="true">
              <AppsIcon />
            </span>
            <button className="profile-chip" type="button" onClick={() => setDetailsOpen(true)} aria-label="Open details">
              <OwnerAvatar label={sourceMode === 'local' ? 'Local' : 'me'} compact />
            </button>
          </div>
        </header>

        <section className="drive-board">
          <div className="board-header">
            <div className="board-title-stack">
              <div className="board-title-row">
                <h1>{boardTitle}</h1>
                <ChevronDownIcon />
              </div>
              <BreadcrumbTrail trail={breadcrumbs} onOpenFolder={openFolder} />
            </div>

            <div className="board-header-actions">
              <div className="view-switch" role="tablist" aria-label="View mode">
                {viewModes.map(({ id, label, Icon }) => (
                  <button
                    key={id}
                    type="button"
                    className={viewMode === id ? 'active' : ''}
                    onClick={() => setViewMode(id)}
                    aria-label={label}
                    title={label}
                  >
                    <Icon />
                  </button>
                ))}
              </div>
              <button
                className={`board-icon-button ${detailsOpen ? 'active' : ''}`}
                type="button"
                onClick={() => setDetailsOpen((open) => !open)}
                aria-label="Toggle details"
              >
                <InfoIcon />
              </button>
            </div>
          </div>

          <div className="filter-row">
            {filterChips.map((label) => (
              <FilterChip key={label} label={label} />
            ))}
            <FilterChip label="Source" onClick={openSettingsPanel} />
          </div>

          <div className="board-meta">
            <span className={`source-pill ${connectionNotice.tone}`}>{activeSourceTag}</span>
            <p className="board-summary">{boardSummary}</p>
            <p className="board-notice">
              <strong>{connectionNotice.title}</strong>
              <span>{connectionNotice.body}</span>
            </p>
            {isScanning ? <span className="status-chip">Scanning...</span> : null}
            {normalizedQuery ? (
              <button className="clear-search-button" type="button" onClick={() => setQuery('')}>
                Clear search
              </button>
            ) : null}
          </div>

          {visibleEntries.length === 0 ? (
            <EmptyState query={query} onReset={() => setQuery('')} />
          ) : viewMode === 'list' ? (
            <ListView
              entries={visibleEntries}
              selectedItemId={selectedItem.id}
              showLocation={Boolean(normalizedQuery)}
              sourceMode={sourceMode}
              onActivate={activateEntry}
              onInspect={inspectItem}
            />
          ) : (
            <CardView
              entries={visibleEntries}
              selectedItemId={selectedItem.id}
              showLocation={Boolean(normalizedQuery)}
              sourceMode={sourceMode}
              onActivate={activateEntry}
              onInspect={inspectItem}
            />
          )}
        </section>
      </main>

      <aside className="drive-rail" aria-hidden="true">
        <div className="rail-stack">
          <span className="rail-icon rail-calendar">
            <CalendarIcon />
          </span>
          <span className="rail-icon rail-note">
            <KeepIcon />
          </span>
          <span className="rail-icon rail-task">
            <TasksIcon />
          </span>
        </div>
        <span className="rail-divider" />
        <span className="rail-icon rail-plus">
          <PlusIcon />
        </span>
      </aside>

      <DetailsDrawer
        item={selectedItem}
        open={detailsOpen}
        path={selectedPath}
        sourceMode={sourceMode}
        onClose={() => setDetailsOpen(false)}
        onOpenFolder={(folderId) => {
          openFolder(folderId);
          setDetailsOpen(false);
        }}
      />

      <SettingsPanel
        apiChecked={apiChecked}
        apiReady={apiReady}
        draftPath={draftPath}
        isScanning={isScanning}
        open={settingsOpen}
        rootTotals={rootTotals}
        sourceError={sourceError}
        sourceMode={sourceMode}
        sourceName={sourceName}
        sourcePath={sourcePath}
        onClose={() => setSettingsOpen(false)}
        onDraftPathChange={setDraftPath}
        onRefreshDirectory={refreshDirectory}
        onSubmit={handleSettingsSubmit}
        onUseSampleData={useSampleData}
      />
    </div>
  );
}

function SidebarTree({ nodes, currentFolderId, expandedFolders, onOpenFolder, onToggle, depth = 0 }) {
  return nodes
    .filter((node) => node.kind === 'folder')
    .map((node) => {
      const childFolders = (node.children ?? []).filter((child) => child.kind === 'folder');
      const expanded = expandedFolders.has(node.id);

      return (
        <div className="tree-node" key={node.id}>
          <div className={`tree-row ${currentFolderId === node.id ? 'active' : ''}`} style={{ '--depth': depth }}>
            <button
              className={`tree-expander ${childFolders.length ? '' : 'empty'} ${expanded ? 'expanded' : ''}`}
              type="button"
              onClick={() => childFolders.length && onToggle(node.id)}
              aria-label={expanded ? `Collapse ${node.name}` : `Expand ${node.name}`}
            >
              <ChevronIcon />
            </button>
            <button className="tree-link" type="button" onClick={() => onOpenFolder(node.id)}>
              <ItemIcon item={node} compact />
              <span>{node.name}</span>
            </button>
          </div>

          {expanded && childFolders.length ? (
            <SidebarTree
              nodes={childFolders}
              currentFolderId={currentFolderId}
              expandedFolders={expandedFolders}
              onOpenFolder={onOpenFolder}
              onToggle={onToggle}
              depth={depth + 1}
            />
          ) : null}
        </div>
      );
    });
}

function BreadcrumbTrail({ trail, onOpenFolder }) {
  return (
    <nav className="breadcrumbs" aria-label="Breadcrumb">
      {trail.map((node, index) => {
        const isCurrent = index === trail.length - 1;
        return (
          <span className="breadcrumb-item" key={node.id}>
            {isCurrent ? (
              <span className="breadcrumb-current">{node.name}</span>
            ) : (
              <button type="button" onClick={() => onOpenFolder(node.id)}>
                {node.name}
              </button>
            )}
            {isCurrent ? null : <ChevronRightIcon />}
          </span>
        );
      })}
    </nav>
  );
}

function FilterChip({ label, onClick }) {
  return (
    <button className="filter-chip" type="button" onClick={onClick}>
      <span>{label}</span>
      <ChevronDownIcon />
    </button>
  );
}

function ListView({ entries, selectedItemId, showLocation, sourceMode, onActivate, onInspect }) {
  return (
    <div className="drive-list">
      <div className="drive-list-head">
        <span className="head-name">
          Name
          <span className="sort-indicator" aria-hidden="true">
            <SortAscendingIcon />
          </span>
        </span>
        <span>Owner</span>
        <span>Date modified</span>
        <span>File size</span>
        <span className="head-sort">
          <SortIcon />
          Sort
        </span>
      </div>
      <div className="drive-list-body">
        {entries.map(({ item, path }) => {
          const owner = getOwnerLabel(sourceMode, item);

          return (
            <div className={`drive-list-row ${selectedItemId === item.id ? 'selected' : ''}`} key={item.id}>
              <button className="row-name-button" type="button" onClick={() => onActivate(item)}>
                <ItemIcon item={item} compact />
                <span className="row-name-copy">
                  <strong>{item.name}</strong>
                  {showLocation ? <span>{formatLocation(path)}</span> : null}
                </span>
              </button>
              <span className="owner-cell">
                <OwnerAvatar label={owner} compact />
                <span>{owner}</span>
              </span>
              <span className="row-value">{item.modified}</span>
              <span className="row-value">{getTableSize(item)}</span>
              <button className="row-menu-button" type="button" onClick={() => onInspect(item.id)} aria-label={`Inspect ${item.name}`}>
                <DotsIcon />
              </button>
            </div>
          );
        })}
      </div>
    </div>
  );
}

function CardView({ entries, selectedItemId, showLocation, sourceMode, onActivate, onInspect }) {
  return (
    <div className="card-grid">
      {entries.map(({ item, path }) => {
        const owner = getOwnerLabel(sourceMode, item);
        return (
          <article className={`drive-card ${selectedItemId === item.id ? 'selected' : ''}`} key={item.id}>
            <div className="drive-card-top">
              <span className="card-icon-frame">
                <ItemIcon item={item} />
              </span>
              <button className="row-menu-button" type="button" onClick={() => onInspect(item.id)} aria-label={`Inspect ${item.name}`}>
                <DotsIcon />
              </button>
            </div>
            <button className="drive-card-main" type="button" onClick={() => onActivate(item)}>
              <strong>{item.name}</strong>
              <span>{item.kind === 'folder' ? 'Folder' : typeLabel(item.type)}</span>
              <span>{owner}</span>
              <span>{showLocation ? formatLocation(path) : item.modified}</span>
            </button>
          </article>
        );
      })}
    </div>
  );
}

function EmptyState({ query, onReset }) {
  return (
    <div className="empty-state">
      <h3>No results for "{query.trim()}"</h3>
      <p>Try a folder name, file type, owner, or path. Search matches against the full active source.</p>
      <button className="primary-button" type="button" onClick={onReset}>
        Clear search
      </button>
    </div>
  );
}

function DetailsDrawer({ item, open, path, sourceMode, onClose, onOpenFolder }) {
  const owner = getOwnerLabel(sourceMode, item);

  return (
    <>
      <div className={`drawer-scrim ${open ? 'open' : ''}`} onClick={onClose} aria-hidden={!open} />
      <aside className={`details-drawer ${open ? 'open' : ''}`} aria-hidden={!open}>
        <div className="drawer-header">
          <div>
            <p className="drawer-eyebrow">Selected item</p>
            <h2>{item.name}</h2>
          </div>
          <button className="panel-close-button" type="button" onClick={onClose}>
            Close
          </button>
        </div>

        <div className={`drawer-preview preview-${item.kind === 'folder' ? 'folder' : item.type}`}>
          <span className="drawer-preview-icon">
            <ItemIcon item={item} />
          </span>
        </div>

        <div className="drawer-copy">
          <p>{getPreviewCopy(item)}</p>
        </div>

        <dl className="drawer-grid">
          <div>
            <dt>Type</dt>
            <dd>{item.kind === 'folder' ? 'Folder' : typeLabel(item.type)}</dd>
          </div>
          <div>
            <dt>Owner</dt>
            <dd>{owner}</dd>
          </div>
          <div>
            <dt>Modified</dt>
            <dd>{item.modified}</dd>
          </div>
          <div>
            <dt>Footprint</dt>
            <dd>{getFootprint(item)}</dd>
          </div>
          <div>
            <dt>Location</dt>
            <dd>{formatLocation(path)}</dd>
          </div>
        </dl>

        {item.kind === 'folder' ? (
          <button className="primary-button" type="button" onClick={() => onOpenFolder(item.id)}>
            Open folder
          </button>
        ) : null}
      </aside>
    </>
  );
}

function SettingsPanel({
  apiChecked,
  apiReady,
  draftPath,
  isScanning,
  open,
  rootTotals,
  sourceError,
  sourceMode,
  sourceName,
  sourcePath,
  onClose,
  onDraftPathChange,
  onRefreshDirectory,
  onSubmit,
  onUseSampleData,
}) {
  return (
    <>
      <div className={`settings-scrim ${open ? 'open' : ''}`} onClick={onClose} aria-hidden={!open} />
      <aside className={`settings-panel ${open ? 'open' : ''}`} role="dialog" aria-modal="true" aria-hidden={!open}>
        <div className="drawer-header">
          <div>
            <p className="drawer-eyebrow">Settings</p>
            <h2>Folder source</h2>
          </div>
          <button className="panel-close-button" type="button" onClick={onClose}>
            Close
          </button>
        </div>

        <form className="settings-card" onSubmit={onSubmit}>
          <div className="settings-status-row">
            <span className={`source-pill ${apiReady ? 'success' : apiChecked ? 'warning' : 'info'}`}>
              {apiChecked ? (apiReady ? 'Bridge connected' : 'Bridge unavailable') : 'Checking bridge'}
            </span>
            <strong>{sourceMode === 'local' ? sourceName : 'Sample workspace'}</strong>
          </div>

          <p className="settings-copy">
            {apiReady
              ? 'Enter a local directory path and the app will scan it through the bundled Node filesystem API.'
              : 'The local filesystem API is not reachable yet. Start the combined dev server, then load a local folder here.'}
          </p>

          <dl className="settings-grid">
            <div>
              <dt>Folders</dt>
              <dd>{rootTotals.folders}</dd>
            </div>
            <div>
              <dt>Files</dt>
              <dd>{rootTotals.files}</dd>
            </div>
            <div>
              <dt>Loaded path</dt>
              <dd>{sourcePath || 'None'}</dd>
            </div>
            <div>
              <dt>Mode</dt>
              <dd>{sourceMode === 'local' ? 'Live local path' : 'Demo data'}</dd>
            </div>
          </dl>

          <label className="settings-field" htmlFor="directory-path">
            <span>Directory path</span>
            <input
              id="directory-path"
              className="settings-input"
              type="text"
              value={draftPath}
              onChange={(event) => onDraftPathChange(event.target.value)}
              placeholder="C:\\Users\\you\\Documents"
              autoComplete="off"
              spellCheck={false}
            />
          </label>

          <div className="settings-actions">
            <button className="primary-button" type="submit" disabled={!apiReady || isScanning || !draftPath.trim()}>
              {sourceMode === 'local' ? 'Load new path' : 'Load path'}
            </button>
            <button className="secondary-button" type="button" onClick={onRefreshDirectory} disabled={!apiReady || !sourcePath || isScanning}>
              Refresh path
            </button>
            <button className="secondary-button" type="button" onClick={onUseSampleData} disabled={sourceMode !== 'local'}>
              Use sample data
            </button>
          </div>

          <p className="settings-note">
            This mode reads directly from the local filesystem through the bundled Node server. No upload step is required.
          </p>

          {sourceError ? <p className="settings-error">{sourceError}</p> : null}
        </form>
      </aside>
    </>
  );
}

function OwnerAvatar({ label, compact = false }) {
  return <span className={`owner-avatar ${compact ? 'compact' : ''}`}>{getAvatarInitials(label)}</span>;
}

function ItemIcon({ item, compact = false }) {
  const iconType = item.kind === 'folder' ? 'folder' : item.type;

  return (
    <span className={`item-icon item-icon-${iconType} ${compact ? 'compact' : ''}`} aria-hidden="true">
      {iconType === 'folder' ? (
        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8">
          <path d="M3.5 8.5A2.5 2.5 0 0 1 6 6h4.4l1.6 1.8H18A2.5 2.5 0 0 1 20.5 10.3v5.2A2.5 2.5 0 0 1 18 18H6A2.5 2.5 0 0 1 3.5 15.5z" />
        </svg>
      ) : iconType === 'doc' ? (
        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8">
          <path d="M8 3.5h6l4 4V20A1.5 1.5 0 0 1 16.5 21.5h-8A1.5 1.5 0 0 1 7 20V5A1.5 1.5 0 0 1 8.5 3.5z" />
          <path d="M14 3.5V8h4" />
          <path d="M9.5 12h5M9.5 15h5M9.5 18h3.5" />
        </svg>
      ) : iconType === 'sheet' ? (
        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8">
          <rect x="5" y="4" width="14" height="16" rx="2" />
          <path d="M5 9h14M10 9v11M14.5 9v11" />
        </svg>
      ) : iconType === 'slides' ? (
        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8">
          <rect x="4.5" y="5" width="15" height="10" rx="2" />
          <path d="M12 15v4M8.5 19h7" />
        </svg>
      ) : iconType === 'image' ? (
        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8">
          <rect x="4" y="5" width="16" height="14" rx="2" />
          <path d="M8 14l2.5-2.5L14 15l2-2 4 4" />
          <circle cx="9" cy="9" r="1.2" fill="currentColor" stroke="none" />
        </svg>
      ) : iconType === 'pdf' ? (
        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8">
          <path d="M8 3.5h6l4 4V20A1.5 1.5 0 0 1 16.5 21.5h-8A1.5 1.5 0 0 1 7 20V5A1.5 1.5 0 0 1 8.5 3.5z" />
          <path d="M14 3.5V8h4" />
          <path d="M9.5 12h2.5a1.5 1.5 0 0 1 0 3H9.5zM14.5 12H16M14.5 15H16" />
        </svg>
      ) : iconType === 'video' ? (
        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8">
          <rect x="4" y="6" width="12" height="12" rx="2" />
          <path d="M16 10.5l4-2v7l-4-2z" />
        </svg>
      ) : (
        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8">
          <path d="M8 4.5h8A1.5 1.5 0 0 1 17.5 6v12A1.5 1.5 0 0 1 16 19.5H8A1.5 1.5 0 0 1 6.5 18V6A1.5 1.5 0 0 1 8 4.5z" />
          <path d="M9.5 9.5h5M9.5 13h5M9.5 16.5h3" />
        </svg>
      )}
    </span>
  );
}

function DriveLogo() {
  return (
    <svg viewBox="0 0 36 32" fill="none" aria-hidden="true">
      <path d="M12.2 2.5 2.6 18.9h8.6L20.8 2.5z" fill="#1a73e8" />
      <path d="m20.8 2.5 9.6 16.4h-8.6L12.2 2.5z" fill="#34a853" />
      <path d="M11.2 18.9H2.6l9.6 10.6h11.6l6.6-10.6h-8.6z" fill="#fbbc04" />
    </svg>
  );
}

function SearchIcon() {
  return (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.9" aria-hidden="true">
      <circle cx="11" cy="11" r="6" />
      <path d="m16 16 4 4" />
    </svg>
  );
}

function SlidersIcon() {
  return (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" aria-hidden="true">
      <path d="M4 6h8M16 6h4M9 6a1.5 1.5 0 1 0 3 0 1.5 1.5 0 0 0-3 0ZM4 12h3M11 12h9M7 12a1.5 1.5 0 1 0 3 0 1.5 1.5 0 0 0-3 0ZM4 18h10M18 18h2M13 18a1.5 1.5 0 1 0 3 0 1.5 1.5 0 0 0-3 0Z" />
    </svg>
  );
}

function ChevronIcon() {
  return (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" aria-hidden="true">
      <path d="m9 6 6 6-6 6" />
    </svg>
  );
}

function ChevronDownIcon() {
  return (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" aria-hidden="true">
      <path d="m6 9 6 6 6-6" />
    </svg>
  );
}

function ChevronRightIcon() {
  return (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" aria-hidden="true">
      <path d="m10 7 5 5-5 5" />
    </svg>
  );
}

function ListIcon() {
  return (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" aria-hidden="true">
      <path d="M8 7h11M8 12h11M8 17h11" />
      <path d="M4 7h.01M4 12h.01M4 17h.01" strokeLinecap="round" />
    </svg>
  );
}

function GridIcon() {
  return (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" aria-hidden="true">
      <rect x="4" y="4" width="6" height="6" rx="1" />
      <rect x="14" y="4" width="6" height="6" rx="1" />
      <rect x="4" y="14" width="6" height="6" rx="1" />
      <rect x="14" y="14" width="6" height="6" rx="1" />
    </svg>
  );
}

function InfoIcon() {
  return (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" aria-hidden="true">
      <circle cx="12" cy="12" r="8" />
      <path d="M12 10v5M12 7.5h.01" strokeLinecap="round" />
    </svg>
  );
}

function DotsIcon() {
  return (
    <svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
      <circle cx="12" cy="5" r="1.7" />
      <circle cx="12" cy="12" r="1.7" />
      <circle cx="12" cy="19" r="1.7" />
    </svg>
  );
}

function PlusIcon() {
  return (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.9" aria-hidden="true">
      <path d="M12 5v14M5 12h14" />
    </svg>
  );
}

function MenuIcon() {
  return (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" aria-hidden="true">
      <path d="M4 7h16M4 12h16M4 17h16" />
    </svg>
  );
}

function HomeIcon() {
  return (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" aria-hidden="true">
      <path d="m4.5 10 7.5-6 7.5 6" />
      <path d="M7 9.5V19h10V9.5" />
    </svg>
  );
}

function DriveFolderIcon() {
  return (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" aria-hidden="true">
      <path d="M3.5 8.5A2.5 2.5 0 0 1 6 6h4.2l1.8 2H18A2.5 2.5 0 0 1 20.5 10.5v5A2.5 2.5 0 0 1 18 18H6A2.5 2.5 0 0 1 3.5 15.5z" />
    </svg>
  );
}

function ComputerIcon() {
  return (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" aria-hidden="true">
      <rect x="4" y="5" width="16" height="10" rx="2" />
      <path d="M9 19h6M12 15v4" />
    </svg>
  );
}

function SharedIcon() {
  return (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" aria-hidden="true">
      <path d="M9 11a3 3 0 1 0 0-6 3 3 0 0 0 0 6ZM16.5 12.5a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0 0 5Z" />
      <path d="M4 18.5a5 5 0 0 1 10 0M13 18.5a3.5 3.5 0 0 1 7 0" />
    </svg>
  );
}

function RecentIcon() {
  return (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" aria-hidden="true">
      <circle cx="12" cy="12" r="8" />
      <path d="M12 8v5l3 2" />
    </svg>
  );
}

function StarIcon() {
  return (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" aria-hidden="true">
      <path d="m12 4 2.4 4.9 5.4.8-3.9 3.8.9 5.5L12 16.9 7.2 19l.9-5.5L4.2 9.7l5.4-.8z" />
    </svg>
  );
}

function SpamIcon() {
  return (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" aria-hidden="true">
      <path d="M12 3.8 19 8v8l-7 4.2L5 16V8z" />
      <path d="M12 8.5v4.5M12 16h.01" strokeLinecap="round" />
    </svg>
  );
}

function TrashIcon() {
  return (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" aria-hidden="true">
      <path d="M5 7h14M9 7V5h6v2M7 7l1 12h8l1-12" />
    </svg>
  );
}

function CloudIcon() {
  return (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" aria-hidden="true">
      <path d="M7.5 18A4.5 4.5 0 1 1 8 9a5.5 5.5 0 0 1 10.5 2A3.5 3.5 0 0 1 18 18z" />
    </svg>
  );
}

function HelpIcon() {
  return (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" aria-hidden="true">
      <circle cx="12" cy="12" r="8" />
      <path d="M9.7 9.5a2.7 2.7 0 1 1 4.7 1.8c-.8.8-1.4 1.2-1.4 2.7" />
      <path d="M12 17h.01" strokeLinecap="round" />
    </svg>
  );
}

function GearIcon() {
  return (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" aria-hidden="true">
      <path d="M12 8.5A3.5 3.5 0 1 0 12 15.5 3.5 3.5 0 0 0 12 8.5z" />
      <path d="M4.8 13.3 3 12l1.8-1.3.5-2.1 2.1-.5L8.7 6l1.8.8 1.5-1.5 1.5 1.5L15.3 6l1.3 1.8 2.1.5.5 2.1L21 12l-1.8 1.3-.5 2.1-2.1.5-1.3 1.8-1.8-.8-1.5 1.5-1.5-1.5-1.8.8-1.3-1.8-2.1-.5z" />
    </svg>
  );
}

function SparkleIcon() {
  return (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" aria-hidden="true">
      <path d="m12 3 1.5 5.5L19 10l-5.5 1.5L12 17l-1.5-5.5L5 10l5.5-1.5z" />
    </svg>
  );
}

function AppsIcon() {
  return (
    <svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
      <circle cx="6" cy="6" r="1.5" />
      <circle cx="12" cy="6" r="1.5" />
      <circle cx="18" cy="6" r="1.5" />
      <circle cx="6" cy="12" r="1.5" />
      <circle cx="12" cy="12" r="1.5" />
      <circle cx="18" cy="12" r="1.5" />
      <circle cx="6" cy="18" r="1.5" />
      <circle cx="12" cy="18" r="1.5" />
      <circle cx="18" cy="18" r="1.5" />
    </svg>
  );
}

function SortAscendingIcon() {
  return (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" aria-hidden="true">
      <path d="M12 18V6" />
      <path d="m8 10 4-4 4 4" />
    </svg>
  );
}

function SortIcon() {
  return (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" aria-hidden="true">
      <path d="M7 6h10M7 12h7M7 18h4" />
    </svg>
  );
}

function CalendarIcon() {
  return (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" aria-hidden="true">
      <rect x="4" y="5" width="16" height="15" rx="2" />
      <path d="M8 3.5v3M16 3.5v3M4 9h16" />
    </svg>
  );
}

function KeepIcon() {
  return (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" aria-hidden="true">
      <path d="M8 4.5h8l2 4v4.5a6 6 0 0 1-12 0V8.5z" />
      <path d="M10 18.5h4" />
    </svg>
  );
}

function TasksIcon() {
  return (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" aria-hidden="true">
      <path d="m5 7 2 2 3-4M5 13l2 2 3-4M12 7h7M12 13h7M12 19h7" />
    </svg>
  );
}

export default App;