import React, { useCallback, useEffect, useMemo, useRef, useState, useId } from 'react';
import { createPortal } from 'react-dom';
import {
  ChevronIcon,
  TrashIcon,
  EditIcon,
  FolderIcon,
  SidebarCollapseIcon,
  LogoutIcon,
  ChevronDownIcon,
  SettingsIcon,
  CheckIcon,
  PlusIcon,
  FolderPlusIcon,
  RestoreIcon,
  SunIcon,
  MoonIcon,
  DesktopIcon,
  UploadIcon,
} from '../ui/icons';
import PanelHeader from '../ui/PanelHeader';
import useFloatingMenu from '../ui/useFloatingMenu';

import { getTagColorStyle } from '../utils/colors';
import { useSidebarContext } from './SidebarContext';

const SIDEBAR_WIDTH_STORAGE_KEY = 'documentsSidebarWidth';
const SIDEBAR_WIDTH_EVENT = 'sidebar-width-change';
const MIN_SIDEBAR_WIDTH = 240;
const MAX_SIDEBAR_WIDTH = 640;
const isBrowser = typeof window !== 'undefined';
const isDocumentAvailable = typeof document !== 'undefined';

const notifySidebarWidthChange = (width) => {
  if (!isBrowser) {
    return;
  }
  try {
    window.dispatchEvent(
      new CustomEvent(SIDEBAR_WIDTH_EVENT, {
        detail: { width },
      }),
    );
  } catch (error) {
    console.warn('Failed to dispatch sidebar width change', error);
  }
};

const getSidebarBounds = () => {
  if (!isBrowser) {
    return {
      min: MIN_SIDEBAR_WIDTH,
      max: MAX_SIDEBAR_WIDTH,
    };
  }
  const viewportWidth = Math.max(window.innerWidth, 1);
  const minFractionWidth = viewportWidth / 6;
  const maxFractionWidth = viewportWidth / 3;
  const rawMin = Math.max(MIN_SIDEBAR_WIDTH, minFractionWidth);
  const rawMax = Math.min(MAX_SIDEBAR_WIDTH, maxFractionWidth);
  if (rawMin >= rawMax) {
    const fallback = Math.min(Math.max(rawMin, viewportWidth / 4), MAX_SIDEBAR_WIDTH);
    return { min: fallback, max: fallback };
  }
  return { min: rawMin, max: rawMax };
};

const clampSidebarWidth = (value) => {
  if (!Number.isFinite(value) || value <= 0) {
    return null;
  }
  const { min, max } = getSidebarBounds();
  return Math.min(Math.max(value, min), max);
};

const loadStoredSidebarWidth = () => {
  if (!isBrowser) {
    return null;
  }
  try {
    const raw = window.localStorage?.getItem(SIDEBAR_WIDTH_STORAGE_KEY);
    if (!raw) {
      return null;
    }
    const parsed = parseInt(raw, 10);
    return Number.isFinite(parsed) ? parsed : null;
  } catch (error) {
    console.warn('Failed to read sidebar width', error);
    return null;
  }
};

const applySidebarWidth = (width) => {
  if (!isDocumentAvailable || width == null) {
    return;
  }
  document.documentElement.style.setProperty('--sidebar-width', `${width}px`);
  notifySidebarWidthChange(width);
};

const FolderNode = ({
  node,
  depth,
  isSelected,
  onToggle,
  onSelect,
  onDrop,
  onDragOver,
  onDragLeave,
  onDelete,
  onRename,
  renderChildren,
  onFolderDragStart,
  onFolderDragEnd,
  draggingFolderId,
}) => {
  const isRoot = node.id === 'root';
  const hasChildren = Boolean(node.hasChildren);
  const canToggle = hasChildren || !node.loaded;
  const showChevron = canToggle;
  const icon = showChevron ? <ChevronIcon className="toggle-icon" /> : null;
  const canDrag = !isRoot;
  const isDragging = draggingFolderId === node.id;
  const isExpanded = Boolean(node.expanded);
  const rowClasses = ['folder-row'];
  if (isSelected) {
    rowClasses.push('active');
  }

  const handleToggleClick = (event) => {
    event.stopPropagation();
    if (canToggle) {
      onToggle(node.id);
    }
  };

  return (
    <li className={`folder-node${isDragging ? ' is-dragging' : ''}`}>
      <div
        className={rowClasses.join(' ')}
        draggable={canDrag}
        onClick={() => onSelect(node.id)}
        onDoubleClick={() => {
          if (canToggle) {
            onToggle(node.id);
          }
        }}
        onDragOver={(event) => onDragOver(event, node.id)}
        onDragLeave={onDragLeave}
        onDrop={(event) => onDrop(event, node.id)}
        onDragStart={(event) => {
          if (!canDrag || !onFolderDragStart) return;
          onFolderDragStart(event, node.id);
        }}
        onDragEnd={(event) => {
          if (onFolderDragEnd) {
            onFolderDragEnd(event);
          }
        }}
      >
        <span
          className={`toggle${showChevron ? '' : ' invisible'}${isExpanded ? ' expanded' : ''}`}
          onClick={handleToggleClick}
        >
          {icon}
        </span>
        <span className="name-wrap">
          <FolderIcon className="folder-icon-image" size={16} />
          <span className="name__label" title={node.name}>
            {node.name}
          </span>
        </span>
        {node.id !== 'root' && (
          <div className="folder-row__actions">
            <button
              type="button"
              className="icon-button ghost"
              onClick={(event) => {
                event.stopPropagation();
                if (!onRename) return;
                const nextName = window.prompt('Rename folder', node.name);
                if (!nextName) {
                  return;
                }
                const trimmed = nextName.trim();
                if (!trimmed || trimmed === node.name) {
                  return;
                }
                onRename(node.id, trimmed);
              }}
              title="Rename folder"
              aria-label={`Rename folder ${node.name}`}
            >
              <EditIcon className="icon-edit" size={18} />
            </button>
            <button
              type="button"
              className="icon-button ghost"
              onClick={(event) => {
                event.stopPropagation();
                onDelete(node.id);
              }}
              title="Delete folder"
              aria-label={`Delete folder ${node.name}`}
            >
              <TrashIcon className="icon-trash" size={18} />
            </button>
          </div>
        )}
      </div>
      {isExpanded && node.children.length > 0 && (
        <ul className={`folder-children${depth === 0 ? ' folder-children--level1' : ''}`}>
          {renderChildren(node.children, depth + 1)}
        </ul>
      )}
    </li>
  );
};

const THEME_MODES = ['system', 'light', 'dark'];
const THEME_MODE_LABELS = {
  system: 'System',
  light: 'Light',
  dark: 'Dark',
};

const Sidebar = ({
  folderNodes,
  onToggle,
  onSelect,
  onDrop,
  onDragOver,
  onDragLeave,
  onDeleteFolder,
  onRenameFolder,
  selectedFolder,
  onFolderDragStart,
  onFolderDragEnd,
  draggedFolderId,
  onCreateFolder,
  creatingFolder = false,
  tags = [],
  untaggedFilterId = null,
  activeTagIds = [],
  onToggleTagFilter,
  correspondents = [],
  activeCorrespondentIds = [],
  onToggleCorrespondentFilter,
  onManageTags,
  onManageCorrespondents,
  onCreateTag,
  onCreateCorrespondent,
  searchQuery = '',
  onSearchChange,
  onSearchSubmit,
  onSearchClear,
  isFilterActive,
  onLogout,
  status,
  tenantName,
  tenants = [],
  activeTenantId = null,
  onSelectTenant,
  onOpenSettings,
  onUploadFiles,
}) => {
  const {
    setCollapsed,
    neutralHue,
    setNeutralHue,
    resetNeutralHue,
    neutralChroma,
    setNeutralChroma,
    resetNeutralChroma,
    neutralContrast,
    setNeutralContrast,
    resetNeutralContrast,
    themeMode,
    cycleThemeMode,
    themeModes,
    sidebarSuppressed,
  } = useSidebarContext();
  const uploadInputRef = useRef(null);
  const sidebarRef = useRef(null);
  const pendingWidthRef = useRef(null);
  const [isResizingSidebar, setIsResizingSidebar] = useState(false);
  const [sidebarWidthState, setSidebarWidthState] = useState(() => {
    if (!isBrowser) {
      return null;
    }
    const stored = loadStoredSidebarWidth();
    return stored != null ? clampSidebarWidth(stored) : null;
  });

  useEffect(() => {
    if (sidebarWidthState != null) {
      const clamped = clampSidebarWidth(sidebarWidthState);
      if (clamped != null) {
        applySidebarWidth(clamped);
      }
    }
  }, [sidebarWidthState]);

  useEffect(() => {
    if (!isBrowser) {
      return undefined;
    }
    const handleResize = () => {
      setSidebarWidthState((prev) => {
        if (prev == null) {
          return prev;
        }
        const clamped = clampSidebarWidth(prev);
        if (clamped != null && clamped !== prev) {
          applySidebarWidth(clamped);
          try {
            window.localStorage?.setItem(SIDEBAR_WIDTH_STORAGE_KEY, String(Math.round(clamped)));
          } catch (error) {
            console.warn('Failed to persist sidebar width', error);
          }
          return clamped;
        }
        return prev;
      });
    };
    window.addEventListener('resize', handleResize);
    return () => window.removeEventListener('resize', handleResize);
  }, []);

  const handleSidebarResizePointerDown = useCallback((event) => {
    if (!isBrowser || !sidebarRef.current) {
      return;
    }
    event.preventDefault();
    event.stopPropagation();
    const pointerId = event.pointerId;
    const target = event.currentTarget;
    target.setPointerCapture?.(pointerId);
    setIsResizingSidebar(true);

    const rect = sidebarRef.current.getBoundingClientRect();
    const startWidth = rect.width;
    const startX = event.clientX;

    const updateWidth = (nextWidth) => {
      const clamped = clampSidebarWidth(nextWidth);
      if (clamped != null) {
        pendingWidthRef.current = clamped;
        applySidebarWidth(clamped);
      }
    };

    const handlePointerMove = (moveEvent) => {
      if (moveEvent.pointerId !== pointerId) {
        return;
      }
      const delta = moveEvent.clientX - startX;
      updateWidth(startWidth + delta);
    };

    const handlePointerUp = (upEvent) => {
      if (upEvent.pointerId !== pointerId) {
        return;
      }
      target.releasePointerCapture?.(pointerId);
      window.removeEventListener('pointermove', handlePointerMove);
      window.removeEventListener('pointerup', handlePointerUp);
      setIsResizingSidebar(false);
      if (pendingWidthRef.current != null) {
        const finalizedWidth = pendingWidthRef.current;
        pendingWidthRef.current = null;
        setSidebarWidthState(finalizedWidth);
        try {
          window.localStorage?.setItem(SIDEBAR_WIDTH_STORAGE_KEY, String(Math.round(finalizedWidth)));
        } catch (error) {
          console.warn('Failed to persist sidebar width', error);
        }
      }
    };

    window.addEventListener('pointermove', handlePointerMove);
    window.addEventListener('pointerup', handlePointerUp);
  }, []);

  const handleSidebarResizeKeyDown = useCallback((event) => {
    if (!isBrowser) {
      return;
    }
    if (event.key !== 'ArrowLeft' && event.key !== 'ArrowRight') {
      return;
    }
    const baseWidth = pendingWidthRef.current
      ?? sidebarWidthState
      ?? sidebarRef.current?.getBoundingClientRect().width;
    if (!Number.isFinite(baseWidth)) {
      return;
    }
    event.preventDefault();
    const step = event.shiftKey ? 40 : 20;
    const delta = event.key === 'ArrowRight' ? step : -step;
    const nextWidth = clampSidebarWidth(baseWidth + delta);
    if (nextWidth == null) {
      return;
    }
    setSidebarWidthState(nextWidth);
    try {
      window.localStorage?.setItem(SIDEBAR_WIDTH_STORAGE_KEY, String(Math.round(nextWidth)));
    } catch (error) {
      console.warn('Failed to persist sidebar width', error);
    }
  }, [sidebarWidthState]);
  const handleCollapse = useCallback(() => {
    setCollapsed(true);
  }, [setCollapsed]);
  const neutralHueInputId = useId();
  const neutralChromaInputId = useId();
  const neutralContrastInputId = useId();
  const sortedCorrespondents = useMemo(() => {
    if (!Array.isArray(correspondents)) {
      return [];
    }
    return correspondents
      .filter((entry) => entry?.name)
      .slice()
      .sort((a, b) => a.name.localeCompare(b.name, undefined, { sensitivity: 'base' }));
  }, [correspondents]);
  const activeCorrespondentSet = useMemo(
    () => new Set(activeCorrespondentIds || []),
    [activeCorrespondentIds],
  );
  const handleToggleTag = onToggleTagFilter || (() => {});
  const activeTagSet = new Set(activeTagIds);
  const untaggedActive = untaggedFilterId ? activeTagSet.has(untaggedFilterId) : false;
  const handleManageTags = onManageTags || (() => {});
  const handleManageCorrespondents = onManageCorrespondents || (() => {});
  const handleCreateTag = useCallback(async () => {
    const input = window.prompt('New tag name');
    if (!input) {
      return;
    }
    const trimmed = input.trim();
    if (!trimmed) {
      return;
    }
    try {
      await onCreateTag?.(trimmed);
    } catch (error) {
      console.error('[sidebar] failed to create tag', error);
    }
  }, [onCreateTag]);

  const handleCreateCorrespondent = useCallback(async () => {
    const input = window.prompt('New correspondent name');
    if (!input) {
      return;
    }
    const trimmed = input.trim();
    if (!trimmed) {
      return;
    }
    try {
      await onCreateCorrespondent?.(trimmed);
    } catch (error) {
      console.error('[sidebar] failed to create correspondent', error);
    }
  }, [onCreateCorrespondent]);

  const handleCreateFolder = useCallback(() => {
    if (creatingFolder) {
      return;
    }
    onCreateFolder?.();
  }, [creatingFolder, onCreateFolder]);

  const handleUploadButtonClick = useCallback(() => {
    if (!onUploadFiles || !uploadInputRef.current) {
      return;
    }
    uploadInputRef.current.click();
  }, [onUploadFiles]);

  const handleUploadInputChange = useCallback(
    (event) => {
      const files = event.target?.files;
      if (files && files.length && onUploadFiles) {
        onUploadFiles(files, selectedFolder);
      }
      if (event.target) {
        event.target.value = '';
      }
    },
    [onUploadFiles, selectedFolder],
  );

  const handleThemeAdjustmentsReset = useCallback(() => {
    resetNeutralHue();
    resetNeutralChroma();
    resetNeutralContrast();
  }, [resetNeutralHue, resetNeutralChroma, resetNeutralContrast]);

  const handleNeutralHueChange = useCallback(
    (value) => {
      if (value === '') {
        resetNeutralHue();
        return;
      }
      const parsed = Number(value);
      if (Number.isNaN(parsed)) {
        return;
      }
      setNeutralHue(parsed);
    },
    [resetNeutralHue, setNeutralHue],
  );

  const handleNeutralChromaChange = useCallback(
    (value) => {
      if (value === '') {
        resetNeutralChroma();
        return;
      }
      const parsed = Number(value);
      if (Number.isNaN(parsed)) {
        return;
      }
      setNeutralChroma(parsed);
    },
    [resetNeutralChroma, setNeutralChroma],
  );

  const handleNeutralContrastChange = useCallback(
    (value) => {
      if (value === '') {
        resetNeutralContrast();
        return;
      }
      const parsed = Number(value);
      if (Number.isNaN(parsed)) {
        return;
      }
      setNeutralContrast(parsed);
    },
    [resetNeutralContrast, setNeutralContrast],
  );

  const formatSliderValue = useCallback((value) => {
    const parsed = Number(value);
    if (Number.isNaN(parsed)) {
      return value;
    }
    return parsed.toFixed(2);
  }, []);

  const themeModeList = themeModes && themeModes.length ? themeModes : THEME_MODES;
  const themeModeIndex = themeModeList.indexOf(themeMode);
  const safeThemeModeIndex = themeModeIndex === -1 ? 0 : themeModeIndex;
  const resolvedThemeMode = themeModeList[safeThemeModeIndex] || THEME_MODES[0];
  const nextThemeMode = themeModeList[(safeThemeModeIndex + 1) % themeModeList.length];
  const themeModeLabel = THEME_MODE_LABELS[resolvedThemeMode] || THEME_MODE_LABELS.system;
  const nextThemeLabel = THEME_MODE_LABELS[nextThemeMode] || THEME_MODE_LABELS.system;
  const themeModeIcon = resolvedThemeMode === 'dark'
    ? <MoonIcon size={16} />
    : resolvedThemeMode === 'light'
      ? <SunIcon size={16} />
      : <DesktopIcon size={16} />;

  const handleThemeModeToggle = useCallback(() => {
    cycleThemeMode();
  }, [cycleThemeMode]);

  const themeMenuSection =
    typeof neutralHue === 'number' || typeof neutralHue === 'string'
      ? (
          <div className="menu__section">
            <div className="menu__heading menu__heading--with-actions">
              <span>Theme</span>
              <div className="menu__heading-actions">
                <button
                  type="button"
                  className="icon-button"
                  onClick={handleThemeModeToggle}
                  aria-label={`Switch theme (next: ${nextThemeLabel})`}
                  title={`Theme: ${themeModeLabel} (next: ${nextThemeLabel})`}
                >
                  {themeModeIcon}
                </button>
                <button
                  type="button"
                  className="icon-button"
                  onClick={handleThemeAdjustmentsReset}
                  aria-label="Reset theme adjustments"
                  title="Reset theme adjustments"
                >
                  <RestoreIcon size={16} />
                </button>
              </div>
            </div>
            <label className="menu__slider" htmlFor={neutralHueInputId}>
              <span className="menu__slider-label">Hue</span>
              <input
                id={neutralHueInputId}
                type="range"
                min="0"
                max="360"
                step="1"
                value={neutralHue}
                onChange={(event) => handleNeutralHueChange(event.target.value)}
                onDoubleClick={resetNeutralHue}
              />
              <span className="menu__slider-value">{neutralHue}°</span>
            </label>
            <label className="menu__slider" htmlFor={neutralChromaInputId}>
              <span className="menu__slider-label">Chroma</span>
              <input
                id={neutralChromaInputId}
                type="range"
                min="0"
                max="1"
                step="0.01"
                value={neutralChroma}
                onChange={(event) => handleNeutralChromaChange(event.target.value)}
                onDoubleClick={resetNeutralChroma}
              />
              <span className="menu__slider-value">{formatSliderValue(neutralChroma)}</span>
            </label>
            <label className="menu__slider" htmlFor={neutralContrastInputId}>
              <span className="menu__slider-label">Contrast</span>
              <input
                id={neutralContrastInputId}
                type="range"
                min="0"
                max="1"
                step="0.01"
                value={neutralContrast}
                onChange={(event) => handleNeutralContrastChange(event.target.value)}
                onDoubleClick={resetNeutralContrast}
              />
              <span className="menu__slider-value">{formatSliderValue(neutralContrast)}</span>
            </label>
          </div>
        )
      : null;

  const handleSearchInputChange = useCallback(
    (event) => {
      onSearchChange?.(event.target.value);
    },
    [onSearchChange],
  );
  const handleSearchFormSubmit = useCallback(
    (event) => {
      event.preventDefault();
      onSearchSubmit?.();
    },
    [onSearchSubmit],
  );
  const handleSearchClear = useCallback(() => {
    onSearchClear?.();
  }, [onSearchClear]);
  const tenantButtonRef = useRef(null);
  const {
    isOpen: tenantMenuOpen,
    toggle: toggleTenantMenuFloating,
    close: closeTenantMenu,
    menuRef: tenantMenuRef,
    menuStyle: tenantMenuStyle,
    updatePosition: refreshTenantMenuPosition,
  } = useFloatingMenu({
    anchorRef: tenantButtonRef,
    minWidth: 220,
    offset: 6,
  });
  const showTenantList = tenants.length > 1;
  const menuClassName = `menu${!showTenantList && !themeMenuSection ? ' menu--simple' : ''}`;

  const toggleTenantMenu = useCallback(() => {
    if (!tenantMenuOpen && tenants.length === 0 && onSelectTenant) {
      onSelectTenant(null, { refreshOnly: true });
    }
    toggleTenantMenuFloating();
  }, [tenantMenuOpen, tenants.length, onSelectTenant, toggleTenantMenuFloating]);

  useEffect(() => {
    if (tenantMenuOpen) {
      refreshTenantMenuPosition();
    }
  }, [tenantMenuOpen, refreshTenantMenuPosition, tenants.length]);

  const handleTenantSelect = useCallback(
    (tenant) => {
      const targetId = tenant?.id || null;
      if (!targetId) {
        return;
      }
      closeTenantMenu();
      onSelectTenant?.(tenant);
    },
    [closeTenantMenu, onSelectTenant],
  );

  const handleLogoutFromMenu = useCallback(() => {
    closeTenantMenu();
    onLogout?.();
  }, [closeTenantMenu, onLogout]);

  const handleSettingsFromMenu = useCallback(() => {
    closeTenantMenu();
    onOpenSettings?.();
  }, [closeTenantMenu, onOpenSettings]);

  const renderNodes = useCallback(
    (ids, depth) =>
      ids.map((id) => {
        const node = folderNodes.get(id);
        if (!node) return null;
        return (
          <FolderNode
            key={id}
            node={node}
            depth={depth}
            isSelected={selectedFolder === id}
            onToggle={() => onToggle(id)}
            onSelect={onSelect}
            onDrop={onDrop}
            onDragOver={onDragOver}
            onDragLeave={onDragLeave}
            onDelete={onDeleteFolder}
            onRename={onRenameFolder}
            renderChildren={renderNodes}
            onFolderDragStart={onFolderDragStart}
            onFolderDragEnd={onFolderDragEnd}
            draggingFolderId={draggedFolderId}
          />
        );
      }),
    [
      folderNodes,
      selectedFolder,
      onToggle,
      onSelect,
      onDrop,
      onDragOver,
      onDragLeave,
      onDeleteFolder,
      onRenameFolder,
      onFolderDragStart,
      onFolderDragEnd,
      draggedFolderId,
    ],
  );

  const rootNode = folderNodes.get('root');
  const sidebarClassNames = ['sidebar'];
  if (isResizingSidebar) {
    sidebarClassNames.push('sidebar--resizing');
  }
  if (sidebarSuppressed) {
    sidebarClassNames.push('sidebar--suppressed');
  }

  return (
    <aside className={sidebarClassNames.join(' ')} ref={sidebarRef}>
      <button
        type="button"
        className={`sidebar__resize-handle${isResizingSidebar ? ' is-active' : ''}`}
        aria-label="Resize sidebar"
        onPointerDown={handleSidebarResizePointerDown}
        onKeyDown={handleSidebarResizeKeyDown}
      >
        <span aria-hidden="true" />
      </button>
      <input
        type="file"
        ref={uploadInputRef}
        style={{ display: 'none' }}
        multiple
        onChange={handleUploadInputChange}
      />
      <PanelHeader
        className="sidebar__header"
        leading={(
          <>
            <button
              type="button"
              className={`sidebar__title-button${tenantMenuOpen ? ' is-open' : ''}`}
              onClick={toggleTenantMenu}
              aria-haspopup="true"
              aria-expanded={tenantMenuOpen}
              ref={tenantButtonRef}
            >
              <span className="sidebar__title">
                Papercrate
                {tenantName ? <span className="sidebar__tenant"> / {tenantName}</span> : null}
              </span>
              <ChevronDownIcon
                className={`sidebar__title-chevron${tenantMenuOpen ? ' is-open' : ''}`}
                size={16}
              />
            </button>
            {tenantMenuOpen
              && tenantMenuStyle
              && typeof document !== 'undefined'
              ? createPortal(
                  <div
                    className={menuClassName}
                    ref={tenantMenuRef}
                    role="menu"
                    aria-label="Account menu"
                    style={tenantMenuStyle}
                  >
                    {showTenantList ? (
                      <div className="menu__section">
                        <div className="menu__heading">Switch tenant</div>
                        <div className="menu__wrapper">
                          {tenants.map((tenant) => {
                            const tenantId = tenant?.id || null;
                            const isActive = tenantId === activeTenantId;
                            const tenantLabel = tenant?.name;
                            return (
                              <button
                                key={tenantId || tenantLabel}
                                type="button"
                                className={`menu__button${isActive ? ' active' : ''}`}
                                onClick={() => handleTenantSelect(tenant)}
                                role="menuitem"
                              >
                                <span className="menu__check-slot">
                                  {isActive ? <CheckIcon size={16} /> : null}
                                </span>
                                <span className="menu__label">{tenantLabel}</span>
                              </button>
                            );
                          })}
                        </div>
                      </div>
                    ) : null}
                    <div className="menu__section">
                      <div className="menu__wrapper">
                        <button
                          type="button"
                          className="menu__button"
                          onClick={handleSettingsFromMenu}
                        >
                          <SettingsIcon size={16} />
                          Settings
                        </button>
                        <button
                          type="button"
                          className="menu__button menu__button--danger"
                          onClick={handleLogoutFromMenu}
                        >
                          <LogoutIcon size={16} />
                          Log out
                        </button>
                      </div>
                    </div>
                    {themeMenuSection}
                  </div>,
                  document.body,
                )
              : null}
          </>
        )}
        actions={(
          <>
            {handleCollapse ? (
              <button
                type="button"
                className="icon-button sidebar__collapse-button"
                onClick={handleCollapse}
                aria-label="Collapse sidebar"
                title="Collapse sidebar"
              >
                <SidebarCollapseIcon />
              </button>
            ) : null}
            <button
              type="button"
              className="icon-button"
              onClick={handleUploadButtonClick}
              disabled={!onUploadFiles}
              title="Upload documents"
              aria-label="Upload documents"
            >
              <UploadIcon size={18} />
            </button>
          </>
        )}
      />
      <div className="panel-body sidebar__body">
        {status && (
          <div className="sidebar__status">
            <div className={`status-banner ${status.variant}`}>{status.message}</div>
          </div>
        )}
        {onSearchChange && (
          <form className="sidebar__search" onSubmit={handleSearchFormSubmit}>
            <input
              type="search"
              value={searchQuery}
              onChange={handleSearchInputChange}
              placeholder="Search documents"
              aria-label="Search documents"
            />
            {isFilterActive && (
              <button type="button" onClick={handleSearchClear}>
                Clear
              </button>
            )}
          </form>
        )}
        <div className="sidebar-section sidebar-section--folders">
          <div className="sidebar-section__header">
            <h3>Folders</h3>
            {onCreateFolder ? (
              <div className="sidebar-section__actions">
                <button
                  type="button"
                  className="icon-button"
                  onClick={handleCreateFolder}
                  aria-label="Create folder"
                  disabled={creatingFolder}
                >
                  <FolderPlusIcon size={16} />
                </button>
              </div>
            ) : null}
          </div>
          <ul className="folder-tree">
            {rootNode && renderNodes([rootNode.id], 0)}
          </ul>
        </div>
        <div className="sidebar-section">
          <div className="sidebar-section__header">
            <h3>Tags</h3>
            <div className="sidebar-section__actions">
              <button
                type="button"
                className="icon-button"
                onClick={handleCreateTag}
                aria-label="Create tag"
              >
                <PlusIcon size={16} />
              </button>
              <button
                type="button"
                className="icon-button"
                onClick={handleManageTags}
                aria-label="Manage tags"
              >
                <SettingsIcon size={16} />
              </button>
              <span className="meta">{tags.length}</span>
            </div>
          </div>
          <div
            className={`sidebar-tag-cloud${
              activeTagSet.size ? ' sidebar-tag-cloud--has-active' : ''
            }`}
            role="list"
          >
            {untaggedFilterId ? (
              <button
                type="button"
                role="listitem"
                className={`sidebar-tag-pill sidebar-tag-pill--untagged${
                  untaggedActive ? ' active' : ''
                }`}
                onClick={() => handleToggleTag(untaggedFilterId)}
                aria-pressed={untaggedActive}
                draggable={false}
              >
                No tag assigned
              </button>
            ) : null}
            {tags.map((tag) => {
              const isActive = activeTagSet.has(tag.id);
              const style = getTagColorStyle(tag.color);
              const className = `sidebar-tag-pill${isActive ? ' active' : ''}`;
              return (
                <button
                  key={tag.id}
                  type="button"
                  role="listitem"
                  className={className}
                  style={style || undefined}
                  onClick={() => handleToggleTag(tag.id)}
                  aria-pressed={isActive}
              draggable
              onDragStart={(event) => {
                try {
                  const payload = JSON.stringify({
                    id: tag.id,
                    label: tag.label,
                    color: tag.color || null,
                  });
                  event.dataTransfer.effectAllowed = 'copy';
                  event.dataTransfer.setData('application/x-papercrate-tag', payload);
                  event.dataTransfer.setData('text/papercrate-tag', payload);
                } catch (error) {
                  console.warn('[sidebar] Failed to set tag drag payload', error);
                }
              }}
            >
              {tag.label}
            </button>
          );
            })}
          </div>
        </div>
        <div className="sidebar-section">
          <div className="sidebar-section__header">
            <h3>Correspondents</h3>
            <div className="sidebar-section__actions">
              <button
                type="button"
                className="icon-button"
                onClick={handleCreateCorrespondent}
                aria-label="Create correspondent"
              >
                <PlusIcon size={16} />
              </button>
              <button
                type="button"
                className="icon-button"
                onClick={handleManageCorrespondents}
                aria-label="Manage correspondents"
              >
                <SettingsIcon size={16} />
              </button>
              <span className="meta">{correspondents.length}</span>
            </div>
          </div>
          <ul className="sidebar-correspondent-list">
            {sortedCorrespondents.map((correspondent) => {
              const isActive = activeCorrespondentSet.has(correspondent.id);
              const className = `sidebar-correspondent-item${isActive ? ' active' : ''}`;
              const handleSelect = () => {
                const nextId = isActive ? null : correspondent.id;
                onToggleCorrespondentFilter?.(nextId);
              };
              return (
                <li key={correspondent.id}>
                  <span
                    className={className}
                    role="button"
                    onClick={handleSelect}
                    onKeyDown={(event) => {
                      if (event.key === 'Enter' || event.key === ' ') {
                        event.preventDefault();
                        handleSelect();
                      }
                    }}
                  >
                    {correspondent.name}
                  </span>
                </li>
              );
            })}
          </ul>
        </div>
      </div>
    </aside>
  );
};

export default Sidebar;
export { FolderNode };
