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

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

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,
}) => {
  const {
    setCollapsed,
    neutralHue,
    setNeutralHue,
    resetNeutralHue,
    themeMode,
    cycleThemeMode,
    themeModes,
  } = useSidebarContext();
  const handleCollapse = useCallback(() => {
    setCollapsed(true);
  }, [setCollapsed]);
  const neutralHueInputId = 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 handleNeutralHueReset = useCallback(() => {
    resetNeutralHue();
  }, [resetNeutralHue]);

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

  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 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 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 themeControls =
    typeof neutralHue === 'number' || typeof neutralHue === 'string'
      ? (
          <div className="sidebar-section sidebar-theme">
            <div className="sidebar-section__header">
              <h3>Theme</h3>
              <div className="sidebar-section__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={handleNeutralHueReset}
                  aria-label="Reset neutral hue"
                  title="Reset neutral hue"
                >
                  <RestoreIcon size={16} />
                </button>
              </div>
            </div>
            <label className="sidebar-slider" htmlFor={neutralHueInputId}>
              <span className="sidebar-slider__label">Hue</span>
              <input
                id={neutralHueInputId}
                type="range"
                min="0"
                max="360"
                step="1"
                value={neutralHue}
                onChange={(event) => handleNeutralHueChange(event.target.value)}
              />
              <span className="sidebar-slider__value">{neutralHue}°</span>
            </label>
          </div>
        )
      : null;

  return (
    <aside className="sidebar">
      <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={`menu${showTenantList ? '' : ' menu--simple'}`}
                    ref={tenantMenuRef}
                    role="menu"
                    aria-label="Account menu"
                    style={tenantMenuStyle}
                  >
                    {showTenantList ? (
                      <>
                        <div className="menu__heading">Switch tenant</div>
                        <div className="menu__list">
                          {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__item${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>
                      </>
                    ) : null}
                    <div className="menu__footer">
                      <button
                        type="button"
                        className="menu__settings"
                        onClick={handleSettingsFromMenu}
                      >
                        <SettingsIcon size={16} />
                        Settings
                      </button>
                      <button
                        type="button"
                        className="menu__logout"
                        onClick={handleLogoutFromMenu}
                      >
                        <LogoutIcon size={16} />
                        Log out
                      </button>
                    </div>
                  </div>,
                  document.body,
                )
              : null}
          </>
        )}
        actions={
            handleCollapse
            ? [
                (
                  <button
                    key="collapse"
                    type="button"
                    className="icon-button"
                    onClick={handleCollapse}
                    aria-label="Collapse sidebar"
                    title="Collapse sidebar"
                  >
                    <SidebarCollapseIcon />
                  </button>
                ),
              ]
            : null
        }
      />
      <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>
      {themeControls ? <div className="sidebar__footer">{themeControls}</div> : null}
    </aside>
  );
};

export default Sidebar;
export { FolderNode };
