import { useState, useEffect, useRef, useCallback, memo, lazy, Suspense } from "react";
import { Z_INDEX } from "@/lib/zindex";
import {
  Save, FileText, Folder, FolderOpen, Plus, Upload, Download,
  Trash2, Play, Loader, RefreshCw, X, ChevronRight, ChevronDown,
} from "lucide-react";
import { vfsAsync, onVfsChanged }  from "@/lib/vfsDb";
import { useLiveDiagnostics }         from "@/hooks/useLiveDiagnostics"; // GAP-3
import { updateFileState } from "@/lib/worldModel"; // X8
import type { VFSFile }     from "@/lib/vfsDb";
// import type { VfsTsError } from "@/lib/vfsTsChecker"; // GAP-3 // removed: unused
import { canRun } from "@/lib/codeRunner";
import DiffBlock from "./DiffBlock";
import CodeMirrorEditor from "./CodeMirrorEditor";
import { useWorkspaceStore } from "@/store/workspaceStore";  // S611
import { useUIStore } from "@/store/uiStore";                // S623: nasconde sidebar interna se showFileTree è aperta
import { useIsMobile } from "@/hooks/use-mobile";            // S800: mobile-specific UX
import { useMobileKeyboardAware } from "@/hooks/useMobileKeyboardAware"; // S800: keyboard height
import { useAutoSave } from "@/hooks/useAutoSave";           // S800: auto-save su iOS
// S800: componenti mobile — lazy-loaded per non impattare bundle desktop
const MobileEditorFindBar  = lazy(() => import("@/components/workspace/MobileEditorFindBar"));
const MobileEditorStatusBar = lazy(() => import("@/components/workspace/MobileEditorStatusBar"));

// ─── Types ────────────────────────────────────────────────────────────────────

interface FileEditorProps {
  onRunRequest?: (code: string, filename: string) => void;
  onFileOpen?: (file: VFSFile) => void;
}

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

// ─── Extension colors ─────────────────────────────────────────────────────────

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 FileIcon({ name, size = 13 }: { name: string; size?: number }) {
  const ext = name.split(".").pop()?.toLowerCase() ?? "";
  const color = EXT_COLORS[ext] || "var(--text-muted)";
  return <FileText size={size} color={color} />;
}

// ─── Build tree from flat VFS list ────────────────────────────────────────────

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 file of sorted) {
    const parts = file.path.split("/");
    if (parts.length === 1) {
      root.push({ name: file.name, path: file.path, isDir: false, children: [], file });
    } else {
      parts.pop();
      const dirPath = parts.join("/");
      const dir = getOrCreateDir(dirPath);
      dir.children.push({ name: file.name, path: file.path, isDir: false, children: [], file });
    }
  }

  const sortNodes = (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 && sortNodes(n.children));
  };
  sortNodes(root);
  return root;
}

// ─── Tree node component ─────────────────────────────────────────────────────

function TreeNodeRow({
  node, depth, activeFile, onOpen, onDelete,
}: {
  node: TreeNode;
  depth: number;
  activeFile: string | null;
  onOpen: (file: VFSFile) => void;
  onDelete: (path: string) => void;
}) {
  const [expanded, setExpanded] = useState(true);
  const isActive = activeFile === node.path;

  if (node.isDir) {
    return (
      <>
        <button
          onClick={() => setExpanded(e => !e)}
          style={{
            display: "flex", alignItems: "center", gap: 5, width: "100%",
            padding: `3px 8px 3px ${8 + depth * 14}px`,
            background: "none", border: "none", cursor: "pointer",
            color: "var(--text-muted)", fontSize: "0.74rem", textAlign: "left",
          }}
        >
          {expanded
            ? <ChevronDown size={10} color="#f59e0b" />
            : <ChevronRight size={10} color="#f59e0b" />}
          {expanded
            ? <FolderOpen size={13} color="#f59e0b" />
            : <Folder size={13} color="#f59e0b" />}
          <span style={{ overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", flex: 1 }}>
            {node.name}
          </span>
        </button>
        {expanded && node.children.map(child => (
          <TreeNodeRow
            key={child.path} node={child} depth={depth + 1}
            activeFile={activeFile} onOpen={onOpen} onDelete={onDelete}
          />
        ))}
      </>
    );
  }

  return (
    <div
      style={{
        display: "flex", alignItems: "center",
        background: isActive ? "rgba(59,130,246,0.12)" : "none",
        borderRadius: 4, margin: "0 4px",
      }}
    >
      <button
        onClick={() => node.file && onOpen(node.file)}
        style={{
          display: "flex", alignItems: "center", gap: 5, flex: 1,
          padding: `3px 4px 3px ${8 + depth * 14}px`,
          background: "none", border: "none", cursor: "pointer",
          color: isActive ? "var(--text)" : "var(--text-muted)",
          fontSize: "0.74rem", textAlign: "left",
        }}
      >
        <FileIcon name={node.name} />
        <span style={{ overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", flex: 1 }}>
          {node.name}
        </span>
      </button>
      <button
        onClick={() => onDelete(node.path)}
        title="Elimina file"
        style={{
          background: "none", border: "none", cursor: "pointer",
          color: "var(--text-muted)", padding: "2px 6px 2px 2px",
          opacity: 0.4, flexShrink: 0, transition: "opacity 0.15s",
        }}
        onMouseEnter={e => { e.currentTarget.style.opacity = "1"; e.currentTarget.style.color = "#f87171"; }}
        onMouseLeave={e => { e.currentTarget.style.opacity = "0.4"; e.currentTarget.style.color = "var(--text-muted)"; }}
      >
        <Trash2 size={10} />
      </button>
    </div>
  );
}

// ─── Main component ───────────────────────────────────────────────────────────

const FileEditor = memo(function FileEditor({ onRunRequest, onFileOpen }: FileEditorProps) {
  const [files, setFiles] = useState<VFSFile[]>([]);
  const [tree, setTree] = useState<TreeNode[]>([]);
  const [openFile, setOpenFile] = useState<VFSFile | null>(null);
  const [editorContent, setEditorContent] = useState("");
  const [saving, setSaving] = useState(false);
  const [saveMsg, setSaveMsg] = useState("");
  const [showDiff, setShowDiff] = useState(false);
  const [isDragOver, setIsDragOver] = useState(false);
  const [newFileName, setNewFileName] = useState("");
  const [showNewFile, setShowNewFile] = useState(false);
  const fileInputRef      = useRef<HTMLInputElement>(null);
  const emptyInputRef     = useRef<HTMLInputElement>(null);

  const isText = (f: VFSFile) =>
    !f.opfs &&
    !f.type.startsWith("image/") &&
    !f.type.startsWith("video/") &&
    !f.type.startsWith("audio/") &&
    f.type !== "application/pdf";

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

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

  // S623: nasconde sidebar interna quando la sidebar globale FileTreeSidebar è aperta (evita doppio albero)
  const showFileTree = useUIStore(s => s.showFileTree);

  // S611: apre un file richiesto da FileTreeSidebar (via workspaceStore.requestOpenPath)
  const requestOpenPath    = useWorkspaceStore(s => s.requestOpenPath);
  const setRequestOpenPath = useWorkspaceStore(s => s.setRequestOpenPath);
  useEffect(() => {
    if (!requestOpenPath) return;
    const target = files.find(f => f.path === requestOpenPath);
    if (target) {
      void openVfsFile(target);
    }
    setRequestOpenPath(null);
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [requestOpenPath, files]);

  const openVfsFile = async (file: VFSFile) => {
    const content = await vfsAsync.read(file.path) ?? file.content ?? "";
    const loaded: VFSFile = { ...file, content };
    setOpenFile(loaded);
    setEditorContent(content);
    setShowDiff(false);
    onFileOpen?.(loaded);
  };

  const save = async () => {
    if (!openFile) return;
    setSaving(true);
    setSaveMsg("");
    try {
      await vfsAsync.write(openFile.path, editorContent, openFile.type || "text/plain");
      setSaveMsg("Salvato!");
      setOpenFile(f => f ? { ...f, content: editorContent } : f);
      updateFileState(openFile.path, { lastModified: Date.now(), health: "unknown" }); // X8: sync WorldModel
    } catch (e) {
      setSaveMsg(`Errore: ${(e as Error).message}`);
    } finally {
      setSaving(false);
      setTimeout(() => setSaveMsg(""), 2500);
    }
  };

  const deleteFile = async (path: string) => {
    if (!confirm(`Eliminare "${path}"?`)) return;
    await vfsAsync.delete(path);
    if (openFile?.path === path) {
      setOpenFile(null);
      setEditorContent("");
    }
  };

  const downloadFile = () => {
    if (!openFile) return;
    const blob = new Blob([editorContent], { type: openFile.type || "text/plain" });
    const url = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = url;
    a.download = openFile.name;
    a.click();
    URL.revokeObjectURL(url);
  };

  const uploadFiles = async (incoming: FileList | File[]) => {
    const list = Array.from(incoming);
    for (const f of list) {
      const textLike =
        f.type.startsWith("text/") ||
        f.type === "application/json" ||
        /\.(ts|tsx|js|jsx|py|go|rs|md|json|yaml|yml|toml|csv|sql|sh|txt|html|css|xml|env|ini|log|conf|cfg|gitignore)$/i.test(f.name);
      if (!textLike) {
        setSaveMsg(`"${f.name}" non è un file di testo`);
        setTimeout(() => setSaveMsg(""), 2500);
        continue;
      }
      const text = await f.text();
      await vfsAsync.write(f.name, text, f.type || "text/plain");
    }
  };

  const createNewFile = async () => {
    const name = newFileName.trim();
    if (!name) return;
    await vfsAsync.write(name, "", "text/plain");
    setNewFileName("");
    setShowNewFile(false);
    await reload();
    const all = await vfsAsync.list();
    const created = all.find(f => f.path === name || f.name === name);
    if (created) openVfsFile(created);
  };

  const handleDrop = async (e: React.DragEvent) => {
    e.preventDefault();
    setIsDragOver(false);
    if (e.dataTransfer.files.length > 0) await uploadFiles(e.dataTransfer.files);
  };

  const isDirty = openFile && editorContent !== openFile.content;

  // S800: mobile-specific state
  const isMobile = useIsMobile();
  const { keyboardHeight, isKeyboardOpen } = useMobileKeyboardAware();
  const [fontSize,    setFontSize]    = useState(13);        // font size controllato da status bar
  const [cursorLine,  setCursorLine]  = useState(1);         // posizione cursore per status bar
  const [cursorCol,   setCursorCol]   = useState(1);
  const [showFindBar, setShowFindBar] = useState(false);     // find/replace bar mobile
  const [isFullscreen, setIsFullscreen] = useState(false);   // full-screen mode mobile
  const scrollToOffsetRef = useRef<((offset: number) => void) | null>(null);

  // S800: auto-save — critico su iOS (app può essere killata in background)
  // _autoSaveRef mantiene sempre l'ultimo save() (che chiude su openFile/editorContent aggiornati)
  const _autoSaveRef = useRef<() => Promise<void>>(async () => {});
  _autoSaveRef.current = save; // assegnazione sincrona nel render — sempre aggiornata
  const stableSave = useCallback(async () => { await _autoSaveRef.current(); }, []);
  useAutoSave({ isDirty: !!isDirty, onSave: stableSave, enabled: isMobile });

  const handleFontSize = useCallback((delta: number) => {
    setFontSize(prev => Math.max(10, Math.min(24, prev + delta)));
  }, []);

  const handleFindNavigate = useCallback((offset: number) => {
    scrollToOffsetRef.current?.(offset);
  }, []);

  const handleReplace = useCallback((offset: number, matchLen: number, replacement: string) => {
    const before = editorContent.slice(0, offset);
    const after  = editorContent.slice(offset + matchLen);
    setEditorContent(before + replacement + after);
  }, [editorContent]);

  const handleReplaceAll = useCallback((query: string, replacement: string) => {
    setEditorContent(editorContent.split(query).join(replacement));
  }, [editorContent]);
  const canRunFile = openFile ? canRun(openFile.path) : false;

  // GAP-3: live TS diagnostics — debounced 800ms, solo file .ts/.tsx
  const { errors: tsErrors, isChecking: isTsChecking } = useLiveDiagnostics(openFile?.path ?? null);
  const tsErrCount  = tsErrors.filter(e => e.sev === "error").length;
  const tsWarnCount = tsErrors.filter(e => e.sev === "warn").length;

  function buildSimpleDiff(): string {
    if (!openFile || editorContent === openFile.content) return "";
    const aLines = openFile.content.split("\n").slice(0, 300);
    const bLines = editorContent.split("\n").slice(0, 300);
    return [
      `--- a/${openFile.path}`,
      `+++ b/${openFile.path}`,
      `@@ -1,${aLines.length} +1,${bLines.length} @@`,
      ...aLines.map(l => `-${l}`),
      ...bLines.map(l => `+${l}`),
    ].join("\n");
  }

  return (
    <div
      style={{ display: "flex", height: "100%", overflow: "hidden", position: "relative" }}
      onDragOver={e => { e.preventDefault(); setIsDragOver(true); }}
      onDragLeave={e => { if (!e.currentTarget.contains(e.relatedTarget as Node)) setIsDragOver(false); }}
      onDrop={handleDrop}
    >
      {/* Drag overlay */}
      {isDragOver && (
        <div style={{
          position: "absolute", inset: 0, zIndex: Z_INDEX.SIDEBAR,
          background: "rgba(59,130,246,0.1)",
          border: "2px dashed rgba(59,130,246,0.5)",
          display: "flex", alignItems: "center", justifyContent: "center",
          borderRadius: 8, pointerEvents: "none",
        }}>
          <div style={{ color: "#60a5fa", fontSize: "1rem", fontWeight: 600 }}>
            Rilascia i file qui per caricarli
          </div>
        </div>
      )}

      {/* ─── Sidebar interna — S623: nascosta quando showFileTree (global) è aperta ─── */}
      {!showFileTree && <div style={{
        width: 200, flexShrink: 0, borderRight: "1px solid var(--border)",
        overflowY: "auto", background: "var(--bg2)",
        display: "flex", flexDirection: "column",
      }}>
        {/* Header */}
        <div style={{
          display: "flex", alignItems: "center", gap: 4,
          padding: "8px 8px 6px", flexShrink: 0,
          borderBottom: "1px solid var(--border)",
        }}>
          <span style={{
            fontSize: "0.66rem", fontWeight: 700,
            color: "var(--text-muted)", textTransform: "uppercase",
            letterSpacing: "0.07em", flex: 1,
          }}>
            File ({files.length})
          </span>
          <button
            onClick={() => setShowNewFile(s => !s)}
            title="Nuovo file"
            style={{ background: "none", border: "none", cursor: "pointer", color: "var(--text-muted)", padding: 2 }}
          >
            <Plus size={13} />
          </button>
          <button
            onClick={() => fileInputRef.current?.click()}
            title="Carica file dal computer"
            style={{ background: "none", border: "none", cursor: "pointer", color: "var(--text-muted)", padding: 2 }}
          >
            <Upload size={13} />
          </button>
          <button
            onClick={reload}
            title="Aggiorna lista"
            style={{ background: "none", border: "none", cursor: "pointer", color: "var(--text-muted)", padding: 2 }}
          >
            <RefreshCw size={11} />
          </button>
        </div>

        {/* New file input */}
        {showNewFile && (
          <div style={{ padding: "6px 8px", borderBottom: "1px solid var(--border)", flexShrink: 0 }}>
            <input
              autoFocus
              value={newFileName}
              onChange={e => setNewFileName(e.target.value)}
              onKeyDown={e => {
                if (e.key === "Enter") createNewFile();
                if (e.key === "Escape") { setShowNewFile(false); setNewFileName(""); }
              }}
              placeholder="es. script.py"
              style={{
                width: "100%", padding: "4px 6px", fontSize: "0.72rem",
                background: "var(--bg3)", border: "1px solid var(--border)",
                borderRadius: 5, color: "var(--text)", outline: "none",
                boxSizing: "border-box",
              }}
            />
          </div>
        )}

        {/* Hidden file inputs */}
        <input
          ref={fileInputRef}
          type="file"
          multiple
          style={{ display: "none" }}
          onChange={async e => {
            if (e.target.files) await uploadFiles(e.target.files);
            e.target.value = "";
          }}
        />

        {/* File tree */}
        <div style={{ flex: 1, overflowY: "auto", paddingTop: 4 }}>
          {tree.length === 0 ? (
            <div style={{
              padding: "1.5rem 0.75rem", textAlign: "center",
              color: "var(--text-muted)", fontSize: "0.72rem",
            }}>
              <Upload size={20} style={{ opacity: 0.25, marginBottom: 6 }} />
              <div style={{ fontWeight: 600 }}>Nessun file</div>
              <div style={{ opacity: 0.6, marginTop: 3 }}>
                Carica o crea un file per iniziare
              </div>
            </div>
          ) : (
            tree.map(node => (
              <TreeNodeRow
                key={node.path}
                node={node}
                depth={0}
                activeFile={openFile?.path ?? null}
                onOpen={openVfsFile}
                onDelete={deleteFile}
              />
            ))
          )}
        </div>

        {/* Drop hint */}
        <div style={{
          padding: "6px 10px", fontSize: "0.61rem",
          color: "var(--text-muted)", opacity: 0.45,
          textAlign: "center", flexShrink: 0,
          borderTop: "1px solid var(--border)",
        }}>
          Trascina file per caricarli
        </div>
      </div>}
      {/* S623: fine sidebar interna condizionale (!showFileTree) */}

      {/* ─── Editor area ─────────────────────────────────────────────── */}
      <div style={{ flex: 1, display: "flex", flexDirection: "column", overflow: "hidden" }}>
        {openFile ? (
          <>
            {/* Toolbar */}
            <div style={{
              display: "flex", alignItems: "center", gap: 6,
              padding: "6px 10px", borderBottom: "1px solid var(--border)",
              background: "var(--bg2)", flexShrink: 0, flexWrap: "wrap",
            }}>
              <div style={{ display: "flex", alignItems: "center", gap: 5, flex: 1, minWidth: 0 }}>
                <FileIcon name={openFile.name} size={12} />
                <span style={{
                  fontSize: "0.77rem", color: "var(--text)",
                  fontFamily: "ui-monospace, monospace",
                  overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap",
                }}>
                  {openFile.path}
                </span>
                {isDirty && <span style={{ color: "#fbbf24", fontSize: "0.85rem" }}>●</span>}
                {/* GAP-3: TS badge */}
                {isTsChecking && (
                  <span style={{ fontSize: "0.60rem", color: "#6366f1", fontFamily: "ui-monospace,monospace", opacity: 0.8 }}>TS…</span>
                )}
                {!isTsChecking && tsErrCount > 0 && (
                  <span style={{
                    fontSize: "0.60rem", fontWeight: 700, color: "#f87171",
                    fontFamily: "ui-monospace,monospace",
                    background: "rgba(248,113,113,0.10)", padding: "1px 5px",
                    borderRadius: 4, border: "1px solid rgba(248,113,113,0.25)",
                  }}>{tsErrCount}⚠</span>
                )}
                {!isTsChecking && tsErrCount === 0 && tsWarnCount > 0 && (
                  <span style={{
                    fontSize: "0.60rem", fontWeight: 700, color: "#fbbf24",
                    fontFamily: "ui-monospace,monospace",
                    background: "rgba(251,191,36,0.10)", padding: "1px 5px",
                    borderRadius: 4, border: "1px solid rgba(251,191,36,0.20)",
                  }}>{tsWarnCount}△</span>
                )}
              </div>

              {canRunFile && (
                <button
                  onClick={() => onRunRequest?.(editorContent, openFile.path)}
                  style={{
                    display: "flex", alignItems: "center", gap: 4,
                    padding: "3px 9px", borderRadius: 6, cursor: "pointer",
                    background: "rgba(59,130,246,0.15)",
                    border: "1px solid rgba(59,130,246,0.25)",
                    color: "#4ade80", fontSize: "0.72rem", fontWeight: 600,
                  }}
                >
                  <Play size={11} fill="currentColor" /> Esegui
                </button>
              )}

              <button
                onClick={downloadFile}
                title="Scarica file"
                style={{
                  display: "flex", alignItems: "center", gap: 4,
                  padding: "3px 9px", borderRadius: 6, cursor: "pointer",
                  background: "rgba(96,165,250,0.1)",
                  border: "1px solid rgba(96,165,250,0.2)",
                  color: "#93c5fd", fontSize: "0.72rem", fontWeight: 600,
                }}
              >
                <Download size={11} /> Scarica
              </button>

              <button
                onClick={save}
                disabled={!isDirty || saving}
                style={{
                  display: "flex", alignItems: "center", gap: 4,
                  padding: "3px 9px", borderRadius: 6,
                  cursor: isDirty ? "pointer" : "default",
                  background: isDirty ? "rgba(59,130,246,0.18)" : "var(--bg4)",
                  border: isDirty ? "1px solid rgba(59,130,246,0.3)" : "1px solid transparent",
                  color: isDirty ? "var(--primary-light)" : "var(--text-muted)",
                  fontSize: "0.72rem", fontWeight: 600, opacity: isDirty ? 1 : 0.45,
                }}
              >
                {saving
                  ? <Loader size={11} style={{ animation: "spin-slow 1s linear infinite" }} />
                  : <Save size={11} />}
                Salva
              </button>

              {isDirty && (
                <>
                  <button
                    onClick={() => setShowDiff(d => !d)}
                    title="Mostra diff"
                    style={{
                      display: "flex", alignItems: "center", gap: 3,
                      padding: "3px 9px", borderRadius: 6, cursor: "pointer",
                      background: showDiff ? "rgba(96,165,250,0.15)" : "rgba(255,255,255,0.04)",
                      border: `1px solid ${showDiff ? "rgba(96,165,250,0.3)" : "rgba(255,255,255,0.08)"}`,
                      color: showDiff ? "#93c5fd" : "var(--text-muted)",
                      fontSize: "0.72rem", fontWeight: 600,
                    }}
                  >
                    ↔ Diff
                  </button>
                  <button
                    onClick={() => { setEditorContent(openFile.content); setShowDiff(false); }}
                    title="Ripristina versione salvata"
                    style={{
                      display: "flex", alignItems: "center", gap: 3,
                      padding: "3px 8px", borderRadius: 6, cursor: "pointer",
                      background: "rgba(239,68,68,0.08)",
                      border: "1px solid rgba(239,68,68,0.18)",
                      color: "#fca5a5", fontSize: "0.72rem", fontWeight: 600,
                    }}
                  >
                    <X size={10} /> Ripristina
                  </button>
                </>
              )}

              {/* S800: Cerca — visibile solo su mobile */}
              {isMobile && (
                <button
                  onClick={() => { setShowFindBar(v => !v); }}
                  title="Cerca nel file"
                  style={{
                    display: "flex", alignItems: "center", gap: 3,
                    padding: "3px 9px", borderRadius: 6, cursor: "pointer",
                    background: showFindBar ? "rgba(99,102,241,0.18)" : "rgba(255,255,255,0.04)",
                    border: `1px solid ${showFindBar ? "rgba(99,102,241,0.3)" : "rgba(255,255,255,0.08)"}`,
                    color: showFindBar ? "#818cf8" : "var(--text-muted)",
                    fontSize: "0.72rem", fontWeight: 600, touchAction: "manipulation",
                    WebkitTapHighlightColor: "transparent",
                  } as React.CSSProperties}
                >
                  🔍
                </button>
              )}

              {/* S800: Full-screen — visibile solo su mobile */}
              {isMobile && (
                <button
                  onClick={() => setIsFullscreen(v => !v)}
                  title={isFullscreen ? "Esci dal full-screen" : "Full-screen"}
                  style={{
                    display: "flex", alignItems: "center",
                    padding: "3px 9px", borderRadius: 6, cursor: "pointer",
                    background: isFullscreen ? "rgba(99,102,241,0.18)" : "rgba(255,255,255,0.04)",
                    border: `1px solid ${isFullscreen ? "rgba(99,102,241,0.3)" : "rgba(255,255,255,0.08)"}`,
                    color: isFullscreen ? "#818cf8" : "var(--text-muted)",
                    fontSize: "0.72rem", touchAction: "manipulation",
                    WebkitTapHighlightColor: "transparent",
                  } as React.CSSProperties}
                >
                  {isFullscreen ? "⊡" : "⊞"}
                </button>
              )}

              {saveMsg && (
                <span style={{
                  fontSize: "0.72rem",
                  color: saveMsg.startsWith("Errore") ? "#f87171" : "#4ade80",
                }}>
                  {saveMsg}
                </span>
              )}
            </div>

            {/* CodeMirror editor — lazy-loaded da esm.sh (zero bundle impact) */}
            {/* S800: padding-bottom su mobile per la status bar (28px) + keyboard safety */}
            <div style={{
              flex: 1, display: "flex", flexDirection: "column", overflow: "hidden",
              ...(isMobile && isFullscreen ? {
                position: "fixed", inset: 0, zIndex: 9999,
                background: "hsl(222 22% 7%)", flexDirection: "column",
              } : {}),
            }}>
              <CodeMirrorEditor
                value={editorContent}
                onChange={setEditorContent}
                filename={openFile.path}
                onSave={save}
                tsErrors={tsErrors}
                fontSize={fontSize}
                onCursorChange={(l, c) => { setCursorLine(l); setCursorCol(c); }}
                scrollToOffsetRef={scrollToOffsetRef}
              />
              {/* S800: Status bar — solo mobile */}
              {isMobile && openFile && (
                <Suspense fallback={null}>
                  <MobileEditorStatusBar
                    filename={openFile.path}
                    fileSize={editorContent.length}
                    isDirty={!!isDirty}
                    line={cursorLine}
                    col={cursorCol}
                    fontSize={fontSize}
                    onFontSize={handleFontSize}
                  />
                </Suspense>
              )}
            </div>

            {/* S800: Find bar — solo mobile, si posiziona sopra la tastiera */}
            {isMobile && showFindBar && openFile && (
              <Suspense fallback={null}>
                <MobileEditorFindBar
                  content={editorContent}
                  bottomOffset={isKeyboardOpen ? keyboardHeight : 0}
                  onClose={() => setShowFindBar(false)}
                  onNavigate={handleFindNavigate}
                  onReplace={handleReplace}
                  onReplaceAll={handleReplaceAll}
                />
              </Suspense>
            )}

            {/* Diff panel */}
            {showDiff && isDirty && (
              <div style={{
                flexShrink: 0, maxHeight: "38vh", overflowY: "auto",
                borderTop: "1px solid rgba(96,165,250,0.12)",
                background: "rgba(5,5,16,0.96)",
              }}>
                <DiffBlock content={buildSimpleDiff()} />
              </div>
            )}
          </>
        ) : (
          /* Empty state */
          <div style={{
            flex: 1, display: "flex", alignItems: "center", justifyContent: "center",
            color: "var(--text-muted)", flexDirection: "column", gap: 10,
          }}>
            <FileText size={38} style={{ opacity: 0.13 }} />
            <p style={{ margin: 0, fontSize: "0.85rem", fontWeight: 600 }}>
              Nessun file aperto
            </p>
            <p style={{ margin: 0, fontSize: "0.75rem", opacity: 0.55, textAlign: "center" }}>
              Seleziona un file dalla sidebar,<br />caricane uno o creane uno nuovo
            </p>
            <div style={{ display: "flex", gap: 8, marginTop: 4 }}>
              <button
                onClick={() => fileInputRef.current?.click()}
                style={{
                  display: "flex", alignItems: "center", gap: 6,
                  padding: "7px 14px", borderRadius: 8, cursor: "pointer",
                  background: "rgba(59,130,246,0.12)",
                  border: "1px solid rgba(59,130,246,0.25)",
                  color: "#4ade80", fontSize: "0.78rem", fontWeight: 600,
                }}
              >
                <Upload size={13} /> Carica file
              </button>
              <button
                onClick={() => setShowNewFile(true)}
                style={{
                  display: "flex", alignItems: "center", gap: 6,
                  padding: "7px 14px", borderRadius: 8, cursor: "pointer",
                  background: "rgba(96,165,250,0.1)",
                  border: "1px solid rgba(96,165,250,0.2)",
                  color: "#93c5fd", fontSize: "0.78rem", fontWeight: 600,
                }}
              >
                <Plus size={13} /> Nuovo file
              </button>
            </div>
            <input
              ref={emptyInputRef}
              type="file"
              multiple
              style={{ display: "none" }}
              onChange={async e => {
                if (e.target.files) await uploadFiles(e.target.files);
                e.target.value = "";
              }}
            />
          </div>
        )}
      </div>
    </div>
  );
});

export default FileEditor;
