import React, { useEffect, useMemo, useRef, useState, useCallback } from 'react';
import { useReactFlow } from 'reactflow';
import { 
  Folder, FileText, Archive, ChevronLeft, ChevronRight, Trash2, MessageSquare, 
  MoreVertical, Download, Upload, Plus, RefreshCw, Edit3, Loader2, LogOut, User
} from 'lucide-react';
import useFlowStore, { type FSItem, type BlueprintDocument, type FileMeta } from '../store/flowStore';
import { useAuthStore } from '../store/authStore';

interface LeftSidebarProps {
  isOpen: boolean;
  onToggle: () => void;
}

const LeftSidebar: React.FC<LeftSidebarProps> = ({ isOpen, onToggle }) => {
  const [activeTab, setActiveTab] = useState<'project' | 'files' | 'archive'>('project');
  const {
    archivedNodes,
    removeFromArchive,
    createNodeFromArchive,
    theme,
    files,
    uploadingFileIds,
    projectTree,
    currentBlueprintPath,
    saveStatus,
    refreshProjectTree,
    loadArchivedNodes,
    refreshFiles,
    uploadFile,
    deleteFile,
    readBlueprintFile,
    loadBlueprint,
    saveBlueprintFile,
    saveCurrentBlueprint,
    createProjectFolder,
    renameProjectItem,
    deleteProjectItem,
    setCurrentBlueprintPath,
    serializeBlueprint,
    clearBlueprint
  } = useFlowStore();
  const { user, logout } = useAuthStore();
  const { setViewport, getViewport } = useReactFlow();
  const isDark = theme === 'dark';
  const fileInputRef = useRef<HTMLInputElement | null>(null);
  const fileUploadRef = useRef<HTMLInputElement | null>(null);
  const [contextMenu, setContextMenu] = useState<{ x: number; y: number; item?: FSItem } | null>(null);
  const [currentFolder, setCurrentFolder] = useState<string>('.');
  const [dragItem, setDragItem] = useState<FSItem | null>(null);
  const [showSaveStatus, setShowSaveStatus] = useState(false);
  const [expanded, setExpanded] = useState<Set<string>>(() => new Set(['.']));
  const [fileProvider, setFileProvider] = useState<'local' | 'openai' | 'google'>('local');
  const [openaiPurpose, setOpenaiPurpose] = useState<string>('user_data');
  const [fileSearch, setFileSearch] = useState('');
  
  const handleDragStart = (e: React.DragEvent, archiveId: string) => {
    e.dataTransfer.setData('archiveId', archiveId);
    e.dataTransfer.effectAllowed = 'copy';
  };

  const joinPath = (folder: string, name: string) => {
    if (!folder || folder === '.' || folder === '/') return name;
    return `${folder.replace(/\\/g, '/').replace(/\/+$/, '')}/${name}`;
  };

  const stripJson = (name: string) => name.endsWith('.json') ? name.slice(0, -5) : name;

  const findChildren = useCallback((folder: string, list: FSItem[] = projectTree): FSItem[] => {
    const norm = folder.replace(/\\/g, '/').replace(/^\.\/?/, '');
    if (folder === '.' || folder === '' || folder === '/') return list;
    for (const item of list) {
      if (item.type === 'folder') {
        if (item.path === norm) return item.children || [];
        const found = findChildren(folder, item.children || []);
        if (found) return found;
      }
    }
    return [];
  }, [projectTree]);

  const ensureUniqueName = useCallback((base: string, targetFolder: string, isFolder: boolean) => {
    const siblings = findChildren(targetFolder).map(i => i.name);
    const ext = isFolder ? '' : '.json';
    const rawBase = stripJson(base);
    let candidate = rawBase + ext;
    let idx = 1;
    while (siblings.includes(candidate)) {
      idx += 1;
      candidate = `${rawBase} (${idx})${ext}`;
    }
    return candidate;
  }, [findChildren]);

  // Load project tree on mount and when tab switches to project
  useEffect(() => {
    if (activeTab === 'project') {
      refreshProjectTree().catch(() => {});
    }
  }, [activeTab, refreshProjectTree]);

  // Load archived nodes on mount
  useEffect(() => {
    loadArchivedNodes().catch(() => {});
  }, [loadArchivedNodes]);

  // Load files when entering files tab
  useEffect(() => {
    if (activeTab === 'files') {
      refreshFiles().catch(() => {});
    }
  }, [activeTab, refreshFiles]);

  // Context menu handlers
  const openContextMenu = (e: React.MouseEvent, item?: FSItem) => {
    e.preventDefault();
    e.stopPropagation();
    setContextMenu({ x: e.clientX, y: e.clientY, item });
  };

  const closeContextMenu = () => setContextMenu(null);

  const promptName = (message: string, defaultValue: string) => {
    const val = window.prompt(message, defaultValue);
    return val?.trim() || null;
  };

  const handleCreateFolder = async (base: string) => {
    const input = promptName('Folder name', 'new-folder');
    if (!input) return;
    const name = ensureUniqueName(input, base, true);
    await createProjectFolder(joinPath(base, name));
  };

  const handleNewBlueprint = async (base: string) => {
    const input = promptName('Blueprint file name', 'untitled');
    if (!input) return;
    const name = ensureUniqueName(input, base, false);
    const path = joinPath(base, name);
    // Create empty blueprint and save immediately
    const empty: BlueprintDocument = {
      version: 1,
      nodes: [],
      edges: [],
      viewport: getViewport(),
      theme,
    };
    await saveBlueprintFile(path, empty.viewport);
    await loadBlueprint(empty);
    setCurrentBlueprintPath(path);
  };

  const handleRename = async (item: FSItem) => {
    const newName = promptName('Rename to', item.name);
    if (!newName || newName === item.name) return;
    await renameProjectItem(item.path, newName);
  };

  const handleDelete = async (item: FSItem) => {
    const currentPath = currentBlueprintPath;
    const isDeletingOpen =
      currentPath === item.path ||
      (item.type === 'folder' && currentPath && (currentPath === item.path || currentPath.startsWith(`${item.path}/`)));
    const ok = window.confirm(
      isDeletingOpen
        ? `The opened blueprint is in this ${item.type}. Delete and clear canvas?`
        : `Delete ${item.name}?`
    );
    if (!ok) return;
    await deleteProjectItem(item.path, item.type === 'folder');
    if (isDeletingOpen) {
      clearBlueprint();
    }
    await refreshProjectTree();
  };

  const handleLoadFile = async (item: FSItem) => {
    if (item.type !== 'file') return;
    try {
      const doc = await readBlueprintFile(item.path);
      const vp = loadBlueprint(doc);
      setCurrentBlueprintPath(item.path);
      if (vp) {
        setViewport(vp);
      }
    } catch (e) {
      console.error(e);
      alert('Not a valid blueprint JSON.');
    }
  };

  const handleDownload = async (item: FSItem) => {
    if (item.type !== 'file') return;
    const url = `${import.meta.env.VITE_BACKEND_URL || 'http://localhost:8000'}/api/projects/download?user=test&path=${encodeURIComponent(item.path)}`;
    const a = document.createElement('a');
    a.href = url;
    a.download = item.name;
    a.click();
  };

  const handleUploadClick = () => fileInputRef.current?.click();

  const promptForPath = (base: string) => {
    const input = window.prompt('Save as (filename without extension)', 'untitled')?.trim();
    if (!input) return null;
    const name = ensureUniqueName(input, base, false);
    return joinPath(base, name);
  };

  const handleSave = async () => {
    let path = currentBlueprintPath;
    if (!path) {
      const p = promptForPath(currentFolder);
      if (!p) return;
      path = p;
      setCurrentBlueprintPath(path);
    }
    const viewport = getViewport();
    await saveCurrentBlueprint(path, viewport);
  };

  const handleUploadFiles = async (files: FileList, targetFolder: string) => {
    for (const file of Array.from(files)) {
      if (!file.name.toLowerCase().endsWith('.json')) continue;
      const text = await file.text();
      try {
        const json = JSON.parse(text);
        const viewport = json.viewport;
        const uniqueName = ensureUniqueName(file.name, targetFolder, false);
        await saveBlueprintFile(joinPath(targetFolder, uniqueName), viewport);
      } catch {
        // skip invalid json
      }
    }
    await refreshProjectTree();
  };

  // Files tab handlers
  const handleFilesUpload = async (list: FileList) => {
    let ok = 0;
    let failed: string[] = [];
    for (const f of Array.from(list)) {
      try {
        await uploadFile(f, {
          provider: fileProvider,
          purpose: fileProvider === 'openai' ? openaiPurpose : undefined,
        });
        ok += 1;
      } catch (e) {
        console.error(e);
        failed.push(`${f.name}: ${(e as Error).message}`);
      }
    }
    await refreshFiles();
    if (failed.length) {
      alert(`Some files failed:\n${failed.join('\n')}`);
    } else if (ok > 0) {
      // Optional: brief feedback
      console.info(`Uploaded ${ok} file(s)`);
    }
  };

  const filteredFiles = useMemo(() => {
    const q = fileSearch.trim().toLowerCase();
    if (!q) return files;
    // Only search local files; keep provider files out of filtered results
    return files.filter(f => !f.provider && f.name.toLowerCase().includes(q));
  }, [files, fileSearch]);

  const handleFilesInputChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
    const files = e.target.files;
    if (files && files.length > 0) {
      await handleFilesUpload(files);
      e.target.value = '';
    }
  };

  const handleDownloadFile = (file: FileMeta) => {
    const url = `${import.meta.env.VITE_BACKEND_URL || 'http://localhost:8000'}/api/files/download?user=test&file_id=${encodeURIComponent(file.id)}`;
    const a = document.createElement('a');
    a.href = url;
    a.download = file.name;
    a.click();
  };

  const formatSize = (bytes: number) => {
    if (bytes === 0) return '0 B';
    const k = 1024;
    const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
    const i = Math.floor(Math.log(bytes) / Math.log(k));
    return `${(bytes / Math.pow(k, i)).toFixed(1)} ${sizes[i]}`;
  };

  // Fade-out for "Saved" indicator
  useEffect(() => {
    if (saveStatus === 'saved') {
      setShowSaveStatus(true);
      const t = window.setTimeout(() => setShowSaveStatus(false), 1000);
      return () => window.clearTimeout(t);
    }
    if (saveStatus === 'saving' || saveStatus === 'error') {
      setShowSaveStatus(true);
      return;
    }
    setShowSaveStatus(false);
  }, [saveStatus]);

  const handleFileInputChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
    const files = e.target.files;
    if (files && files.length > 0) {
      await handleUploadFiles(files, currentFolder);
      e.target.value = '';
    }
  };

  // Drag move blueprint into folder
  const onItemDragStart = (e: React.DragEvent, item: FSItem) => {
    setDragItem(item);
    e.dataTransfer.effectAllowed = 'move';
  };
  const onItemDragOver = (e: React.DragEvent, item: FSItem) => {
    if (item.type === 'folder') {
      e.preventDefault();
      e.dataTransfer.dropEffect = 'move';
    }
  };
  const onItemDrop = async (e: React.DragEvent, target: FSItem) => {
    e.preventDefault();
    if (!dragItem || target.type !== 'folder') return;
    const newPath = joinPath(target.path, dragItem.name);
    if (newPath === dragItem.path) return;
    await renameProjectItem(dragItem.path, undefined, newPath);
    setDragItem(null);
  };

  const toggleFolder = (path: string) => {
    setExpanded(prev => {
      const next = new Set(prev);
      if (next.has(path)) next.delete(path);
      else next.add(path);
      return next;
    });
  };

  const renderTree = useCallback((items: FSItem[], depth = 0) => {
    return items.map(item => {
      const isActive = currentBlueprintPath === item.path;
      const isExpanded = expanded.has(item.path);
      const padding = depth * 12;
      const hasChildren = (item.children?.length || 0) > 0;
      return (
        <div key={item.path}>
          <div
            className={`flex items-center justify-between px-2 py-1 rounded cursor-pointer ${
              isActive
                ? isDark ? 'bg-blue-900/40 border border-blue-700' : 'bg-blue-50 border-blue-200 border'
                : isDark ? 'hover:bg-gray-700' : 'hover:bg-gray-100'
            }`}
            style={{ paddingLeft: padding + 8 }}
            onContextMenu={(e) => openContextMenu(e, item)}
            onClick={() => {
              if (item.type === 'folder') {
                toggleFolder(item.path);
                setCurrentFolder(item.path);
              } else {
                setCurrentFolder(item.path.split('/').slice(0, -1).join('/') || '.');
              }
            }}
            onDoubleClick={() => {
              if (item.type === 'file') {
                handleLoadFile(item);
                setCurrentFolder(item.path.split('/').slice(0, -1).join('/') || '.');
              }
            }}
            draggable
            onDragStart={(e) => onItemDragStart(e, item)}
            onDragOver={(e) => onItemDragOver(e, item)}
            onDrop={(e) => onItemDrop(e, item)}
          >
            <div className="flex items-center gap-2">
              {item.type === 'folder' ? (
                <button
                  className="w-4 text-left"
                  onClick={(e) => { e.stopPropagation(); toggleFolder(item.path); }}
                  title={hasChildren ? undefined : 'Empty folder'}
                >
                  {isExpanded ? '▾' : '▸'}
                </button>
              ) : (
                <span className="w-4" />
              )}
              {item.type === 'folder' ? <Folder size={14} /> : <FileText size={14} />}
              <span className="truncate">{stripJson(item.name)}</span>
            </div>
            <button className="p-1 rounded hover:bg-gray-200 dark:hover:bg-gray-700" onClick={(e) => { e.stopPropagation(); openContextMenu(e as any, item); }}>
              <MoreVertical size={14} />
            </button>
          </div>
          {item.type === 'folder' && isExpanded && item.children && item.children.length > 0 && (
            <div>
              {renderTree(item.children, depth + 1)}
            </div>
          )}
        </div>
      );
    });
  }, [isDark, currentBlueprintPath, expanded, handleLoadFile]);

  if (!isOpen) {
    return (
      <div className={`border-r h-screen flex flex-col items-center py-4 w-12 z-10 transition-all duration-300 ${
        isDark ? 'border-gray-700 bg-gray-800' : 'border-gray-200 bg-white'
      }`}>
        <button 
          onClick={onToggle}
          className={`p-2 rounded mb-4 ${isDark ? 'hover:bg-gray-700' : 'hover:bg-gray-100'}`}
          title="Expand"
        >
          <ChevronRight size={20} className={isDark ? 'text-gray-400' : 'text-gray-500'} />
        </button>
        {/* Icons when collapsed */}
        <div className="flex flex-col gap-4">
           <Folder size={20} className={activeTab === 'project' ? "text-blue-500" : isDark ? "text-gray-500" : "text-gray-400"} />
           <FileText size={20} className={activeTab === 'files' ? "text-blue-500" : isDark ? "text-gray-500" : "text-gray-400"} />
           <Archive size={20} className={activeTab === 'archive' ? "text-blue-500" : isDark ? "text-gray-500" : "text-gray-400"} />
        </div>
      </div>
    );
  }

  return (
    <div 
      className={`w-[14%] min-w-[260px] max-w-[360px] border-r h-screen flex flex-col shadow-xl z-10 transition-all duration-300 ${
      isDark ? 'border-gray-700 bg-gray-800' : 'border-gray-200 bg-white'
    }`} 
      onClick={() => setContextMenu(null)}
      onContextMenu={(e) => {
        // Default empty-area context menu
        if (activeTab === 'project') {
          openContextMenu(e);
        }
      }}
    >
      {/* Header */}
      <div className={`p-3 border-b flex justify-between items-center ${
        isDark ? 'border-gray-700 bg-gray-900' : 'border-gray-200 bg-gray-50'
      }`}>
        <div className="flex items-center gap-2">
          <h2 className={`font-bold text-sm uppercase ${isDark ? 'text-gray-300' : 'text-gray-700'}`}>Workspace</h2>
          {user && (
            <span className={`text-xs px-2 py-0.5 rounded-full ${
              isDark ? 'bg-gray-700 text-gray-400' : 'bg-gray-200 text-gray-600'
            }`}>
              <User size={10} className="inline mr-1" />
              {user.username}
            </span>
          )}
        </div>
        <div className="flex items-center gap-1">
          {user && (
            <button 
              onClick={logout}
              className={`p-1 rounded transition-colors ${
                isDark 
                  ? 'hover:bg-red-900/50 text-gray-400 hover:text-red-400' 
                  : 'hover:bg-red-50 text-gray-500 hover:text-red-500'
              }`}
              title="Logout"
            >
              <LogOut size={16} />
            </button>
          )}
          <button 
            onClick={onToggle}
            className={`p-1 rounded ${isDark ? 'hover:bg-gray-700' : 'hover:bg-gray-200'}`}
          >
            <ChevronLeft size={16} className={isDark ? 'text-gray-400' : 'text-gray-500'} />
          </button>
        </div>
      </div>

      {/* Tabs */}
      <div className={`flex border-b ${isDark ? 'border-gray-700' : 'border-gray-200'}`}>
        <button 
          onClick={() => setActiveTab('project')}
          className={`flex-1 p-3 text-xs flex justify-center items-center gap-2 ${
            activeTab === 'project' 
              ? 'border-b-2 border-blue-500 text-blue-500 font-medium' 
              : isDark ? 'text-gray-400 hover:bg-gray-700' : 'text-gray-600 hover:bg-gray-50'
          }`}
        >
          <Folder size={14} /> Project
        </button>
        <button 
          onClick={() => setActiveTab('files')}
          className={`flex-1 p-3 text-xs flex justify-center items-center gap-2 ${
            activeTab === 'files' 
              ? 'border-b-2 border-blue-500 text-blue-500 font-medium' 
              : isDark ? 'text-gray-400 hover:bg-gray-700' : 'text-gray-600 hover:bg-gray-50'
          }`}
        >
          <FileText size={14} /> Files
        </button>
        <button 
          onClick={() => setActiveTab('archive')}
          className={`flex-1 p-3 text-xs flex justify-center items-center gap-2 ${
            activeTab === 'archive' 
              ? 'border-b-2 border-blue-500 text-blue-500 font-medium' 
              : isDark ? 'text-gray-400 hover:bg-gray-700' : 'text-gray-600 hover:bg-gray-50'
          }`}
        >
          <Archive size={14} /> Archive
        </button>
      </div>

      {/* Content Area */}
      <div className={`flex-1 overflow-y-auto p-4 text-sm ${isDark ? 'text-gray-400' : 'text-gray-500'}`}>
        {activeTab === 'project' && (
          <div 
            className="space-y-2"
          >
            <div 
              className="flex items-center gap-2 mb-2"
              onContextMenu={(e) => { e.preventDefault(); e.stopPropagation(); }}
            >
              <button
                onClick={() => refreshProjectTree()}
                className={`p-1 rounded ${isDark ? 'hover:bg-gray-700' : 'hover:bg-gray-200'}`}
                title="Refresh"
              >
                <RefreshCw size={14} />
              </button>
              <button
                onClick={() => handleNewBlueprint(currentFolder)}
                className={`p-1 rounded ${isDark ? 'hover:bg-gray-700' : 'hover:bg-gray-200'}`}
                title="New Blueprint"
              >
                <Plus size={14} />
              </button>
              <button
                onClick={() => handleCreateFolder(currentFolder)}
                className={`p-1 rounded ${isDark ? 'hover:bg-gray-700' : 'hover:bg-gray-200'}`}
                title="New Folder"
              >
                <Folder size={14} />
              </button>
              <button
                onClick={handleUploadClick}
                className={`p-1 rounded ${isDark ? 'hover:bg-gray-700' : 'hover:bg-gray-200'}`}
                title="Upload Blueprint"
              >
                <Upload size={14} />
              </button>
              <button
                onClick={handleSave}
                className={`p-1 rounded ${isDark ? 'hover:bg-gray-700' : 'hover:bg-gray-200'}`}
                title="Save (Ctrl+S)"
              >
                <Edit3 size={14} />
              </button>
              <span 
                className={`text-xs transition-opacity duration-300 ${
                  saveStatus === 'saved' ? 'text-green-500' : saveStatus === 'saving' ? 'text-blue-500' : saveStatus === 'error' ? 'text-red-500' : isDark ? 'text-gray-500' : 'text-gray-400'
                }`}
                style={{ opacity: showSaveStatus && saveStatus !== 'idle' ? 1 : 0 }}
              >
                {saveStatus === 'saved' ? 'Saved' : saveStatus === 'saving' ? 'Saving...' : saveStatus === 'error' ? 'Save failed' : ''}
              </span>
              <input
                ref={fileInputRef}
                type="file"
                accept=".json,application/json"
                multiple
                className="hidden"
                onChange={handleFileInputChange}
              />
            </div>
            {!currentBlueprintPath && (
              <div className={`text-xs italic ${isDark ? 'text-gray-500' : 'text-gray-400'}`}>
                No file open; Save will create a new file.
              </div>
            )}

            <div 
              className={`${isDark ? 'border-gray-700' : 'border-gray-200'} border-t border-dashed mx-1`} 
              onContextMenu={(e) => { e.preventDefault(); e.stopPropagation(); }}
            />

            <div
              onContextMenu={(e) => {
                if (activeTab === 'project') {
                  openContextMenu(e);
                }
              }}
              onDragOver={(e) => { 
                if (e.dataTransfer.types.includes('Files')) { e.preventDefault(); }
              }}
              onDrop={async (e) => {
                if (e.dataTransfer.files?.length) {
                  e.preventDefault();
                  await handleUploadFiles(e.dataTransfer.files, currentFolder);
                }
              }}
            >
              {projectTree.length === 0 ? (
                <div className="flex flex-col items-center justify-center h-40 opacity-50">
                  <Folder size={32} className="mb-2" />
                  <p className="text-xs text-center">No files. Right-click to add.</p>
                </div>
              ) : (
                <div className="space-y-1">
                  {renderTree(projectTree, 0)}
                </div>
              )}
            </div>
          </div>
        )}
        {activeTab === 'files' && (
          <div 
            className="flex flex-col h-full gap-2"
            onDragOver={(e) => { if (e.dataTransfer.types.includes('Files')) e.preventDefault(); }}
            onDrop={async (e) => {
              if (e.dataTransfer.files?.length) {
                e.preventDefault();
                await handleFilesUpload(e.dataTransfer.files);
              }
            }}
          >
            <div className="flex items-center gap-2">
              <button
                onClick={() => refreshFiles()}
                className={`p-1 rounded ${isDark ? 'hover:bg-gray-700' : 'hover:bg-gray-200'}`}
                title="Refresh files"
              >
                <RefreshCw size={14} />
              </button>
              <button
                onClick={() => fileUploadRef.current?.click()}
                className={`p-1 rounded ${isDark ? 'hover:bg-gray-700' : 'hover:bg-gray-200'}`}
                title="Upload files (drag & drop supported)"
              >
                <Upload size={14} />
              </button>
              <input
                ref={fileUploadRef}
                type="file"
                multiple
                className="hidden"
                onChange={handleFilesInputChange}
              />
              <span className={`text-xs ${isDark ? 'text-gray-500' : 'text-gray-500'}`}>Drag files here or click upload</span>
            </div>

            <div className="flex items-center gap-2">
              <input
                value={fileSearch}
                onChange={(e) => setFileSearch(e.target.value)}
                className={`flex-1 text-sm border rounded px-2 py-1 ${isDark ? 'bg-gray-800 border-gray-700 text-gray-100 placeholder-gray-500' : 'bg-white border-gray-200 text-gray-800 placeholder-gray-400'}`}
                placeholder="Search files by name..."
              />
              {fileSearch && (
                <button
                  onClick={() => setFileSearch('')}
                  className={`text-xs px-2 py-1 rounded ${isDark ? 'bg-gray-800 border border-gray-700 text-gray-200' : 'bg-gray-100 border border-gray-200 text-gray-700'}`}
                  title="Clear search"
                >
                  Clear
                </button>
              )}
            </div>

            {files.length === 0 && (uploadingFileIds?.length || 0) === 0 ? (
              <div className="flex flex-col items-center justify-center h-full opacity-50 border border-dashed border-gray-300 dark:border-gray-700 rounded">
                <FileText size={32} className="mb-2" />
                <p className="text-xs text-center">No files uploaded yet.</p>
              </div>
            ) : filteredFiles.length === 0 && (uploadingFileIds?.length || 0) === 0 ? (
              <div className="flex flex-col items-center justify-center h-full opacity-50 border border-dashed border-gray-300 dark:border-gray-700 rounded">
                <FileText size={32} className="mb-2" />
                <p className="text-xs text-center">No files match your search.</p>
              </div>
            ) : (
              <div className="flex-1 overflow-y-auto space-y-1">
                {filteredFiles.map(f => (
                  <div
                    key={f.id}
                    className={`flex items-center justify-between px-2 py-1 rounded border ${isDark ? 'border-gray-700 hover:bg-gray-800' : 'border-gray-200 hover:bg-gray-100'}`}
                  >
                    <div className="flex flex-col">
                      <span className="text-sm font-medium">{f.name}</span>
                      <span className={`text-[11px] ${isDark ? 'text-gray-500' : 'text-gray-500'}`}>
                        {formatSize(f.size)} • {new Date(f.created_at * 1000).toLocaleString()}
                      </span>
                      {f.provider && (
                        <span className={`text-[11px] inline-flex items-center gap-1 mt-0.5 px-2 py-0.5 rounded ${isDark ? 'bg-gray-800 text-gray-300 border border-gray-700' : 'bg-gray-100 text-gray-700 border border-gray-200'}`}>
                          Provider: {f.provider === 'openai' ? 'OpenAI' : f.provider === 'google' ? 'Gemini' : f.provider}
                        </span>
                      )}
                    </div>
                    <div className="flex items-center gap-2">
                      <button
                        onClick={() => handleDownloadFile(f)}
                        className={`p-1 rounded ${isDark ? 'hover:bg-gray-700' : 'hover:bg-gray-200'}`}
                        title="Download"
                      >
                        <Download size={14} />
                      </button>
                      <button
                        onClick={async () => { if (confirm('Delete this file?')) { await deleteFile(f.id); } }}
                        className={`p-1 rounded ${isDark ? 'hover:bg-red-900 text-red-300' : 'hover:bg-red-50 text-red-600'}`}
                        title="Delete"
                      >
                        <Trash2 size={14} />
                      </button>
                    </div>
                  </div>
                ))}
                {uploadingFileIds && uploadingFileIds.length > 0 && (
                  <div className={`flex items-center justify-between px-2 py-2 rounded border border-dashed ${isDark ? 'border-gray-700 text-gray-400' : 'border-gray-300 text-gray-500'}`}>
                    <div className="flex items-center gap-2">
                      <Loader2 className="animate-spin" size={14} />
                      <span className="text-sm">Uploading {uploadingFileIds.length} file{uploadingFileIds.length > 1 ? 's' : ''}…</span>
                    </div>
                  </div>
                )}
              </div>
            )}
          </div>
        )}
        {activeTab === 'archive' && (
          <div className="space-y-2">
            {archivedNodes.length === 0 ? (
              <div className="flex flex-col items-center justify-center h-40 opacity-50">
                <Archive size={32} className="mb-2" />
                <p className="text-xs text-center">
                  No archived nodes.<br/>
                  Right-click a node → "Add to Archive"
                </p>
              </div>
            ) : (
              <>
                <p className={`text-xs mb-2 ${isDark ? 'text-gray-500' : 'text-gray-400'}`}>Drag to canvas to create a copy</p>
                {archivedNodes.map((archived) => (
                  <div
                    key={archived.id}
                    draggable
                    onDragStart={(e) => handleDragStart(e, archived.id)}
                    className={`p-2 border rounded-md cursor-grab transition-colors group ${
                      isDark 
                        ? 'bg-gray-700 border-gray-600 hover:bg-gray-600 hover:border-gray-500' 
                        : 'bg-gray-50 border-gray-200 hover:bg-gray-100 hover:border-gray-300'
                    }`}
                    title={`Label: ${archived.label}\nModel: ${archived.model}\nSystem: ${archived.systemPrompt || '(empty)'}\nUser: ${(archived.userPrompt || '').slice(0,80)}${(archived.userPrompt || '').length>80?'…':''}\nResp: ${(archived.response || '').slice(0,80)}${(archived.response || '').length>80?'…':''}`}
                  >
                    <div className="flex items-center justify-between">
                      <div className="flex items-center gap-2">
                        <MessageSquare size={14} className={isDark ? 'text-gray-400' : 'text-gray-500'} />
                        <span className={`text-sm font-medium truncate max-w-[140px] ${isDark ? 'text-gray-200' : ''}`}>{archived.label}</span>
                      </div>
                      <button
                        onClick={() => removeFromArchive(archived.id)}
                        className={`opacity-0 group-hover:opacity-100 p-1 rounded transition-all ${
                          isDark ? 'hover:bg-red-900 text-gray-400 hover:text-red-400' : 'hover:bg-red-100 text-gray-400 hover:text-red-500'
                        }`}
                        title="Remove from archive"
                      >
                        <Trash2 size={12} />
                      </button>
                    </div>
                    <div className={`text-[10px] mt-1 ${isDark ? 'text-gray-500' : 'text-gray-400'}`}>{archived.model}</div>
                  </div>
                ))}
              </>
            )}
          </div>
        )}
      </div>

      {/* Context Menu */}
      {contextMenu && (
        <div
          className={`fixed z-50 rounded-md shadow-lg border py-1 text-sm ${isDark ? 'bg-gray-800 border-gray-700 text-gray-200' : 'bg-white border-gray-200 text-gray-700'}`}
          style={{ top: contextMenu.y, left: contextMenu.x }}
          onClick={(e) => e.stopPropagation()}
        >
          {(() => {
            const item = contextMenu.item;
            const targetFolder = item
              ? (item.type === 'folder' ? item.path : item.path.split('/').slice(0, -1).join('/') || '.')
              : '.'; // empty area => root
            const commonNew = (
              <>
                <button className="block w-full text-left px-3 py-1 hover:bg-gray-100 dark:hover:bg-gray-700" onClick={() => { closeContextMenu(); handleCreateFolder(targetFolder); }}>New Folder</button>
                <button className="block w-full text-left px-3 py-1 hover:bg-gray-100 dark:hover:bg-gray-700" onClick={() => { closeContextMenu(); handleNewBlueprint(targetFolder); }}>New Blueprint</button>
                <button className="block w-full text-left px-3 py-1 hover:bg-gray-100 dark:hover:bg-gray-700" onClick={() => { closeContextMenu(); handleUploadClick(); }}>Upload</button>
              </>
            );
            if (!item) {
              return commonNew;
            }
            if (item.type === 'file') {
              return (
                <>
                  {commonNew}
                  <button className="block w-full text-left px-3 py-1 hover:bg-gray-100 dark:hover:bg-gray-700" onClick={() => { closeContextMenu(); handleDownload(item); }}>Download</button>
                  <button className="block w-full text-left px-3 py-1 hover:bg-gray-100 dark:hover:bg-gray-700" onClick={() => { closeContextMenu(); handleRename(item); }}>Rename</button>
                  <button className="block w-full text-left px-3 py-1 text-red-500 hover:bg-red-50 dark:hover:bg-red-900/40" onClick={() => { closeContextMenu(); handleDelete(item); }}>Delete</button>
                </>
              );
            }
            // folder
            return (
              <>
                {commonNew}
                <button className="block w-full text-left px-3 py-1 hover:bg-gray-100 dark:hover:bg-gray-700" onClick={() => { closeContextMenu(); handleRename(item); }}>Rename</button>
                <button className="block w-full text-left px-3 py-1 text-red-500 hover:bg-red-50 dark:hover:bg-red-900/40" onClick={() => { closeContextMenu(); handleDelete(item); }}>Delete</button>
              </>
            );
          })()}
        </div>
      )}
    </div>
  );
};

export default LeftSidebar;

