/**
 * FileTreeSidebar.tsx — S611: file tree persistente nell'editor tab
 *
 * Sostituisce il VFS "cieco" (accessibile solo da More > File System VFS) con
 * una sidebar sempre visibile che mostra la struttura del progetto in real-time.
 *
 * Desktop: sidebar collassabile a sinistra dell'editor (~180px).
 * Mobile (iPhone): drawer a scomparsa dal basso, attivato da un FAB floating.
 *
 * Real-time: si aggiorna automaticamente via onVfsChanged ogni volta che
 * l'agente scrive un file (write_file tool).
 *
 * S615: search input con debounce 250ms — quando attivo mostra lista flat
 * dei file che corrispondono (path match), con highlight del termine trovato.
 */

import { useState, useEffect, useCallback, useRef, memo } from "react";
import { Z_INDEX } from "@/lib/zindex";
import {
  Folder, FolderOpen, FileText, ChevronRight, ChevronDown,
  PanelLeftClose, PanelLeftOpen, X, Search, FilePlus,
} from "lucide-react";
import { vfsAsync, onVfsChanged } from "@/lib/vfsDb";
import type { VFSFile } from "@/lib/vfsDb";
import { useWorkspaceStore } from "@/store/workspaceStore";
import { useUIStore } from "@/store/uiStore";
import { useLongPress } from "@/hooks/useLongPress";                          // S800
import { MobileFileContextSheet } from "@/components/workspace/MobileFileContextSheet"; // S800

// ─── Extension → colour map (same as FileEditor) ─────────────────────────────

const EXT_COLORS: Record<string, string> = {
  ts: "#3178c6", tsx: "#3178c6", js: "#f7df1e", jsx: "#61dafb",
  py: "#3572a5", go: "#00add8", rs: "#dea584", json: "#ffa500",
  md: "#83a598", css: "#563d7c", html: "#e34c26", sh: "#89d051",
  txt: "#888",   toml: "#9c4221", yaml: "#cc3e44", yml: "#cc3e44",
  csv: "#3b82f6", xml: "#84cc16", sql: "#f472b6",
};

function fileColor(name: string): string {
  const ext = name.split(".").pop()?.toLowerCase() ?? "";
  return EXT_COLORS[ext] ?? "#9ca3af";
}

// ─── Tree node types ──────────────────────────────────────────────────────────

interface TreeNode {
  name: string;
  path: string;
  isDir: boolean;
  children: TreeNode[];
  file?: VFSFile;
}

function buildTree(files: VFSFile[]): TreeNode[] {
  const root: TreeNode[] = [];
  const dirMap = new Map<string, TreeNode>();

  const getOrCreateDir = (dirPath: string): TreeNode => {
    if (dirMap.has(dirPath)) return dirMap.get(dirPath)!;
    const parts = dirPath.split("/");
    const name = parts.pop()!;
    const parentPath = parts.join("/");
    const node: TreeNode = { name, path: dirPath, isDir: true, children: [] };
    dirMap.set(dirPath, node);
    if (!parentPath) root.push(node);
    else getOrCreateDir(parentPath).children.push(node);
    return node;
  };

  const sorted = [...files].sort((a, b) => a.path.localeCompare(b.path));
  for (const f of sorted) {
    const parts = f.path.split("/");
    if (parts.length === 1) {
      root.push({ name: f.name, path: f.path, isDir: false, children: [], file: f });
    } else {
      parts.pop();
      getOrCreateDir(parts.join("/")).children.push({
        name: f.name, path: f.path, isDir: false, children: [], file: f,
      });
    }
  }

  const sort = (nodes: TreeNode[]) => {
    nodes.sort((a, b) => {
      if (a.isDir !== b.isDir) return a.isDir ? -1 : 1;
      return a.name.localeCompare(b.name);
    });
    nodes.forEach(n => n.children.length && sort(n.children));
  };
  sort(root);
  return root;
}

// ─── S615: debounce hook ──────────────────────────────────────────────────────

function useDebounce<T>(value: T, ms: number): T {
  const [debounced, setDebounced] = useState(value);
  useEffect(() => {
    const t = setTimeout(() => setDebounced(value), ms);
    return () => clearTimeout(t);
  }, [value, ms]);
  return debounced;
}

// ─── S615: highlight helper ───────────────────────────────────────────────────

function HighlightMatch({ text, query }: { text: string; query: string }) {
  if (!query) return <span>{text}</span>;
  const lc = text.toLowerCase();
  const qi = lc.indexOf(query.toLowerCase());
  if (qi === -1) return <span>{text}</span>;
  return (
    <span>
      {text.slice(0, qi)}
      <mark style={{ background: "rgba(251,191,36,0.30)", color: "#fbbf24", borderRadius: 3, padding: "0 1px" }}>
        {text.slice(qi, qi + query.length)}
      </mark>
      {text.slice(qi + query.length)}
    </span>
  );
}

// ─── S615: flat search results ────────────────────────────────────────────────

function SearchResults({
  files, query, activePath, onSelect, onLongPress,
}: {
  files: VFSFile[];
  query: string;
  activePath: string | null;
  onSelect: (f: VFSFile) => void;
  onLongPress?: (f: VFSFile) => void;
}) {
  const lq = query.toLowerCase();
  const matches = files.filter(f =>
    f.path.toLowerCase().includes(lq) || f.name.toLowerCase().includes(lq),
  );

  if (matches.length === 0) {
    return (
      <p style={{ fontSize: "0.66rem", color: "#3a3a6a", padding: "8px 10px", lineHeight: 1.4 }}>
        Nessun file trovato per "{query}"
      </p>
    );
  }

  return (
    <>
      <p style={{ fontSize: "0.58rem", color: "#3a3a6a", padding: "4px 10px 2px", letterSpacing: "0.05em" }}>
        {matches.length} risultat{matches.length === 1 ? "o" : "i"}
      </p>
      {matches.map(f => {
        const isActive = activePath === f.path;
        return (
          <button
            key={f.path}
            onClick={() => onSelect(f)}
            title={f.path}
            style={{
              display: "flex", alignItems: "center", gap: 4, width: "100%",
              padding: "3px 8px",
              background: isActive ? "rgba(59,130,246,0.15)" : "none",
              border: "none", cursor: "pointer",
              borderRadius: 6, margin: "0 2px",
              color: isActive ? "#93c5fd" : "#8892b0",
              fontSize: "0.70rem", textAlign: "left",
              transition: "background 0.12s",
            }}
            onMouseEnter={e => { if (!isActive) e.currentTarget.style.background = "rgba(255,255,255,0.04)"; }}
            onMouseLeave={e => { if (!isActive) e.currentTarget.style.background = "none"; }}
          >
            <FileText size={11} color={fileColor(f.name)} style={{ flexShrink: 0 }} />
            <span style={{ flex: 1, minWidth: 0, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
              <HighlightMatch text={f.name} query={query} />
            </span>
          </button>
        );
      })}
    </>
  );
}

// ─── TreeRow ─────────────────────────────────────────────────────────────────

function TreeRow({
  node, depth, activePath, onSelect, onLongPress,
}: {
  node: TreeNode;
  depth: number;
  activePath: string | null;
  onSelect: (f: VFSFile) => void;
  /** S800: long-press su file leaf → context sheet mobile */
  onLongPress?: (f: VFSFile) => void;
}) {
  const [expanded, setExpanded] = useState(true);
  const isActive = activePath === node.path;
  const indent = 8 + depth * 12;

  // S800: long-press detection per file (non cartelle)
  const lp = useLongPress({
    onLongPress: () => { if (node.file) onLongPress?.(node.file); },
    enabled: !!onLongPress && !node.isDir,
  });

  if (node.isDir) {
    return (
      <>
        <button
          onClick={() => setExpanded(e => !e)}
          style={{
            display: "flex", alignItems: "center", gap: 4, width: "100%",
            padding: `4px 6px 4px ${indent}px`,
            background: "none", border: "none", cursor: "pointer",
            color: "#8892b0", fontSize: "0.72rem", textAlign: "left",
          }}
        >
          {expanded
            ? <ChevronDown  size={10} color="#f59e0b" />
            : <ChevronRight size={10} color="#f59e0b" />}
          {expanded
            ? <FolderOpen size={12} color="#f59e0b" />
            : <Folder     size={12} color="#f59e0b" />}
          <span style={{ overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", flex: 1, fontWeight: 600 }}>
            {node.name}
          </span>
        </button>
        {expanded && node.children.map(child => (
          <TreeRow key={child.path} node={child} depth={depth + 1}
            activePath={activePath} onSelect={onSelect} onLongPress={onLongPress} />
        ))}
      </>
    );
  }

  return (
    <button
      onClick={() => node.file && onSelect(node.file)}
      title={node.path}
      {...(onLongPress ? lp : {})}
      style={{
        display: "flex", alignItems: "center", gap: 4, width: "100%",
        padding: `3px 6px 3px ${indent}px`,
        background: isActive ? "rgba(59,130,246,0.15)" : "none",
        border: "none", cursor: "pointer",
        borderRadius: 6, margin: "0 2px",
        color: isActive ? "#93c5fd" : "#8892b0",
        fontSize: "0.72rem", textAlign: "left",
        transition: "background 0.12s",
        touchAction: "manipulation",
        WebkitTapHighlightColor: "transparent",
      } as React.CSSProperties}
      onMouseEnter={e => { if (!isActive) e.currentTarget.style.background = "rgba(255,255,255,0.04)"; }}
      onMouseLeave={e => { if (!isActive) e.currentTarget.style.background = "none"; }}
    >
      <FileText size={11} color={fileColor(node.name)} style={{ flexShrink: 0 }} />
      <span style={{ overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", flex: 1 }}>
        {node.name}
      </span>
    </button>
  );
}

// ─── Props ────────────────────────────────────────────────────────────────────

interface FileTreeSidebarProps {
  /** Called when user clicks a file — parent switches tab to editor */
  onRequestOpen: (file: VFSFile) => void;
}

// ─── Desktop sidebar ──────────────────────────────────────────────────────────

export const FileTreeSidebar = memo(function FileTreeSidebar({ onRequestOpen }: FileTreeSidebarProps) {
  const [files, setFiles] = useState<VFSFile[]>([]);
  const [tree,  setTree]  = useState<TreeNode[]>([]);
  // S615: search state
  const [rawQuery, setRawQuery] = useState("");
  const debouncedQuery = useDebounce(rawQuery, 250);
  const searchInputRef = useRef<HTMLInputElement | null>(null);
  // S620: nuovo file inline
  const [newFileMode, setNewFileMode] = useState(false);
  const [newFilePath, setNewFilePath] = useState("");
  const newFileInputRef = useRef<HTMLInputElement | null>(null);

  const openFile     = useWorkspaceStore(s => s.openFile);
  const showFileTree = useUIStore(s => s.showFileTree);
  const toggleFileTree = useUIStore(s => s.toggleFileTree);

  const reload = useCallback(async () => {
    const all = await vfsAsync.list();
    setFiles(all);
    setTree(buildTree(all));
  }, []);

  useEffect(() => {
    reload();
    return onVfsChanged(reload);
  }, [reload]);

  // S723-GAP3.2: ascolta agent:vfs-update emesso da agentSSE quando il backend scrive file.
  // reload() rilegge vfsAsync.list() — il workspace mostra file creati dall'agente in real-time.
  useEffect(() => {
    const _h = () => { void reload(); };
    window.addEventListener("agent:vfs-update", _h);
    return () => window.removeEventListener("agent:vfs-update", _h);
  }, [reload]);

  // S615: Ctrl+F / Cmd+F focalizza la search input quando la sidebar è aperta
  // S619: Ctrl+B / Cmd+B toggle FileTreeSidebar (VS Code standard)
  useEffect(() => {
    const handler = (e: KeyboardEvent) => {
      if (e.ctrlKey || e.metaKey) {
        if (e.key === "b") {
          e.preventDefault();
          toggleFileTree();
          return;
        }
        if (e.key === "f" && showFileTree && searchInputRef.current) {
          const active = document.activeElement;
          if (active?.tagName === "TEXTAREA" || (active as HTMLInputElement)?.dataset?.codemirror) return;
          e.preventDefault();
          searchInputRef.current.focus();
        }
      }
    };
    window.addEventListener("keydown", handler);
    return () => window.removeEventListener("keydown", handler);
  }, [showFileTree, toggleFileTree]);

  const clearSearch = () => { setRawQuery(""); searchInputRef.current?.focus(); };
  const isSearching = debouncedQuery.trim().length > 0;

  // S620: auto-focus sull'input "nuovo file" quando si entra in modalità di creazione
  useEffect(() => {
    if (newFileMode) {
      setTimeout(() => newFileInputRef.current?.focus(), 60);
    }
  }, [newFileMode]);

  // S620: crea il file nel VFS e aprilo nell'editor
  const handleCreateFile = useCallback(async () => {
    const p = newFilePath.trim();
    if (!p) { setNewFileMode(false); setNewFilePath(""); return; }
    const normPath = p.startsWith("/") ? p : "/" + p;
    const exists = await vfsAsync.exists(normPath);
    if (!exists) {
      await vfsAsync.write(normPath, "", "text/plain");
    }
    setNewFileMode(false);
    setNewFilePath("");
    const _vfsFile = files.find(f => f.path === normPath) ?? {
      name: normPath.split('/').pop() ?? normPath,
      path: normPath, content: '', size: 0,
      type: 'text/plain', createdAt: Date.now(), updatedAt: Date.now(),
    };
    onRequestOpen(_vfsFile);
  }, [newFilePath, onRequestOpen]);

  return (
    <div style={{
      width: showFileTree ? 180 : 28,
      minWidth: showFileTree ? 180 : 28,
      borderRight: "1px solid rgba(99,102,241,0.14)",
      background: "rgba(4,5,16,0.96)",
      display: "flex", flexDirection: "column",
      overflow: "hidden",
      transition: "width 0.22s cubic-bezier(0.4,0,0.2,1), min-width 0.22s cubic-bezier(0.4,0,0.2,1)",
      flexShrink: 0,
    }}>
      {/* Header */}
      <div style={{
        display: "flex", alignItems: "center", justifyContent: "space-between",
        padding: "6px 6px 6px 8px", borderBottom: "1px solid rgba(99,102,241,0.10)",
        flexShrink: 0, minHeight: 32,
      }}>
        {showFileTree && (
          <span style={{ fontSize: "0.62rem", fontWeight: 700, color: "#4a4a78",
            textTransform: "uppercase", letterSpacing: "0.08em", whiteSpace: "nowrap", overflow: "hidden" }}>
            FILE
            {files.length > 0 && (
              <span style={{ marginLeft: 5, color: "#3b82f6", fontWeight: 600 }}>
                {files.length}
              </span>
            )}
          </span>
        )}
        {/* S620: pulsanti header (FilePlus + toggle) */}
        <div style={{ display: "flex", alignItems: "center", gap: 1, marginLeft: "auto" }}>
          {showFileTree && (
            <button
              onClick={() => { setNewFilePath(""); setNewFileMode(true); }}
              title="Nuovo file (S620)"
              aria-label="Crea nuovo file"
              style={{
                background: "none", border: "none", cursor: "pointer",
                color: "#4a4a78", padding: 3, borderRadius: 6, display: "flex",
                transition: "color 0.15s",
              }}
              onMouseEnter={e => { e.currentTarget.style.color = "#34d399"; }}
              onMouseLeave={e => { e.currentTarget.style.color = "#4a4a78"; }}
            >
              <FilePlus size={13} />
            </button>
          )}
          <button
            onClick={toggleFileTree}
            title={showFileTree ? "Chiudi file tree (Ctrl+B)" : "Apri file tree (Ctrl+B)"}
            style={{
              background: "none", border: "none", cursor: "pointer",
              color: "#4a4a78", padding: 3, borderRadius: 6, display: "flex",
              transition: "color 0.15s",
            }}
            onMouseEnter={e => { e.currentTarget.style.color = "#818cf8"; }}
            onMouseLeave={e => { e.currentTarget.style.color = "#4a4a78"; }}
          >
            {showFileTree
              ? <PanelLeftClose size={14} />
              : <PanelLeftOpen  size={14} />}
          </button>
        </div>
      </div>

      {/* S615: search input — solo visibile quando la sidebar è espansa */}
      {showFileTree && (
        <div style={{
          padding: "5px 6px",
          borderBottom: "1px solid rgba(99,102,241,0.08)",
          flexShrink: 0,
        }}>
          <div style={{
            display: "flex", alignItems: "center", gap: 4,
            background: "rgba(255,255,255,0.04)",
            border: `1px solid ${isSearching ? "rgba(129,140,248,0.40)" : "rgba(99,102,241,0.15)"}`,
            borderRadius: 8, padding: "3px 6px",
            transition: "border-color 0.15s",
          }}>
            <Search size={11} color={isSearching ? "#818cf8" : "#3a3a6a"} style={{ flexShrink: 0 }} />
            <input
              ref={searchInputRef}
              value={rawQuery}
              onChange={e => setRawQuery(e.target.value)}
              onKeyDown={e => { if (e.key === "Escape") clearSearch(); }}
              placeholder="Cerca file…"
              aria-label="Cerca file nel VFS"
              style={{
                flex: 1, background: "none", border: "none", outline: "none",
                color: "#c7d2fe", fontSize: "0.68rem",
                caretColor: "#818cf8",
              }}
            />
            {rawQuery && (
              <button
                onClick={clearSearch}
                aria-label="Cancella ricerca"
                style={{
                  background: "none", border: "none", cursor: "pointer",
                  color: "#4a4a78", padding: 0, display: "flex",
                  transition: "color 0.15s",
                }}
                onMouseEnter={e => { e.currentTarget.style.color = "#ef4444"; }}
                onMouseLeave={e => { e.currentTarget.style.color = "#4a4a78"; }}
              >
                <X size={10} />
              </button>
            )}
          </div>
        </div>
      )}

      {/* S620: input inline "nuovo file" — visibile solo in newFileMode */}
      {showFileTree && newFileMode && (
        <div style={{
          padding: "5px 6px",
          borderBottom: "1px solid rgba(52,211,153,0.20)",
          flexShrink: 0,
          background: "rgba(52,211,153,0.04)",
        }}>
          <div style={{
            display: "flex", alignItems: "center", gap: 4,
            border: "1px solid rgba(52,211,153,0.50)",
            borderRadius: 8, padding: "3px 6px",
          }}>
            <FilePlus size={11} color="#34d399" style={{ flexShrink: 0 }} />
            <input
              ref={newFileInputRef}
              value={newFilePath}
              onChange={e => setNewFilePath(e.target.value)}
              onKeyDown={e => {
                if (e.key === "Enter") { e.preventDefault(); handleCreateFile(); }
                if (e.key === "Escape") { setNewFileMode(false); setNewFilePath(""); }
              }}
              placeholder="src/nuovo.ts…"
              aria-label="Path del nuovo file"
              style={{
                flex: 1, background: "none", border: "none", outline: "none",
                color: "#6ee7b7", fontSize: "0.68rem",
                caretColor: "#34d399",
              }}
            />
            <button
              onClick={() => { setNewFileMode(false); setNewFilePath(""); }}
              aria-label="Annulla nuovo file"
              style={{
                background: "none", border: "none", cursor: "pointer",
                color: "#4a4a78", padding: 0, display: "flex",
                transition: "color 0.15s",
              }}
              onMouseEnter={e => { e.currentTarget.style.color = "#ef4444"; }}
              onMouseLeave={e => { e.currentTarget.style.color = "#4a4a78"; }}
            >
              <X size={10} />
            </button>
          </div>
        </div>
      )}

      {/* Tree / Search results */}
      {showFileTree && (
        <div style={{ flex: 1, overflow: "auto", padding: "4px 0" }}>
          {isSearching ? (
            /* S615: risultati flat con highlight */
            <SearchResults
              files={files}
              query={debouncedQuery.trim()}
              activePath={openFile?.path ?? null}
              onSelect={onRequestOpen}
            />
          ) : tree.length === 0 ? (
            <p style={{ fontSize: "0.66rem", color: "#3a3a6a", padding: "8px 12px", lineHeight: 1.4 }}>
              Nessun file nel VFS.{"\n"}L'agente creerà i file qui.
            </p>
          ) : (
            tree.map(node => (
              <TreeRow
                key={node.path}
                node={node}
                depth={0}
                activePath={openFile?.path ?? null}
                onSelect={onRequestOpen}
              />
            ))
          )}
        </div>
      )}
    </div>
  );
});

// ─── Mobile drawer (bottom sheet) ────────────────────────────────────────────

export function MobileFileTreeDrawer({ onRequestOpen }: FileTreeSidebarProps) {
  const [open,        setOpen]       = useState(false);
  const [files,       setFiles]      = useState<VFSFile[]>([]);
  const [tree,        setTree]       = useState<TreeNode[]>([]);
  const [contextFile, setContextFile] = useState<VFSFile | null>(null); // S800: long-press context
  // S615: search nel drawer mobile
  const [rawQuery, setRawQuery] = useState("");
  const debouncedQuery = useDebounce(rawQuery, 250);
  const openFile = useWorkspaceStore(s => s.openFile);

  const reload = useCallback(async () => {
    const all = await vfsAsync.list();
    setFiles(all);
    setTree(buildTree(all));
  }, []);

  useEffect(() => {
    reload();
    return onVfsChanged(reload);
  }, [reload]);

  const isSearching = debouncedQuery.trim().length > 0;

  return (
    <>
      {/* FAB button */}
      <button
        onClick={() => setOpen(v => !v)}
        title="File tree"
        style={{
          position: "fixed", bottom: 72, right: 14,
          zIndex: Z_INDEX.MODAL_BACKDROP,
          width: 38, height: 38, borderRadius: "50%",
          background: "rgba(99,102,241,0.85)",
          border: "1px solid rgba(129,140,248,0.4)",
          boxShadow: "0 4px 16px rgba(99,102,241,0.35)",
          cursor: "pointer", color: "#fff",
          display: "flex", alignItems: "center", justifyContent: "center",
          transition: "transform 0.18s, background 0.18s",
        }}
        onMouseEnter={e => { e.currentTarget.style.transform = "scale(1.08)"; }}
        onMouseLeave={e => { e.currentTarget.style.transform = "scale(1)"; }}
      >
        <Folder size={16} />
        {files.length > 0 && (
          <span style={{
            position: "absolute", top: -4, right: -4,
            background: "#3b82f6", color: "#fff",
            fontSize: "0.55rem", fontWeight: 700,
            borderRadius: "50%", width: 16, height: 16,
            display: "flex", alignItems: "center", justifyContent: "center",
          }}>
            {files.length > 9 ? "9+" : files.length}
          </span>
        )}
      </button>

      {/* Backdrop */}
      {open && (
        <div
          onClick={() => setOpen(false)}
          style={{
            position: "fixed", inset: 0, zIndex: Z_INDEX.MODAL,
            background: "rgba(0,0,0,0.45)",
          }}
        />
      )}

      {/* Bottom sheet */}
      <div style={{
        position: "fixed", left: 0, right: 0, bottom: 0,
        zIndex: Z_INDEX.DRAWER_CONTENT,
        height: "65vh",
        background: "rgba(8,9,24,0.98)",
        borderTop: "1px solid rgba(99,102,241,0.3)",
        borderRadius: "18px 18px 0 0",
        display: "flex", flexDirection: "column",
        overflow: "hidden",
        transform: open ? "translateY(0)" : "translateY(100%)",
        transition: "transform 0.28s cubic-bezier(0.4,0,0.2,1)",
        boxShadow: "0 -12px 40px rgba(0,0,0,0.5)",
        paddingBottom: "max(8px, env(safe-area-inset-bottom, 0px))",
      }}>
        {/* Handle + header */}
        <div style={{
          display: "flex", alignItems: "center", justifyContent: "space-between",
          padding: "10px 16px 8px",
          borderBottom: "1px solid rgba(99,102,241,0.12)",
          flexShrink: 0,
        }}>
          <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
            <div style={{
              width: 36, height: 4, borderRadius: 3,
              background: "rgba(255,255,255,0.15)",
              position: "absolute", top: 6, left: "50%", transform: "translateX(-50%)",
            }} />
            <Folder size={14} color="#818cf8" />
            <span style={{ fontSize: "0.78rem", fontWeight: 600, color: "#c7d2fe" }}>
              File VFS
            </span>
            <span style={{ fontSize: "0.68rem", color: "#4a4a78" }}>
              ({files.length} file)
            </span>
          </div>
          <button
            onClick={() => setOpen(false)}
            style={{
              background: "none", border: "none", cursor: "pointer",
              color: "#4a4a78", padding: 4, borderRadius: 4, display: "flex",
            }}
          >
            <X size={16} />
          </button>
        </div>

        {/* S615: search input mobile */}
        <div style={{ padding: "8px 12px 6px", flexShrink: 0 }}>
          <div style={{
            display: "flex", alignItems: "center", gap: 6,
            background: "rgba(255,255,255,0.05)",
            border: `1px solid ${isSearching ? "rgba(129,140,248,0.4)" : "rgba(99,102,241,0.18)"}`,
            borderRadius: 8, padding: "6px 10px",
            transition: "border-color 0.15s",
          }}>
            <Search size={14} color={isSearching ? "#818cf8" : "#3a3a6a"} />
            <input
              value={rawQuery}
              onChange={e => setRawQuery(e.target.value)}
              onKeyDown={e => { if (e.key === "Escape") setRawQuery(""); }}
              placeholder="Cerca file…"
              autoComplete="off"
              style={{
                flex: 1, background: "none", border: "none", outline: "none",
                color: "#c7d2fe", fontSize: "0.82rem",
                caretColor: "#818cf8",
              }}
            />
            {rawQuery && (
              <button
                onClick={() => setRawQuery("")}
                style={{ background: "none", border: "none", cursor: "pointer", color: "#4a4a78", padding: 0 }}
              >
                <X size={13} />
              </button>
            )}
          </div>
        </div>

        {/* Tree / Search results */}
        <div style={{ flex: 1, overflow: "auto", padding: "4px 0" }}>
          {isSearching ? (
            <SearchResults
              files={files}
              query={debouncedQuery.trim()}
              activePath={openFile?.path ?? null}
              onSelect={(f) => { onRequestOpen(f); setOpen(false); setRawQuery(""); }}
              onLongPress={(f) => { setContextFile(f); }}
            />
          ) : tree.length === 0 ? (
            <p style={{ fontSize: "0.72rem", color: "#3a3a6a", padding: "12px 16px", lineHeight: 1.5 }}>
              Nessun file nel VFS.{"\n"}L'agente creerà i file qui.
            </p>
          ) : (
            tree.map(node => (
              <TreeRow
                key={node.path}
                node={node}
                depth={0}
                activePath={openFile?.path ?? null}
                onSelect={(f) => { onRequestOpen(f); setOpen(false); }}
                onLongPress={(f) => { setContextFile(f); }}
              />
            ))
          )}
        </div>
      </div>
      {/* S800: context sheet long-press */}
      <MobileFileContextSheet
        file={contextFile}
        onClose={() => setContextFile(null)}
        onFileChanged={(oldPath, newPath) => {
          // Se il file aperto era quello rinominato/eliminato, gestiscilo
          if (openFile?.path === oldPath) {
            onRequestOpen({ ...(openFile!), path: newPath ?? "", name: newPath?.split("/").pop() ?? "" } as VFSFile);
          }
          setContextFile(null);
        }}
      />
    </>
  );
}
