import React, { useState, useEffect, useRef, useMemo, useCallback, Component } from 'react';
import {
  Folder, File, Terminal, Menu, X, Play, Cpu,
  Send, Code2, ChevronRight, Settings, Sparkles, Plus,
  Layout, GitBranch, AlertCircle, CheckCircle2, MessageSquare,
  ChevronDown, Paperclip, Loader2, GitCommit,
  Save, FilePlus, FolderOpen, Scissors, Copy, Clipboard,
  Undo2, Redo2, Search, ZoomIn, ZoomOut,
  Bug, Square, CheckSquare, HelpCircle, BookOpen, Info,
  Zap, ListChecks, FileEdit, FileMinus, Eye,
  Wifi, WifiOff, Trash2, Globe, TerminalSquare
} from 'lucide-react';

/* ─── Error Boundary ────────────────────────────────────────────────────────── */
class ErrorBoundary extends Component {
  constructor(props) { super(props); this.state = { error: null }; }
  static getDerivedStateFromError(error) { return { error }; }
  render() {
    if (this.state.error) {
      return (
        <div style={{ background: '#0a0412', color: '#e879f9', minHeight: '100vh', display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', padding: '2rem', fontFamily: 'monospace' }}>
          <h1 style={{ fontSize: '1.5rem', marginBottom: '1rem' }}>⚡ EpiCodeSpace crashed</h1>
          <pre style={{ background: '#1a0b35', padding: '1.5rem', borderRadius: '0.75rem', maxWidth: '90vw', overflow: 'auto', fontSize: '0.85rem', color: '#f87171', border: '1px solid rgba(232,121,249,0.3)' }}>{this.state.error?.message}\n{this.state.error?.stack}</pre>
          <button onClick={() => { try { localStorage.clear(); } catch {} this.setState({ error: null }); window.location.reload(); }} style={{ marginTop: '1.5rem', padding: '0.75rem 2rem', background: '#a21caf', color: 'white', border: 'none', borderRadius: '0.5rem', cursor: 'pointer', fontSize: '0.9rem' }}>Clear Data &amp; Reload</button>
          <button onClick={() => this.setState({ error: null })} style={{ marginTop: '0.75rem', padding: '0.5rem 1.5rem', background: 'transparent', color: '#c084fc', border: '1px solid #c084fc', borderRadius: '0.5rem', cursor: 'pointer', fontSize: '0.85rem' }}>Try Again</button>
        </div>
      );
    }
    return this.props.children;
  }
}

/* ─── localStorage persistence ──────────────────────────────────────────────── */
const STORAGE_KEY = 'epicodespace_fs_v2';
const CONVOS_KEY = 'epicodespace_conversations_v1';
const PREFS_KEY = 'epicodespace_preferences_v1';
const PANELS_KEY = 'epicodespace_panels_v1';
const AGENT_KEY = 'epicodespace_agent_v1';
const MODE_KEY = 'epicodespace_mode_v1';

function loadJSON(key, fallback) {
  try { const r = localStorage.getItem(key); return r ? JSON.parse(r) : fallback; } catch { return fallback; }
}
function storeJSON(key, val) {
  try { localStorage.setItem(key, JSON.stringify(val)); } catch { /* quota */ }
}

const DEFAULT_FS = {};

function loadFS() {
  try {
    const raw = localStorage.getItem(STORAGE_KEY);
    if (raw) {
      const parsed = JSON.parse(raw);
      // Clear old mock/default data
      const oldMockKeys = ['copilot-instructions.md', 'src/App.jsx', 'src/index.css', 'src/hooks/useFileSystem.ts'];
      const keys = Object.keys(parsed);
      if (keys.length <= 4 && keys.every(k => oldMockKeys.includes(k))) {
        localStorage.removeItem(STORAGE_KEY);
        return DEFAULT_FS;
      }
      // Sanitize: ensure every entry has a string content
      Object.keys(parsed).forEach(k => {
        if (!parsed[k] || typeof parsed[k].content !== 'string') {
          parsed[k] = { name: k.split('/').pop(), language: 'text', content: parsed[k]?.content ?? '' };
        }
        if (!parsed[k].name) parsed[k].name = k.split('/').pop();
      });
      return parsed;
    }
  } catch { /* corrupted — fall through */ }
  return DEFAULT_FS;
}

function saveFS(fs) {
  try { localStorage.setItem(STORAGE_KEY, JSON.stringify(fs)); } catch { /* quota */ }
}

/* ─── Agent Registry ─────────────────────────────────────────────────────── */
const AGENT_REGISTRY = {
  'epicode-agent': {
    id: 'epicode-agent',
    name: 'EpiCode Agent',
    icon: 'sparkles',
    color: 'text-fuchsia-400',
    description: 'Full-stack coding assistant',
    capabilities: ['code_gen', 'refactor', 'explain', 'debug', 'file_ops', 'review'],
  },
  'copilot': {
    id: 'copilot',
    name: 'Copilot',
    icon: 'cpu',
    color: 'text-cyan-400',
    description: 'GitHub Copilot-style autocomplete & chat',
    capabilities: ['code_gen', 'explain', 'test_gen', 'docs'],
  },
  'claude': {
    id: 'claude',
    name: 'Claude 3.5 Sonnet',
    icon: 'sparkles',
    color: 'text-orange-400',
    description: 'Anthropic reasoning & analysis',
    capabilities: ['explain', 'refactor', 'review', 'architecture', 'debug'],
  },
  'gemini': {
    id: 'gemini',
    name: 'Gemini Pro 1.5',
    icon: 'sparkles',
    color: 'text-blue-400',
    description: 'Google multimodal reasoning',
    capabilities: ['explain', 'code_gen', 'architecture', 'docs'],
  },
  'deepseek': {
    id: 'deepseek',
    name: 'DeepSeek Coder V2',
    icon: 'code2',
    color: 'text-green-400',
    description: 'Specialized code generation & completion',
    capabilities: ['code_gen', 'refactor', 'debug', 'test_gen'],
  },
};

/* ─── Agent Tools (function calling) ─────────────────────────────────────── */
function createAgentTools(fileSystem, activeFile) {
  return {
    readFile: {
      name: 'readFile',
      description: 'Read file contents',
      execute: (path) => {
        const f = fileSystem[path];
        return f ? { ok: true, content: f.content, language: f.language } : { ok: false, error: `File '${path}' not found` };
      },
    },
    listFiles: {
      name: 'listFiles',
      description: 'List all files in workspace',
      execute: () => ({ ok: true, files: Object.keys(fileSystem) }),
    },
    searchCode: {
      name: 'searchCode',
      description: 'Search for pattern across all files',
      execute: (pattern) => {
        const results = [];
        Object.entries(fileSystem).forEach(([path, f]) => {
          f.content.split('\n').forEach((line, i) => {
            if (line.toLowerCase().includes(pattern.toLowerCase())) {
              results.push({ file: path, line: i + 1, text: line.trim() });
            }
          });
        });
        return { ok: true, matches: results.length, results: results.slice(0, 15) };
      },
    },
    analyzeFile: {
      name: 'analyzeFile',
      description: 'Static analysis of a file',
      execute: (path) => {
        const f = fileSystem[path || activeFile];
        if (!f) return { ok: false, error: 'File not found' };
        const lines = f.content.split('\n');
        const issues = [];
        lines.forEach((line, i) => {
          if (/console\.(log|warn|error)/.test(line)) issues.push({ line: i + 1, type: 'warning', msg: 'Console statement' });
          if (/==(?!=)/.test(line)) issues.push({ line: i + 1, type: 'warning', msg: 'Loose equality' });
          if (/\bvar\b/.test(line)) issues.push({ line: i + 1, type: 'warning', msg: 'var usage' });
          if (/TODO|FIXME|HACK/.test(line)) issues.push({ line: i + 1, type: 'info', msg: 'TODO marker' });
          if (/debugger/.test(line)) issues.push({ line: i + 1, type: 'error', msg: 'Debugger statement' });
        });
        return { ok: true, file: path || activeFile, lines: lines.length, chars: f.content.length, issues };
      },
    },
    getContext: {
      name: 'getContext',
      description: 'Get current workspace context',
      execute: () => ({
        ok: true,
        activeFile,
        totalFiles: Object.keys(fileSystem).length,
        files: Object.entries(fileSystem).map(([p, f]) => ({
          path: p, language: f.language, lines: f.content.split('\n').length,
        })),
      }),
    },
  };
}

/* ─── Agent Response Engine ──────────────────────────────────────────────── */
function buildAgentResponse(agentId, query, tools, fileSystem, activeFile) {
  const q = query.toLowerCase();
  const ctx = tools.getContext.execute();
  const activeContent = fileSystem[activeFile]?.content || '';
  const activeLines = activeContent.split('\n').length;

  // Detect intent from query
  const intents = {
    explain: /explain|what does|how does|what is|walk me through|describe/i.test(q),
    refactor: /refactor|improve|clean up|optimize|simplify|better way/i.test(q),
    debug: /debug|fix|error|bug|issue|wrong|broken|not working|crash/i.test(q),
    generate: /generate|create|write|add|implement|build|make a|scaffold/i.test(q),
    review: /review|audit|check|scan|analyze|look at|assess/i.test(q),
    test: /test|spec|unit test|coverage|testing/i.test(q),
    search: /find|search|where|locate|grep|which file/i.test(q),
    docs: /document|docstring|jsdoc|comment|readme/i.test(q),
    architecture: /architect|design|pattern|structure|organize|plan/i.test(q),
  };

  const agent = AGENT_REGISTRY[agentId];
  const toolCalls = [];
  const steps = [];

  // --- Tool invocations based on intent ---
  if (intents.search) {
    const words = q.split(/\s+/).filter(w => w.length > 3 && !['find', 'search', 'where', 'which', 'file', 'locate', 'does', 'the'].includes(w));
    const pattern = words[words.length - 1] || 'function';
    const result = tools.searchCode.execute(pattern);
    toolCalls.push({ tool: 'searchCode', args: pattern, result });
    if (result.matches > 0) {
      steps.push(`🔍 **searchCode**("${pattern}") → ${result.matches} match(es)`);
      const matchList = result.results.slice(0, 8).map(r => `  \`${r.file}:${r.line}\` → ${r.text}`).join('\n');
      return { steps, toolCalls, response: `Found **${result.matches}** occurrences of "${pattern}":\n\n${matchList}${result.matches > 8 ? `\n  _...and ${result.matches - 8} more_` : ''}` };
    }
    steps.push(`🔍 **searchCode**("${pattern}") → 0 matches`);
    return { steps, toolCalls, response: `No matches for "${pattern}" across ${ctx.totalFiles} files.` };
  }

  if (intents.review || intents.debug) {
    const analysis = tools.analyzeFile.execute(activeFile);
    toolCalls.push({ tool: 'analyzeFile', args: activeFile, result: analysis });
    steps.push(`🔬 **analyzeFile**(${activeFile}) → ${analysis.issues?.length || 0} issue(s)`);
    if (analysis.ok && analysis.issues.length > 0) {
      const issueList = analysis.issues.slice(0, 10).map(i => `  ${i.type === 'error' ? '🔴' : i.type === 'warning' ? '🟡' : 'ℹ️'} Line ${i.line}: ${i.msg}`).join('\n');
      const advice = agentId === 'claude'
        ? `\n\n**Recommendation:** Address errors first, then warnings. The TODO markers can wait. I'd prioritize removing any \`debugger\` statements and converting \`var\` to \`const\`/\`let\`.`
        : agentId === 'copilot'
        ? `\n\n**Quick fix available.** I can auto-fix ${analysis.issues.filter(i => i.type === 'warning').length} warning(s). Want me to apply?`
        : agentId === 'deepseek'
        ? `\n\n**Auto-fix ready:** I can patch \`var→const\`, \`==→===\`, and strip console statements in one pass. Confirm to proceed.`
        : `\n\nI can fix these automatically or walk you through each one. What would you prefer?`;
      return { steps, toolCalls, response: `**Code Review:** \`${activeFile}\` (${analysis.lines} lines)\n\n${issueList}${advice}` };
    }
    steps.push(`✅ No issues found in \`${activeFile}\``);
  }

  if (intents.explain) {
    const file = tools.readFile.execute(activeFile);
    toolCalls.push({ tool: 'readFile', args: activeFile, result: { ok: true, lines: activeLines } });
    steps.push(`📖 **readFile**(${activeFile}) → ${activeLines} lines`);
    const lang = fileSystem[activeFile]?.language || 'text';
    const explanations = {
      'epicode-agent': `**\`${activeFile}\`** (${lang}, ${activeLines} lines)\n\nThis file ${lang === 'markdown' ? 'documents project configuration and business logic. Key sections cover the tech stack (Vercel, Firebase, Modal), subscription tiers, and credit system.' : lang === 'css' ? 'defines the base styles using Tailwind CSS directives and custom properties.' : `defines a ${lang === 'typescript' ? 'TypeScript' : 'JavaScript'} module. It exports ${activeContent.includes('export default') ? 'a default component/function' : 'named exports'} and contains ${activeLines} lines of logic.`}\n\nWant me to break down any specific section?`,
      'copilot': `Here's a breakdown of \`${activeFile}\`:\n\n• **Language:** ${lang}\n• **Lines:** ${activeLines}\n• **Exports:** ${activeContent.match(/export/g)?.length || 0}\n• **Imports:** ${activeContent.match(/import/g)?.length || 0}\n\n${activeContent.includes('useState') ? 'This is a **stateful React component** using hooks.' : activeContent.includes('function') ? 'Contains **function declarations** — looks like a utility module.' : 'This appears to be a **configuration/content** file.'}\n\nI can generate inline comments or a JSDoc summary. Just say the word.`,
      'claude': `Let me walk through \`${activeFile}\` systematically.\n\n**Structure:** ${activeLines} lines of ${lang}. ${activeContent.includes('import') ? `The file imports ${(activeContent.match(/import/g) || []).length} dependencies, ` : ''}${activeContent.includes('export') ? `exports ${(activeContent.match(/export/g) || []).length} symbol(s).` : 'no exports detected.'}\n\n**Purpose:** ${lang === 'markdown' ? 'This is a project specification document outlining the tech stack, business model, and deployment architecture.' : `This ${lang} module ${activeContent.includes('return') ? 'renders UI or returns computed values' : 'defines data structures or utilities'}.`}\n\n**Key observation:** ${activeContent.length > 2000 ? 'This file is fairly large — consider breaking it into smaller modules if complexity grows.' : 'File size is manageable. Good modularity.'}\n\nWould you like me to analyze the control flow or data dependencies?`,
      'gemini': `**Analysis of \`${activeFile}\`:**\n\n📊 **Metrics:** ${activeLines} lines | ${activeContent.length} chars | ${lang}\n\nThis file ${activeContent.includes('React') ? 'is a React component' : activeContent.includes('function') ? 'contains utility functions' : 'holds configuration data'}. ${activeContent.includes('async') ? 'It uses async patterns — ensure proper error handling.' : ''}\n\n${lang === 'markdown' ? 'The markdown outlines a SaaS architecture with Vercel + Firebase + Modal + Stripe.' : `The main logic ${activeContent.includes('useState') ? 'is stateful (React hooks detected)' : 'is stateless'}.`}`,
      'deepseek': `\`\`\`analysis\nFile: ${activeFile}\nLang: ${lang}\nLines: ${activeLines}\nSize: ${activeContent.length} bytes\nImports: ${(activeContent.match(/import/g) || []).length}\nExports: ${(activeContent.match(/export/g) || []).length}\nFunctions: ${(activeContent.match(/function\s/g) || []).length}\nArrow fns: ${(activeContent.match(/=>/g) || []).length}\n\`\`\`\n\n${activeContent.includes('useState') ? 'Detected React hooks pattern. State variables found: ' + (activeContent.match(/useState/g) || []).length : 'No React hooks detected.'}\n\nShall I generate type annotations or refactor suggestions?`,
    };
    return { steps, toolCalls, response: explanations[agentId] || explanations['epicode-agent'] };
  }

  if (intents.generate || intents.test) {
    const ctxResult = tools.getContext.execute();
    toolCalls.push({ tool: 'getContext', result: ctxResult });
    steps.push(`📋 **getContext**() → ${ctxResult.totalFiles} files`);
    if (intents.test) {
      const testCode = `import { describe, it, expect } from 'vitest';\n\ndescribe('${activeFile}', () => {\n  it('should exist and be importable', () => {\n    expect(true).toBe(true);\n  });\n\n  it('should render without crashing', () => {\n    // TODO: Add component render test\n    expect(true).toBeTruthy();\n  });\n\n  it('should handle edge cases', () => {\n    // TODO: Add edge case tests\n  });\n});`;
      return { steps, toolCalls, response: `Here's a test scaffold for \`${activeFile}\`:\n\n\`\`\`javascript\n${testCode}\n\`\`\`\n\nI've generated 3 test cases. Want me to write this to \`${activeFile.replace(/\.(jsx?|tsx?)$/, '.test$&')}\`?` };
    }
    const generators = {
      'epicode-agent': `Based on your workspace (${ctxResult.totalFiles} files), here's what I'd generate:\n\n\`\`\`javascript\n// Generated by EpiCode Agent\nexport function ${q.match(/(?:create|make|build|add|write)\s+(?:a\s+)?(\w+)/i)?.[1] || 'newModule'}() {\n  // TODO: Implement\n  return null;\n}\n\`\`\`\n\nShall I expand this with full implementation based on your project context?`,
      'copilot': `**Copilot suggestion:**\n\n\`\`\`javascript\n// ✨ Generated from context of ${ctxResult.totalFiles} workspace files\nconst ${q.match(/(?:create|make|build|add|write)\s+(?:a\s+)?(\w+)/i)?.[1] || 'handler'} = async (params) => {\n  try {\n    const result = await processRequest(params);\n    return { success: true, data: result };\n  } catch (error) {\n    console.error('Operation failed:', error);\n    return { success: false, error: error.message };\n  }\n};\n\`\`\`\n\nTab to accept, or ask me to refine.`,
      'claude': `Let me think about the best approach.\n\n**Design considerations:**\n1. Error handling at boundaries\n2. Type safety\n3. Testability\n\n\`\`\`typescript\ninterface ${(q.match(/(?:create|make|build|add|write)\s+(?:a\s+)?(\w+)/i)?.[1] || 'Module')}Config {\n  // Define your options here\n  enabled: boolean;\n  retries?: number;\n}\n\nexport function create${(q.match(/(?:create|make|build|add|write)\s+(?:a\s+)?(\w+)/i)?.[1] || 'Module')}(config: ${(q.match(/(?:create|make|build|add|write)\s+(?:a\s+)?(\w+)/i)?.[1] || 'Module')}Config) {\n  if (!config.enabled) return null;\n  // Implementation here\n}\n\`\`\`\n\nThis follows the factory pattern. Want me to flesh out the implementation?`,
      'deepseek': `\`\`\`javascript\n/**\n * Auto-generated by DeepSeek Coder V2\n * Context: ${ctxResult.totalFiles} files in workspace\n */\nexport default function ${q.match(/(?:create|make|build|add|write)\s+(?:a\s+)?(\w+)/i)?.[1] || 'generated'}(input) {\n  // Type: ${typeof input === 'string' ? 'string' : 'unknown'}\n  const processed = input;\n  return processed;\n}\n\`\`\`\n\nCompact and ready. Need types or tests?`,
      'gemini': `**Here's my approach:**\n\n1. First, I'll scaffold the structure\n2. Then wire it into your existing modules\n\n\`\`\`javascript\n// 🌟 Gemini-generated scaffold\nimport React from 'react';\n\nexport default function ${q.match(/(?:create|make|build|add|write)\s+(?:a\s+)?(\w+)/i)?.[1] || 'NewComponent'}({ data }) {\n  return (\n    <div className="p-4">\n      <h2>{data?.title || 'New Component'}</h2>\n      {/* Add your content here */}\n    </div>\n  );\n}\n\`\`\`\n\nThis integrates with your Tailwind setup. Want me to add state management?`,
    };
    return { steps, toolCalls, response: generators[agentId] || generators['epicode-agent'] };
  }

  if (intents.refactor) {
    const analysis = tools.analyzeFile.execute(activeFile);
    toolCalls.push({ tool: 'analyzeFile', args: activeFile, result: analysis });
    steps.push(`🔬 **analyzeFile**(${activeFile}) → ${analysis.lines} lines, ${analysis.issues?.length || 0} issues`);
    return { steps, toolCalls, response: `**Refactoring plan for \`${activeFile}\`:**\n\n1. ${analysis.issues?.some(i => i.msg.includes('var')) ? '✅ Convert `var` → `const`/`let`' : '◻️ Variables already use modern declarations'}\n2. ${analysis.issues?.some(i => i.msg.includes('equality')) ? '✅ Fix loose equality `==` → `===`' : '◻️ Strict equality in use'}\n3. ${analysis.issues?.some(i => i.msg.includes('Console')) ? '✅ Remove console statements' : '◻️ No console statements'}\n4. ${analysis.lines > 100 ? '✅ Consider extracting functions (file is ' + analysis.lines + ' lines)' : '◻️ File length is fine'}\n5. ${activeContent.includes('any') ? '✅ Replace `any` types with proper interfaces' : '◻️ No `any` types detected'}\n\nWant me to apply these changes now?` };
  }

  if (intents.architecture) {
    const ctxResult = tools.getContext.execute();
    toolCalls.push({ tool: 'getContext', result: ctxResult });
    steps.push(`📋 **getContext**() → ${ctxResult.totalFiles} files`);
    const fileBreakdown = ctxResult.files.map(f => `  \`${f.path}\` (${f.language}, ${f.lines} lines)`).join('\n');
    return { steps, toolCalls, response: `**Workspace Architecture Overview:**\n\n📁 **${ctxResult.totalFiles} files:**\n${fileBreakdown}\n\n**Observations:**\n• ${ctxResult.files.some(f => f.language === 'typescript') ? 'TypeScript is in use — good for type safety' : 'Consider adding TypeScript for better DX'}\n• ${ctxResult.files.some(f => f.path.includes('hooks/')) ? 'Custom hooks pattern detected — well-organized' : 'Consider extracting reusable logic into hooks'}\n• Total codebase: ~${ctxResult.files.reduce((a, f) => a + f.lines, 0)} lines\n\nWant me to suggest a restructuring plan?` };
  }

  // Fallback: general conversation with context awareness
  const ctxResult = tools.getContext.execute();
  toolCalls.push({ tool: 'getContext', result: ctxResult });
  steps.push(`📋 **getContext**() → ${ctxResult.totalFiles} files, active: ${activeFile}`);

  const fallbacks = {
    'epicode-agent': `I've reviewed your workspace (${ctxResult.totalFiles} files, active: \`${activeFile}\`). Regarding "${query}":\n\nI can help with that. Here's what I'd suggest:\n\n1. Let me scan the relevant files for context\n2. I'll draft the implementation\n3. You review and I'll apply\n\nWant me to start with a specific file, or should I work across the whole project?`,
    'copilot': `**Copilot** — Working from \`${activeFile}\` (${activeLines} lines)\n\nI understand you want to: "${query}"\n\nBased on the project context (${ctxResult.totalFiles} files), I can:\n• Generate code inline\n• Suggest completions\n• Write tests\n\nRefine your ask and I'll produce code directly.`,
    'claude': `Let me think about this carefully.\n\n**Context:** ${ctxResult.totalFiles} files in workspace. Currently editing \`${activeFile}\` (${activeLines} lines, ${fileSystem[activeFile]?.language}).\n\n**On "${query}":** This is a nuanced question. The approach depends on your constraints — performance requirements, maintainability goals, and whether this is user-facing. Could you clarify which aspect matters most? I'll tailor my response accordingly.`,
    'gemini': `**Gemini Pro** analyzing your request...\n\n📊 Workspace: ${ctxResult.totalFiles} files | Active: \`${activeFile}\`\n\nFor "${query}", I recommend a multi-step approach:\n\n**Step 1:** Audit current implementation\n**Step 2:** Identify optimization targets\n**Step 3:** Apply changes incrementally\n\nShall I begin with Step 1?`,
    'deepseek': `\`\`\`context\nWorkspace: ${ctxResult.totalFiles} files\nActive: ${activeFile} (${activeLines} lines)\nQuery: "${query}"\n\`\`\`\n\nReady to execute. Specify:\n- \`/gen\` — generate code\n- \`/fix\` — debug & patch\n- \`/refactor\` — clean & optimize\n- \`/test\` — scaffold tests\n\nOr just describe what you need in plain English.`,
  };
  return { steps, toolCalls, response: fallbacks[agentId] || fallbacks['epicode-agent'] };
}

/* ─── Main Component ────────────────────────────────────────────────────────── */
function EpiCodeSpaceApp() {
  // ── File system ───────────────────────────────────────────────────────────
  const [fileSystem, setFileSystem] = useState(loadFS);
  const [projectName, setProjectName] = useState(() => loadJSON('epicodespace_project_v1', 'My Project'));
  const firstFile = Object.keys(fileSystem)[0] || null;
  const [activeFile, setActiveFile] = useState(firstFile);
  const [openTabs, setOpenTabs] = useState(firstFile ? [firstFile] : []);
  const [untitledCount, setUntitledCount] = useState(1);
  const [renamingFile, setRenamingFile] = useState(null);
  const [renameValue, setRenameValue] = useState('');

  // ── Panels ────────────────────────────────────────────────────────────────
  const savedPanels = loadJSON(PANELS_KEY, { sidebarOpen: true, rightSidebarOpen: true, terminalState: 'open' });
  const [sidebarOpen, setSidebarOpen] = useState(savedPanels.sidebarOpen);
  const [rightSidebarOpen, setRightSidebarOpen] = useState(savedPanels.rightSidebarOpen);
  const [terminalState, setTerminalState] = useState(savedPanels.terminalState);
  const [activeTerminalTab, setActiveTerminalTab] = useState('terminal');

  // ── Terminal ──────────────────────────────────────────────────────────────
  const [terminalLines, setTerminalLines] = useState(['ubuntu@epicode:~/workspace (main) $ ']);
  const [terminalInput, setTerminalInput] = useState('');
  const [outputLog, setOutputLog] = useState(['EpiCodeSpace output panel ready.']);
  const [debugConsoleLines, setDebugConsoleLines] = useState([{ type: 'info', text: 'Debug console attached.', ts: Date.now() }]);
  const [ports, setPorts] = useState([
    { port: 5173, protocol: 'https', state: 'running', label: 'Vite Dev Server', visibility: 'private', pid: 1024 },
  ]);
  const [chatTodos, setChatTodos] = useState([]);

  // ── Chat ──────────────────────────────────────────────────────────────────
  const [chatInput, setChatInput] = useState('');
  const [messages, setMessages] = useState([]);
  const [isTyping, setIsTyping] = useState(false);
  const [chatMode, setChatMode] = useState(() => loadJSON(MODE_KEY, 'agent'));
  const savedConvos = loadJSON(CONVOS_KEY, [{ id: 1, name: 'Chat 1', messages: [], agent: 'epicode-agent' }]);
  const [activeAgent, setActiveAgent] = useState(() => loadJSON(AGENT_KEY, 'epicode-agent'));
  const [showAgentPicker, setShowAgentPicker] = useState(false);
  const [showConversations, setShowConversations] = useState(false);
  const [conversations, setConversations] = useState(savedConvos);
  const [activeConvoId, setActiveConvoId] = useState(savedConvos[0]?.id ?? 1);
  const convoCountRef = useRef(savedConvos.length);

  // ── Resizing ──────────────────────────────────────────────────────────────
  const isMobile = typeof window !== 'undefined' && window.innerWidth < 768;
  const isTablet = typeof window !== 'undefined' && window.innerWidth >= 768 && window.innerWidth < 1024;
  const [leftWidth, setLeftWidth] = useState(isMobile ? 280 : 240);
  const [rightWidth, setRightWidth] = useState(isMobile ? window.innerWidth : isTablet ? 300 : 320);
  const [termHeight, setTermHeight] = useState(isMobile ? 200 : 256);
  const [isDragging, setIsDragging] = useState(null);
  const [screenWidth, setScreenWidth] = useState(typeof window !== 'undefined' ? window.innerWidth : 1200);

  // ── Editor extras ─────────────────────────────────────────────────────────
  const [cursorPos, setCursorPos] = useState({ line: 1, col: 1 });
  const savedPrefs = loadJSON(PREFS_KEY, { fontSize: 13, wordWrap: false });
  const [fontSize, setFontSize] = useState(savedPrefs.fontSize);
  const [wordWrap, setWordWrap] = useState(savedPrefs.wordWrap);
  const [showFind, setShowFind] = useState(false);
  const [findQuery, setFindQuery] = useState('');
  const [savedIndicator, setSavedIndicator] = useState(false);
  const [activeMenu, setActiveMenu] = useState(null);
  const [showAbout, setShowAbout] = useState(false);

  // ── Refs ──────────────────────────────────────────────────────────────────
  const chatEndRef = useRef(null);
  const editorRef = useRef(null);
  const menuBarRef = useRef(null);
  const termInputRef = useRef(null);
  const handleSaveRef = useRef(null);
  const handleNewFileRef = useRef(null);
  const handleTerminalCommandRef = useRef(null);

  // ── Track screen width ────────────────────────────────────────────────────
  useEffect(() => {
    const onResize = () => setScreenWidth(window.innerWidth);
    window.addEventListener('resize', onResize);
    return () => window.removeEventListener('resize', onResize);
  }, []);
  const sm = screenWidth < 768;
  const md = screenWidth >= 768 && screenWidth < 1024;

  // ── Persist on change ─────────────────────────────────────────────────────
  useEffect(() => { saveFS(fileSystem); }, [fileSystem]);
  useEffect(() => { storeJSON(CONVOS_KEY, conversations); }, [conversations]);
  useEffect(() => { storeJSON(AGENT_KEY, activeAgent); }, [activeAgent]);
  useEffect(() => { storeJSON(MODE_KEY, chatMode); }, [chatMode]);
  useEffect(() => { storeJSON(PREFS_KEY, { fontSize, wordWrap }); }, [fontSize, wordWrap]);
  useEffect(() => { storeJSON(PANELS_KEY, { sidebarOpen, rightSidebarOpen, terminalState }); }, [sidebarOpen, rightSidebarOpen, terminalState]);

  // ── Chat auto-scroll ─────────────────────────────────────────────────────
  useEffect(() => { chatEndRef.current?.scrollIntoView({ behavior: 'smooth' }); }, [messages, isTyping]);

  // ── Resizing logic (mouse + touch) ────────────────────────────────────────
  useEffect(() => {
    if (!isDragging) return;
    const getXY = (e) => e.touches ? { x: e.touches[0].clientX, y: e.touches[0].clientY } : { x: e.clientX, y: e.clientY };
    const onMove = (e) => {
      const { x, y } = getXY(e);
      if (isDragging === 'left') setLeftWidth(Math.max(160, Math.min(sm ? screenWidth * 0.85 : 600, x)));
      else if (isDragging === 'right') setRightWidth(Math.max(250, Math.min(sm ? screenWidth : 800, window.innerWidth - x)));
      else if (isDragging === 'terminal') setTermHeight(Math.max(80, Math.min(window.innerHeight - 150, window.innerHeight - y - 24)));
    };
    const onUp = () => setIsDragging(null);
    document.addEventListener('mousemove', onMove);
    document.addEventListener('mouseup', onUp);
    document.addEventListener('touchmove', onMove, { passive: false });
    document.addEventListener('touchend', onUp);
    return () => {
      document.removeEventListener('mousemove', onMove);
      document.removeEventListener('mouseup', onUp);
      document.removeEventListener('touchmove', onMove);
      document.removeEventListener('touchend', onUp);
    };
  }, [isDragging, sm, screenWidth]);

  // ── Close menu/picker on outside click ─────────────────────────────────
  useEffect(() => {
    const h = (e) => {
      if (menuBarRef.current && !menuBarRef.current.contains(e.target)) setActiveMenu(null);
      // Close agent picker if click outside chat panel
      if (showAgentPicker && !e.target.closest('[data-agent-picker]')) setShowAgentPicker(false);
    };
    document.addEventListener('mousedown', h);
    return () => document.removeEventListener('mousedown', h);
  }, [showAgentPicker]);

  // ── Cursor tracking ──────────────────────────────────────────────────────
  const handleCursorMove = useCallback((e) => {
    const ta = e.target;
    const text = ta.value.substring(0, ta.selectionStart);
    const lines = text.split('\n');
    setCursorPos({ line: lines.length, col: lines[lines.length - 1].length + 1 });
  }, []);

  // ── Problems scanner ─────────────────────────────────────────────────────
  const allProblems = useMemo(() => {
    const results = [];
    Object.entries(fileSystem).forEach(([path, f]) => {
      if (!f || typeof f.content !== 'string') return;
      f.content.split('\n').forEach((line, idx) => {
        if (line.trim().startsWith('//')) return;
        if (/console\.(log|warn|error|info)/.test(line)) results.push({ severity: 'warning', file: path, line: idx + 1, msg: `Avoid console.${line.match(/console\.(log|warn|error|info)/)[1]} in production code` });
        if (/TODO|FIXME|HACK/.test(line)) results.push({ severity: 'info', file: path, line: idx + 1, msg: `${line.match(/TODO|FIXME|HACK/)[0]}: ${line.trim()}` });
        if (/==(?!=)/.test(line)) results.push({ severity: 'warning', file: path, line: idx + 1, msg: 'Use === instead of ==' });
        if (/\bvar\b/.test(line)) results.push({ severity: 'warning', file: path, line: idx + 1, msg: 'Prefer const or let over var' });
        if (line.length > 120) results.push({ severity: 'info', file: path, line: idx + 1, msg: `Line exceeds 120 characters (${line.length})` });
        if (/debugger/.test(line)) results.push({ severity: 'error', file: path, line: idx + 1, msg: 'Remove debugger statement before commit' });
      });
    });
    return results;
  }, [fileSystem]);

  const errorCount = useMemo(() => allProblems.filter(p => p.severity === 'error').length, [allProblems]);
  const warningCount = useMemo(() => allProblems.filter(p => p.severity === 'warning').length, [allProblems]);
  const infoCount = useMemo(() => allProblems.filter(p => p.severity === 'info').length, [allProblems]);

  // ── Build output (stable) ────────────────────────────────────────────────
  const buildOutput = useMemo(() => {
    const total = Object.values(fileSystem).reduce((a, f) => a + (f?.content?.length || 0), 0);
    return [
      '> epicodespace@1.0.0 build', '> vite build', '',
      'vite v6.0.0 building for production...',
      `✓ ${Object.keys(fileSystem).length + 38} modules transformed.`,
      'dist/index.html                   0.45 kB',
      `dist/assets/index-Bqx3.css        ${(total / 1200).toFixed(2)} kB | gzip: 2.31 kB`,
      `dist/assets/index-DiYf.js       ${(total / 1000).toFixed(2)} kB | gzip: 58.21 kB`,
      '✓ built in 1.14s',
    ];
  }, [fileSystem]);

  // ── File handlers ─────────────────────────────────────────────────────────
  const handleFileClick = useCallback((path) => {
    setActiveFile(path);
    setOpenTabs(prev => prev.includes(path) ? prev : [...prev, path]);
    if (sm) setSidebarOpen(false);
  }, [sm]);

  const handleCloseTab = useCallback((path, e) => {
    e.stopPropagation();
    setOpenTabs(prev => {
      const next = prev.filter(t => t !== path);
      setActiveFile(cur => cur === path ? (next[next.length - 1] ?? Object.keys(fileSystem)[0]) : cur);
      return next;
    });
  }, [fileSystem]);

  const handleEditorChange = useCallback((e) => {
    const value = e.target.value;
    setFileSystem(prev => ({ ...prev, [activeFile]: { ...prev[activeFile], content: value } }));
  }, [activeFile]);

  const handleSave = useCallback(() => {
    setSavedIndicator(true);
    setTimeout(() => setSavedIndicator(false), 2000);
  }, []);

  const handleNewFile = useCallback(() => {
    setUntitledCount(prev => {
      const newPath = `untitled-${prev}.js`;
      setFileSystem(fs => ({ ...fs, [newPath]: { name: `untitled-${prev}.js`, language: 'javascript', content: '' } }));
      setOpenTabs(tabs => [...tabs, newPath]);
      setActiveFile(newPath);
      return prev + 1;
    });
  }, []);

  useEffect(() => { handleSaveRef.current = handleSave; }, [handleSave]);
  useEffect(() => { handleNewFileRef.current = handleNewFile; }, [handleNewFile]);

  // ── Project management ────────────────────────────────────────────────────
  useEffect(() => { storeJSON('epicodespace_project_v1', projectName); }, [projectName]);

  const handleNewProject = useCallback((template) => {
    const templates = {
      empty: {},
      react: {
        'src/App.jsx': { name: 'App.jsx', language: 'javascript', content: "import React from 'react';\n\nexport default function App() {\n  return <div>Hello World</div>;\n}\n" },
        'src/index.css': { name: 'index.css', language: 'css', content: "body { margin: 0; font-family: sans-serif; }\n" },
        'package.json': { name: 'package.json', language: 'json', content: '{\n  "name": "my-app",\n  "version": "1.0.0",\n  "dependencies": {\n    "react": "^18.0.0",\n    "react-dom": "^18.0.0"\n  }\n}\n' },
      },
      node: {
        'index.js': { name: 'index.js', language: 'javascript', content: "const http = require('http');\n\nconst server = http.createServer((req, res) => {\n  res.writeHead(200, { 'Content-Type': 'text/plain' });\n  res.end('Hello World');\n});\n\nserver.listen(3000, () => console.log('Server running on port 3000'));\n" },
        'package.json': { name: 'package.json', language: 'json', content: '{\n  "name": "my-server",\n  "version": "1.0.0",\n  "main": "index.js",\n  "scripts": {\n    "start": "node index.js"\n  }\n}\n' },
      },
      html: {
        'index.html': { name: 'index.html', language: 'html', content: '<!DOCTYPE html>\n<html lang="en">\n<head>\n  <meta charset="UTF-8">\n  <meta name="viewport" content="width=device-width, initial-scale=1.0">\n  <title>My Site</title>\n  <link rel="stylesheet" href="style.css">\n</head>\n<body>\n  <h1>Hello World</h1>\n  <script src="app.js"></script>\n</body>\n</html>\n' },
        'style.css': { name: 'style.css', language: 'css', content: "body {\n  margin: 0;\n  font-family: sans-serif;\n  background: #f5f5f5;\n}\n\nh1 {\n  text-align: center;\n  padding: 2rem;\n}\n" },
        'app.js': { name: 'app.js', language: 'javascript', content: "document.addEventListener('DOMContentLoaded', () => {\n  console.log('App loaded');\n});\n" },
      },
    };
    const newFS = templates[template] || templates.empty;
    setFileSystem(newFS);
    const firstKey = Object.keys(newFS)[0] || null;
    setOpenTabs(firstKey ? [firstKey] : []);
    setActiveFile(firstKey);
    setProjectName(template === 'empty' ? 'New Project' : `${template}-app`);
  }, []);

  const handleDeleteFile = useCallback((path) => {
    setFileSystem(prev => { const n = { ...prev }; delete n[path]; return n; });
    setOpenTabs(prev => prev.filter(t => t !== path));
    setActiveFile(cur => cur === path ? (Object.keys(fileSystem).find(k => k !== path) || null) : cur);
  }, [fileSystem]);

  const handleRenameFile = useCallback((oldPath, newPath) => {
    if (!newPath || newPath === oldPath || fileSystem[newPath]) return;
    setFileSystem(prev => {
      const n = { ...prev };
      n[newPath] = { ...n[oldPath], name: newPath.split('/').pop() };
      delete n[oldPath];
      return n;
    });
    setOpenTabs(prev => prev.map(t => t === oldPath ? newPath : t));
    setActiveFile(cur => cur === oldPath ? newPath : cur);
    setRenamingFile(null);
  }, [fileSystem]);

  const handleExportProject = useCallback(() => {
    const files = Object.entries(fileSystem);
    if (files.length === 0) return;
    // Export as JSON bundle (downloadable)
    const bundle = { name: projectName, files: fileSystem, exportedAt: new Date().toISOString() };
    const blob = new Blob([JSON.stringify(bundle, null, 2)], { type: 'application/json' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = `${projectName.replace(/[^a-zA-Z0-9-_]/g, '_')}.epicode.json`;
    a.click();
    URL.revokeObjectURL(url);
  }, [fileSystem, projectName]);

  const handleImportProject = useCallback(() => {
    const input = document.createElement('input');
    input.type = 'file';
    input.accept = '.json,.epicode.json';
    input.onchange = (e) => {
      const file = e.target.files[0];
      if (!file) return;
      const reader = new FileReader();
      reader.onload = (ev) => {
        try {
          const data = JSON.parse(ev.target.result);
          if (data.files && typeof data.files === 'object') {
            setFileSystem(data.files);
            setProjectName(data.name || file.name.replace(/\.epicode\.json$|\.json$/, ''));
            const first = Object.keys(data.files)[0] || null;
            setOpenTabs(first ? [first] : []);
            setActiveFile(first);
          }
        } catch { /* invalid file */ }
      };
      reader.readAsText(file);
    };
    input.click();
  }, []);

  // ── Clipboard operations ──────────────────────────────────────────────────
  const editorCut = useCallback(() => {
    const ta = editorRef.current;
    if (!ta) return;
    const selected = ta.value.substring(ta.selectionStart, ta.selectionEnd);
    if (!selected) return;
    navigator.clipboard?.writeText(selected).catch(() => {});
    const newVal = ta.value.substring(0, ta.selectionStart) + ta.value.substring(ta.selectionEnd);
    setFileSystem(prev => ({ ...prev, [activeFile]: { ...prev[activeFile], content: newVal } }));
  }, [activeFile]);

  const editorCopy = useCallback(() => {
    const ta = editorRef.current;
    if (!ta) return;
    navigator.clipboard?.writeText(ta.value.substring(ta.selectionStart, ta.selectionEnd)).catch(() => {});
  }, []);

  const editorPaste = useCallback(() => {
    navigator.clipboard?.readText().then(text => {
      const ta = editorRef.current;
      if (!ta) return;
      const newVal = ta.value.substring(0, ta.selectionStart) + text + ta.value.substring(ta.selectionEnd);
      setFileSystem(prev => ({ ...prev, [activeFile]: { ...prev[activeFile], content: newVal } }));
    }).catch(() => {});
  }, [activeFile]);

  const editorSelectAll = useCallback(() => { editorRef.current?.focus(); editorRef.current?.select(); }, []);

  // ── Keyboard shortcuts (stable refs) ──────────────────────────────────────
  useEffect(() => {
    const handleKeyDown = (e) => {
      const ctrl = e.ctrlKey || e.metaKey;
      if (ctrl && e.key === 's') { e.preventDefault(); handleSaveRef.current?.(); }
      if (ctrl && e.key === 'n') { e.preventDefault(); handleNewFileRef.current?.(); }
      if (ctrl && e.key === 'f') { e.preventDefault(); setShowFind(true); }
      if (ctrl && e.key === '`') { e.preventDefault(); setTerminalState(p => p === 'open' ? 'closed' : 'open'); }
      if (ctrl && e.shiftKey && e.key === 'E') { e.preventDefault(); setSidebarOpen(p => !p); }
      if (ctrl && e.key === '=') { e.preventDefault(); setFontSize(p => Math.min(p + 1, 28)); }
      if (ctrl && e.key === '-') { e.preventDefault(); setFontSize(p => Math.max(p - 1, 10)); }
      if (ctrl && e.key === '0') { e.preventDefault(); setFontSize(13); }
      if (e.key === 'Escape') { setShowFind(false); setFindQuery(''); setActiveMenu(null); setShowAbout(false); }
    };
    document.addEventListener('keydown', handleKeyDown);
    return () => document.removeEventListener('keydown', handleKeyDown);
  }, []);

  // ── Execute tool calls against virtual filesystem ────────────────────────
  const executeToolCall = useCallback((name, args, currentFS) => {
    switch (name) {
      case 'readFile': {
        const f = currentFS[args.path];
        if (!f) return { ok: false, error: `File not found: ${args.path}` };
        return { ok: true, path: args.path, content: f.content, language: f.language, lines: f.content.split('\n').length };
      }
      case 'writeFile': {
        const lang = args.path.endsWith('.jsx') || args.path.endsWith('.js') ? 'javascript'
          : args.path.endsWith('.tsx') || args.path.endsWith('.ts') ? 'typescript'
          : args.path.endsWith('.css') ? 'css'
          : args.path.endsWith('.json') ? 'json'
          : args.path.endsWith('.md') ? 'markdown'
          : args.path.endsWith('.html') ? 'html' : 'text';
        return { ok: true, action: 'write', path: args.path, language: lang, content: args.content, lines: args.content.split('\n').length };
      }
      case 'editFile': {
        const f = currentFS[args.path];
        if (!f) return { ok: false, error: `File not found: ${args.path}` };
        if (!f.content.includes(args.oldText)) return { ok: false, error: `Text not found in ${args.path}` };
        const newContent = f.content.replace(args.oldText, args.newText);
        return { ok: true, action: 'edit', path: args.path, content: newContent, lines: newContent.split('\n').length };
      }
      case 'deleteFile': {
        if (!currentFS[args.path]) return { ok: false, error: `File not found: ${args.path}` };
        return { ok: true, action: 'delete', path: args.path };
      }
      case 'listFiles':
        return { ok: true, files: Object.entries(currentFS).map(([p, f]) => ({ path: p, language: f.language, lines: f.content.split('\n').length })) };
      case 'searchCode': {
        const results = [];
        const pat = args.pattern?.toLowerCase() || '';
        Object.entries(currentFS).forEach(([p, f]) => {
          f.content.split('\n').forEach((line, i) => {
            if (line.toLowerCase().includes(pat)) results.push({ file: p, line: i + 1, text: line.trim().slice(0, 120) });
          });
        });
        return { ok: true, pattern: args.pattern, matches: results.length, results: results.slice(0, 30) };
      }
      case 'runCommand': {
        return { ok: true, action: 'runCommand', command: args.command };
      }
      default:
        return { ok: false, error: `Unknown tool: ${name}` };
    }
  }, []);

  // ── Apply file mutations from tool calls ────────────────────────────────
  const applyToolMutations = useCallback((toolCalls, results, currentFS) => {
    let newFS = { ...currentFS };
    let changed = false;
    const cmdsToRun = [];
    toolCalls.forEach((tc, i) => {
      const r = results[i]?.result;
      if (!r?.ok) return;
      if (tc.name === 'writeFile') {
        newFS[tc.arguments.path] = { name: tc.arguments.path.split('/').pop(), language: r.language, content: tc.arguments.content };
        changed = true;
      } else if (tc.name === 'editFile' && r.content) {
        newFS[tc.arguments.path] = { ...newFS[tc.arguments.path], content: r.content };
        changed = true;
      } else if (tc.name === 'deleteFile') {
        delete newFS[tc.arguments.path];
        changed = true;
      } else if (tc.name === 'runCommand' && r.action === 'runCommand') {
        cmdsToRun.push(tc.arguments.command);
      }
    });
    return { newFS, changed, cmdsToRun };
  }, []);

  // ── Chat handler (agent-aware with tool loop) ──────────────────────────
  const handleAgentSubmit = useCallback((e) => {
    e.preventDefault();
    if (!chatInput.trim() || isTyping) return;
    const userMessage = chatInput.trim();
    const userMsg = { role: 'user', content: userMessage, agent: activeAgent, timestamp: Date.now() };
    setMessages(prev => [...prev, userMsg]);
    setConversations(prev => prev.map(c => c.id === activeConvoId ? { ...c, messages: [...c.messages, userMsg] } : c));
    setChatInput('');
    setIsTyping(true);

    const context = {
      activeFile,
      activeContent: fileSystem[activeFile]?.content || '',
      files: Object.entries(fileSystem).map(([p, f]) => ({ path: p, language: f.language, lines: f.content.split('\n').length })),
    };

    const convo = conversations.find(c => c.id === activeConvoId);
    const history = [...(convo?.messages || []), userMsg]
      .filter(m => m.role === 'user' || m.role === 'assistant')
      .slice(-20)
      .map(m => ({ role: m.role, content: m.content }));

    (async () => {
      let allSteps = [];
      let allToolCalls = [];
      let currentFS = { ...fileSystem };
      let pendingToolCalls = null;
      let toolResults = null;
      const MAX_ROUNDS = 8;

      try {
        for (let round = 0; round < MAX_ROUNDS; round++) {
          const payload = { agent: activeAgent, messages: history, context, mode: chatMode };
          if (toolResults && pendingToolCalls) {
            payload.toolResults = toolResults;
            payload.pendingToolCalls = pendingToolCalls;
          }

          const res = await fetch('/api/chat', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(payload),
          });
          const data = await res.json();
          if (!res.ok) throw new Error(data.error || `API error ${res.status}`);

          // If model returned text only, we're done
          if (data.type === 'text') {
            const assistantMsg = {
              role: 'assistant',
              content: data.content,
              agent: activeAgent,
              agentName: AGENT_REGISTRY[activeAgent]?.name || 'Agent',
              toolCalls: allToolCalls,
              steps: allSteps,
              mode: chatMode,
              timestamp: Date.now(),
            };
            setMessages(prev => [...prev, assistantMsg]);
            setConversations(prev => prev.map(c => c.id === activeConvoId ? { ...c, messages: [...c.messages, assistantMsg] } : c));
            return;
          }

          // Model wants to call tools
          if (data.type === 'tool_calls' && data.tool_calls?.length) {
            // Show thinking text if present
            if (data.content) {
              allSteps.push(`💭 ${data.content.slice(0, 200)}`);
            }

            // Execute each tool call locally
            toolResults = data.tool_calls.map(tc => {
              const result = executeToolCall(tc.name, tc.arguments, currentFS);
              const argSummary = tc.name === 'writeFile' ? `"${tc.arguments.path}" (${tc.arguments.content?.split('\n').length || 0} lines)`
                : tc.name === 'editFile' ? `"${tc.arguments.path}"`
                : tc.name === 'deleteFile' ? `"${tc.arguments.path}"`
                : tc.name === 'readFile' ? `"${tc.arguments.path}"`
                : tc.name === 'searchCode' ? `"${tc.arguments.pattern}"`
                : '';
              const icon = tc.name === 'writeFile' ? '📝' : tc.name === 'editFile' ? '✏️' : tc.name === 'deleteFile' ? '🗑️' : tc.name === 'readFile' ? '📖' : tc.name === 'searchCode' ? '🔍' : '📋';
              allSteps.push(`${icon} **${tc.name}**(${argSummary}) → ${result.ok ? '✅' : '❌ ' + result.error}`);
              allToolCalls.push({ tool: tc.name, args: tc.arguments });
              return { id: tc.id, name: tc.name, result };
            });

            // Apply filesystem mutations
            const { newFS, changed, cmdsToRun } = applyToolMutations(data.tool_calls, toolResults, currentFS);
            if (changed) {
              currentFS = newFS;
              setFileSystem(newFS);
              data.tool_calls.forEach(tc => {
                if (tc.name === 'writeFile') {
                  setOpenTabs(prev => prev.includes(tc.arguments.path) ? prev : [...prev, tc.arguments.path]);
                  setActiveFile(tc.arguments.path);
                }
              });
            }
            // Run terminal commands requested by agent
            if (cmdsToRun.length > 0) {
              setTerminalState('open');
              setActiveTerminalTab('terminal');
              cmdsToRun.forEach(cmd => handleTerminalCommandRef.current?.(cmd));
            }

            pendingToolCalls = data.tool_calls;

            // Update steps in real-time with a progress message
            setMessages(prev => {
              const progressMsg = prev.find(m => m._progress && m.agent === activeAgent);
              const msg = {
                role: 'assistant', _progress: true,
                content: `Working... (${allToolCalls.length} tool call${allToolCalls.length > 1 ? 's' : ''})`,
                agent: activeAgent, agentName: AGENT_REGISTRY[activeAgent]?.name || 'Agent',
                toolCalls: [...allToolCalls], steps: [...allSteps],
                mode: chatMode, timestamp: Date.now(),
              };
              return progressMsg ? prev.map(m => m._progress && m.agent === activeAgent ? msg : m) : [...prev, msg];
            });

            continue; // next round
          }

          // Unexpected response shape — treat as text
          const assistantMsg = {
            role: 'assistant',
            content: data.content || 'Done.',
            agent: activeAgent, agentName: AGENT_REGISTRY[activeAgent]?.name || 'Agent',
            toolCalls: allToolCalls, steps: allSteps, mode: chatMode, timestamp: Date.now(),
          };
          setMessages(prev => [...prev.filter(m => !m._progress), assistantMsg]);
          setConversations(prev => prev.map(c => c.id === activeConvoId ? { ...c, messages: [...c.messages, assistantMsg] } : c));
          return;
        }

        // Max rounds reached
        const finalMsg = {
          role: 'assistant',
          content: `Completed ${allToolCalls.length} operations (max rounds reached).`,
          agent: activeAgent, agentName: AGENT_REGISTRY[activeAgent]?.name || 'Agent',
          toolCalls: allToolCalls, steps: allSteps, mode: chatMode, timestamp: Date.now(),
        };
        setMessages(prev => [...prev.filter(m => !m._progress), finalMsg]);
        setConversations(prev => prev.map(c => c.id === activeConvoId ? { ...c, messages: [...c.messages, finalMsg] } : c));
      } catch (err) {
        // Fallback to local simulated response
        const tools = createAgentTools(fileSystem, activeFile);
        const { response: fallbackResponse } = buildAgentResponse(activeAgent, userMessage, tools, fileSystem, activeFile);
        const assistantMsg = {
          role: 'assistant',
          content: `⚠️ *API unavailable — using local mode*\n\n${fallbackResponse}`,
          agent: activeAgent, agentName: AGENT_REGISTRY[activeAgent]?.name || 'Agent',
          toolCalls: allToolCalls, steps: [...allSteps, `⚠️ API error: ${err.message}`],
          mode: chatMode, timestamp: Date.now(),
        };
        setMessages(prev => [...prev.filter(m => !m._progress), assistantMsg]);
        setConversations(prev => prev.map(c => c.id === activeConvoId ? { ...c, messages: [...c.messages, assistantMsg] } : c));
      } finally {
        setIsTyping(false);
      }
    })();
  }, [chatInput, isTyping, fileSystem, activeFile, activeAgent, activeConvoId, chatMode, executeToolCall, applyToolMutations, conversations]);

  const handleNewConversation = useCallback(() => {
    convoCountRef.current += 1;
    const newId = convoCountRef.current;
    const newConvo = { id: newId, name: `Chat ${newId}`, messages: [], agent: activeAgent };
    setConversations(prev => [...prev, newConvo]);
    setActiveConvoId(newId);
    setMessages([]);
    setShowConversations(false);
  }, [activeAgent]);

  const handleSwitchConversation = useCallback((id) => {
    setActiveConvoId(id);
    const convo = conversations.find(c => c.id === id);
    if (convo) {
      setMessages(convo.messages);
      setActiveAgent(convo.agent);
    }
    setShowConversations(false);
  }, [conversations]);

  // ── Build/Debug/Run handlers ──────────────────────────────────────────────
  const handleRunBuild = useCallback(() => {
    setTerminalState('open');
    setActiveTerminalTab('terminal');
    setOutputLog(buildOutput);
    setTerminalLines(prev => [...prev, 'ubuntu@epicode:~/workspace (main) $ npm run build', ...buildOutput, 'ubuntu@epicode:~/workspace (main) $ ']);
  }, [buildOutput]);

  const handleStartDebug = useCallback(() => {
    setTerminalState('open');
    setActiveTerminalTab('terminal');
    setTerminalLines(prev => [
      ...prev,
      `ubuntu@epicode:~/workspace (main) $ node --inspect ${fileSystem[activeFile]?.name || 'app.js'}`,
      'Debugger listening on ws://127.0.0.1:9229/abc123',
      'For help, see: https://nodejs.org/en/docs/inspector',
      'ubuntu@epicode:~/workspace (main) $ ',
    ]);
  }, [activeFile, fileSystem]);

  const handleRunActiveFile = useCallback(() => {
    const fileName = fileSystem[activeFile]?.name || 'file';
    setTerminalState('open');
    setActiveTerminalTab('terminal');
    setTerminalLines(prev => [...prev, `ubuntu@epicode:~/workspace (main) $ node ${fileName}`, `Running ${fileName}...`, 'Done.', 'ubuntu@epicode:~/workspace (main) $ ']);
  }, [activeFile, fileSystem]);

  // ── Terminal command handler ──────────────────────────────────────────────
  const handleTerminalCommand = useCallback((cmd) => {
    const prompt = 'ubuntu@epicode:~/workspace (main) $ ';
    const args = cmd.trim().split(/\s+/);
    const base = args[0];
    const fileList = Object.keys(fileSystem).join('  ');
    const responses = {
      clear: () => { setTerminalLines([]); return null; },
      ls: () => [`  ${fileList}`, 'index.html  node_modules/  package.json  postcss.config.js  tailwind.config.js  vite.config.js'],
      pwd: () => ['/workspaces/EpiCodeSpace'],
      whoami: () => ['ubuntu'],
      date: () => [new Date().toString()],
      echo: () => [args.slice(1).join(' ')],
      node: () => args[1] ? [`Running ${args[1]}...`, 'Done.'] : ['Welcome to Node.js v20.x.', 'Type ".exit" to exit'],
      git: () => {
        if (args[1] === 'status') return ['On branch main', 'Changes not staged for commit:', `  modified:   ${activeFile}`, '', `${Object.keys(fileSystem).length} files tracked`];
        if (args[1] === 'log') return ['commit a1b2c3d (HEAD -> main)', 'Author: EpiCodeSpace <dev@epicodespace.io>', 'Date:   ' + new Date().toDateString(), '', '    Initial commit'];
        if (args[1] === 'branch') return ['* main', '  dev', '  feature/ai-chat'];
        if (args[1] === 'diff') return [`diff --git a/${activeFile} b/${activeFile}`, '--- a/' + activeFile, '+++ b/' + activeFile, '@@ -1,4 +1,4 @@', '+ // latest changes'];
        if (args[1] === 'add') return args[2] ? [`Added ${args[2]} to staging area`] : ['Added all files to staging area'];
        if (args[1] === 'commit') return ['[main abc1234] ' + (args.includes('-m') ? args.slice(args.indexOf('-m') + 1).join(' ') : 'Commit'), ' 1 file changed, 1 insertion(+)'];
        if (args[1] === 'push') return ['Enumerating objects: 3, done.', 'Counting objects: 100% (3/3), done.', 'Writing objects: 100% (3/3), 312 bytes | 312.00 KiB/s', 'To github.com:epicodespace/project.git', '   abc1234..def5678  main -> main'];
        if (args[1] === 'pull') return ['Already up to date.'];
        if (args[1] === 'clone') return args[2] ? [`Cloning into '${args[2].split('/').pop()}'...`, 'remote: Enumerating objects: 42, done.', 'Receiving objects: 100% (42/42), done.'] : ['fatal: You must specify a repository to clone.'];
        if (args[1] === 'stash') return args[2] === 'pop' ? ['On branch main', 'Changes restored from stash'] : ['Saved working directory and index state WIP on main'];
        if (args[1] === 'remote') return ['origin  git@github.com:epicodespace/project.git (fetch)', 'origin  git@github.com:epicodespace/project.git (push)'];
        if (args[1] === 'checkout') return args[2] ? [`Switched to branch '${args[2]}'`] : ['error: please specify a branch'];
        return [`git: '${args[1] || ''}' is not a git command. See 'git --help'.`];
      },
      npm: () => {
        if (args[1] === 'run' && args[2] === 'build') { handleRunBuild(); return null; }
        if (args[1] === 'run' && args[2] === 'dev') return ['', '  VITE v6.0.0  ready in 312 ms', '', '  ➜  Local:   http://localhost:5173/', '  ➜  Network: use --host to expose'];
        if (args[1] === 'install' || args[1] === 'i') return ['added 127 packages, audited 128 packages in 4s', '24 packages are looking for funding', '  run `npm fund` for details', 'found 0 vulnerabilities'];
        if (args[1] === 'test') return ['> epicodespace@1.0.0 test', '> vitest run', '', 'PASS  src/__tests__/App.test.jsx', '  ✓ renders welcome message (12ms)', '', 'Test Suites: 1 passed, 1 total', 'Tests:       1 passed, 1 total'];
        if (args[1] === 'list' || args[1] === 'ls') return Object.keys(fileSystem).map(f => `  └── ${f}`);
        if (args[1] === 'init') return ['Wrote to /workspaces/EpiCodeSpace/package.json'];
        return [`npm: unknown command '${args.slice(1).join(' ')}'`];
      },
      cat: () => {
        const target = args[1];
        if (target && fileSystem[target]) return [fileSystem[target].content];
        return [`cat: ${target || '(no file)'}: No such file or directory`];
      },
      touch: () => {
        if (!args[1]) return ['touch: missing file operand'];
        if (!fileSystem[args[1]]) {
          setFileSystem(prev => ({ ...prev, [args[1]]: { name: args[1], language: 'text', content: '' } }));
          setOpenTabs(prev => [...prev, args[1]]);
          setActiveFile(args[1]);
        }
        return [`Created: ${args[1]}`];
      },
      mkdir: () => args[1] ? [`mkdir: directory '${args[1]}' created (virtual)`] : ['mkdir: missing operand'],
      rm: () => {
        if (!args[1]) return ['rm: missing operand'];
        const target = args[1] === '-rf' ? args[2] : args[1];
        if (target && fileSystem[target]) {
          setFileSystem(prev => { const n = { ...prev }; delete n[target]; return n; });
          setOpenTabs(prev => prev.filter(t => t !== target));
          return [`Removed: ${target}`];
        }
        return [`rm: cannot remove '${target}': No such file or directory`];
      },
      mv: () => {
        if (!args[1] || !args[2]) return ['mv: missing operand'];
        if (fileSystem[args[1]]) {
          setFileSystem(prev => {
            const n = { ...prev };
            n[args[2]] = { ...n[args[1]], name: args[2].split('/').pop() };
            delete n[args[1]];
            return n;
          });
          setOpenTabs(prev => prev.map(t => t === args[1] ? args[2] : t));
          setActiveFile(cur => cur === args[1] ? args[2] : cur);
          return [`Renamed ${args[1]} → ${args[2]}`];
        }
        return [`mv: cannot stat '${args[1]}': No such file`];
      },
      cp: () => {
        if (!args[1] || !args[2]) return ['cp: missing operand'];
        if (fileSystem[args[1]]) {
          setFileSystem(prev => ({ ...prev, [args[2]]: { ...prev[args[1]], name: args[2].split('/').pop() } }));
          return [`Copied ${args[1]} → ${args[2]}`];
        }
        return [`cp: cannot stat '${args[1]}': No such file`];
      },
      grep: () => {
        if (!args[1]) return ['Usage: grep <pattern> [file]'];
        const pattern = args[1];
        const target = args[2];
        const results = [];
        const files = target && fileSystem[target] ? { [target]: fileSystem[target] } : fileSystem;
        Object.entries(files).forEach(([p, f]) => {
          f.content.split('\n').forEach((line, i) => {
            if (line.includes(pattern)) results.push(`${p}:${i + 1}: ${line.trim()}`);
          });
        });
        return results.length > 0 ? results : [`No matches for '${pattern}'`];
      },
      wc: () => {
        if (!args[1]) return ['Usage: wc <file>'];
        const target = args.find(a => fileSystem[a]);
        if (target) {
          const c = fileSystem[target].content;
          return [`  ${c.split('\n').length}  ${c.split(/\s+/).length}  ${c.length} ${target}`];
        }
        return [`wc: ${args[1]}: No such file`];
      },
      head: () => {
        const target = args[1];
        if (target && fileSystem[target]) return fileSystem[target].content.split('\n').slice(0, 10);
        return [`head: ${target || '(no file)'}: No such file`];
      },
      tail: () => {
        const target = args[1];
        if (target && fileSystem[target]) return fileSystem[target].content.split('\n').slice(-10);
        return [`tail: ${target || '(no file)'}: No such file`];
      },
      history: () => terminalLines.filter(l => l.startsWith('ubuntu@')).map((l, i) => `  ${i + 1}  ${l.replace('ubuntu@epicode:~/workspace (main) $ ', '')}`).slice(-20),
      env: () => ['NODE_ENV=development', 'PORT=5173', 'HOME=/home/ubuntu', 'SHELL=/bin/bash', 'TERM=xterm-256color', 'LANG=en_US.UTF-8'],
      which: () => args[1] ? [`/usr/bin/${args[1]}`] : ['Usage: which <command>'],
      curl: () => args[1] ? ['HTTP/1.1 200 OK', 'Content-Type: application/json', '', '{"status":"ok","message":"EpiCodeSpace API running"}'] : ['curl: try \'curl --help\' for more information'],
      ping: () => args[1] ? [`PING ${args[1]} (127.0.0.1) 56(84) bytes of data.`, `64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.035 ms`, `--- ${args[1]} ping statistics ---`, '1 packets transmitted, 1 received, 0% packet loss'] : ['ping: usage error'],
      uptime: () => [' 14:32:01 up 42 days,  3:17,  1 user,  load average: 0.12, 0.08, 0.01'],
      df: () => ['Filesystem     1K-blocks     Used Available Use% Mounted on', '/dev/sda1       41943040 12582912  29360128  30% /'],
      free: () => ['              total        used        free      shared  buff/cache   available', 'Mem:        8053696     2013424     4026848       65536     2013424     5786272'],
      uname: () => ['Linux epicodespace 5.15.0-1052-azure #60-Ubuntu SMP x86_64 GNU/Linux'],
      exit: () => { setTerminalState('closed'); return null; },
      python: () => ['Python 3.11.4', '>>> (interactive mode not available in EpiCodeSpace)'],
      docker: () => {
        if (args[1] === 'ps') return ['CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS   PORTS   NAMES'];
        if (args[1] === 'images') return ['REPOSITORY   TAG       IMAGE ID   CREATED   SIZE'];
        return ['Usage: docker [command]'];
      },
      deploy: () => {
        const target = args[1] || 'vercel';
        if (target === 'vercel' || target === '--vercel') {
          // Generate a deployable bundle and download it
          const files = Object.entries(fileSystem);
          if (files.length === 0) return ['Error: No files to deploy. Create some files first.'];
          setOutputLog(prev => [...prev, '', '> deploy --vercel', '⏳ Preparing deployment bundle...']);
          const pkg = fileSystem['package.json'];
          const bundle = {};
          files.forEach(([p, f]) => { bundle[p] = f.content; });
          // Add vercel.json if not present
          if (!bundle['vercel.json']) bundle['vercel.json'] = JSON.stringify({ buildCommand: "npm run build", outputDirectory: "dist", framework: "vite" }, null, 2);
          const blob = new Blob([JSON.stringify(bundle, null, 2)], { type: 'application/json' });
          const url = URL.createObjectURL(blob);
          const a = document.createElement('a');
          a.href = url;
          a.download = `${projectName.replace(/[^a-zA-Z0-9-_]/g, '_')}-deploy.json`;
          a.click();
          URL.revokeObjectURL(url);
          setTimeout(() => setOutputLog(prev => [...prev, '✓ Bundle exported!', '', 'To deploy on Vercel:', '  1. Go to https://vercel.com/new', '  2. Import your Git repository or drag & drop the project files', '  3. Vercel auto-detects framework and deploys', '', 'Or use the Vercel CLI:', '  $ npm i -g vercel', '  $ vercel --prod']), 500);
          return [
            '⏳ Preparing for Vercel deployment...',
            `📦 Bundling ${files.length} files from "${projectName}"...`,
            '✓ Bundle downloaded!',
            '',
            'To deploy to Vercel:',
            '  1. Push your code to GitHub/GitLab/Bitbucket',
            '  2. Go to https://vercel.com/new and import the repo',
            '  3. Vercel auto-detects settings and deploys',
            '',
            'Or use the Vercel CLI:',
            '  $ npm i -g vercel && vercel --prod',
          ];
        }
        if (target === 'netlify' || target === '--netlify') {
          return [
            '📦 Netlify deployment guide:',
            '  1. Push code to GitHub',
            '  2. Go to https://app.netlify.com/start',
            '  3. Connect your repository',
            '  4. Set build command: npm run build',
            '  5. Set publish directory: dist',
            '  6. Click Deploy',
            '',
            'Or drag & drop the dist folder at https://app.netlify.com/drop',
          ];
        }
        if (target === 'github-pages' || target === '--gh-pages') {
          return [
            '📦 GitHub Pages deployment guide:',
            '  1. In your vite.config.js, set base: "/<repo-name>/"',
            '  2. npm run build',
            '  3. git add dist -f && git commit -m "deploy"',
            '  4. git subtree push --prefix dist origin gh-pages',
            '',
            'Or use GitHub Actions for automatic deployment.',
          ];
        }
        return [
          'Usage: deploy <platform>',
          '  deploy vercel      Deploy to Vercel (recommended)',
          '  deploy netlify     Deploy to Netlify',
          '  deploy github-pages Deploy to GitHub Pages',
        ];
      },
      export: () => {
        handleExportProject();
        return [`✓ Exporting project "${projectName}" as .epicode.json...`, 'Download started.'];
      },
      help: () => [
        'Available commands:',
        '  ls, pwd, whoami, date, echo, clear, help, exit, history, env, uname, uptime, df, free',
        '  cat <file>, touch <file>, mkdir <dir>, rm <file>, mv <src> <dst>, cp <src> <dst>',
        '  head <file>, tail <file>, wc <file>, grep <pattern> [file], which <cmd>',
        '  git status|log|branch|diff|add|commit|push|pull|clone|stash|remote|checkout',
        '  npm run dev|build|test | npm install|list|init',
        '  node <file>, python, docker ps|images, curl <url>, ping <host>',
        '  deploy vercel|netlify|github-pages  — deployment guides & bundle export',
        '  export  — export project as downloadable file',
      ],
    };
    const handler = responses[base];
    if (handler) {
      const output = handler();
      if (output === null) return;
      setTerminalLines(prev => [...prev, `${prompt}${cmd}`, ...output, prompt]);
    } else {
      setTerminalLines(prev => [...prev, `${prompt}${cmd}`, `bash: ${base}: command not found — type 'help' for available commands`, prompt]);
    }
  }, [fileSystem, activeFile, handleRunBuild, terminalLines, projectName, handleExportProject]);

  // Keep ref in sync so handleAgentSubmit can call it without a forward-reference TDZ
  handleTerminalCommandRef.current = handleTerminalCommand;

  // ── Line numbers ──────────────────────────────────────────────────────────
  const getLineNumbers = useMemo(() => {
    const content = fileSystem[activeFile]?.content ?? '';
    return content.split('\n').map((_, i) => i + 1).join('\n');
  }, [fileSystem, activeFile]);

  // ── Menu definitions ──────────────────────────────────────────────────────
  const menuDefinitions = useMemo(() => ({
    File: [
      { label: 'New File', shortcut: 'Ctrl+N', icon: FilePlus, action: handleNewFile },
      { label: 'New Project...', icon: FolderOpen, action: () => { const t = prompt('Project template: react, node, html, or empty', 'react'); if (t) handleNewProject(t); } },
      { label: 'New Window', shortcut: 'Ctrl+Shift+N', disabled: true },
      { type: 'separator' },
      { label: 'Open Project...', icon: FolderOpen, action: handleImportProject },
      { type: 'separator' },
      { label: 'Save', shortcut: 'Ctrl+S', icon: Save, action: handleSave },
      { label: 'Save As...', shortcut: 'Ctrl+Shift+S', disabled: true },
      { label: 'Save All', shortcut: 'Ctrl+K S', action: handleSave },
      { type: 'separator' },
      { label: 'Export Project...', action: handleExportProject },
      { label: 'Deploy to Vercel', icon: Globe, action: () => { setTerminalState('open'); setActiveTerminalTab('terminal'); handleTerminalCommand('deploy vercel'); } },
      { label: 'Deploy to Netlify', icon: Globe, action: () => { setTerminalState('open'); setActiveTerminalTab('terminal'); handleTerminalCommand('deploy netlify'); } },
      { type: 'separator' },
      { label: 'Close Editor', shortcut: 'Ctrl+W', action: () => setActiveFile(Object.keys(fileSystem)[0] || null) },
    ],
    Edit: [
      { label: 'Undo', shortcut: 'Ctrl+Z', icon: Undo2, disabled: true },
      { label: 'Redo', shortcut: 'Ctrl+Y', icon: Redo2, disabled: true },
      { type: 'separator' },
      { label: 'Cut', shortcut: 'Ctrl+X', icon: Scissors, action: editorCut },
      { label: 'Copy', shortcut: 'Ctrl+C', icon: Copy, action: editorCopy },
      { label: 'Paste', shortcut: 'Ctrl+V', icon: Clipboard, action: editorPaste },
      { type: 'separator' },
      { label: 'Find', shortcut: 'Ctrl+F', icon: Search, action: () => setShowFind(true) },
      { label: 'Replace', shortcut: 'Ctrl+H', disabled: true },
      { type: 'separator' },
      { label: 'Select All', shortcut: 'Ctrl+A', action: editorSelectAll },
      { type: 'separator' },
      { label: 'Toggle Line Comment', shortcut: 'Ctrl+/', disabled: true },
      { label: 'Format Document', shortcut: 'Shift+Alt+F', disabled: true },
    ],
    Selection: [
      { label: 'Select All', shortcut: 'Ctrl+A', action: editorSelectAll },
      { label: 'Expand Selection', shortcut: 'Shift+Alt+→', disabled: true },
      { label: 'Shrink Selection', shortcut: 'Shift+Alt+←', disabled: true },
      { type: 'separator' },
      { label: 'Copy Line Up', shortcut: 'Shift+Alt+↑', disabled: true },
      { label: 'Copy Line Down', shortcut: 'Shift+Alt+↓', disabled: true },
      { label: 'Move Line Up', shortcut: 'Alt+↑', disabled: true },
      { label: 'Move Line Down', shortcut: 'Alt+↓', disabled: true },
      { type: 'separator' },
      { label: 'Add Cursor Above', shortcut: 'Ctrl+Alt+↑', disabled: true },
      { label: 'Add Cursor Below', shortcut: 'Ctrl+Alt+↓', disabled: true },
      { label: 'Select All Occurrences', shortcut: 'Ctrl+Shift+L', disabled: true },
    ],
    View: [
      { label: 'Command Palette', shortcut: 'Ctrl+Shift+P', disabled: true },
      { type: 'separator' },
      { label: 'Explorer', shortcut: 'Ctrl+Shift+E', action: () => setSidebarOpen(p => !p) },
      { label: 'AI Chat Panel', action: () => setRightSidebarOpen(p => !p) },
      { type: 'separator' },
      { label: 'Terminal', shortcut: 'Ctrl+`', action: () => setTerminalState(p => p === 'open' ? 'closed' : 'open') },
      { type: 'separator' },
      { label: 'Word Wrap', shortcut: 'Alt+Z', action: () => setWordWrap(p => !p) },
      { type: 'separator' },
      { label: 'Zoom In', shortcut: 'Ctrl+=', icon: ZoomIn, action: () => setFontSize(p => Math.min(p + 1, 28)) },
      { label: 'Zoom Out', shortcut: 'Ctrl+-', icon: ZoomOut, action: () => setFontSize(p => Math.max(p - 1, 10)) },
      { label: 'Reset Zoom', shortcut: 'Ctrl+0', action: () => setFontSize(13) },
    ],
    Go: [
      { label: 'Back', shortcut: 'Alt+←', disabled: true },
      { label: 'Forward', shortcut: 'Alt+→', disabled: true },
      { type: 'separator' },
      { label: 'Go to File...', shortcut: 'Ctrl+P', disabled: true },
      { label: 'Go to Symbol...', shortcut: 'Ctrl+Shift+O', disabled: true },
      { label: 'Go to Definition', shortcut: 'F12', disabled: true },
      { label: 'Go to Line/Column...', shortcut: 'Ctrl+G', disabled: true },
      { type: 'separator' },
      { label: 'Next Problem', shortcut: 'F8', disabled: true },
      { label: 'Previous Problem', shortcut: 'Shift+F8', disabled: true },
    ],
    Run: [
      { label: 'Start Debugging', shortcut: 'F5', icon: Bug, action: handleStartDebug },
      { label: 'Run Without Debugging', shortcut: 'Ctrl+F5', action: handleStartDebug },
      { label: 'Stop Debugging', shortcut: 'Shift+F5', icon: Square, disabled: true },
      { type: 'separator' },
      { label: 'Add Configuration...', disabled: true },
      { label: 'Toggle Breakpoint', shortcut: 'F9', disabled: true },
      { type: 'separator' },
      { label: 'Run Build Task', shortcut: 'Ctrl+Shift+B', action: handleRunBuild },
    ],
    Terminal: [
      { label: 'New Terminal', shortcut: 'Ctrl+Shift+`', action: () => { setTerminalState('open'); setActiveTerminalTab('terminal'); } },
      { label: 'Split Terminal', shortcut: 'Ctrl+Shift+5', disabled: true },
      { type: 'separator' },
      { label: 'Run Active File', action: handleRunActiveFile },
      { label: 'Run Selected Text', disabled: true },
      { type: 'separator' },
      { label: 'Clear Terminal', action: () => setTerminalLines([]) },
    ],
    Help: [
      { label: 'Welcome', disabled: true },
      { label: 'Documentation', icon: BookOpen, disabled: true },
      { label: 'Release Notes', disabled: true },
      { type: 'separator' },
      { label: 'Keyboard Shortcuts', shortcut: 'Ctrl+K Ctrl+S', disabled: true },
      { type: 'separator' },
      { label: 'Toggle Developer Tools', disabled: true },
      { type: 'separator' },
      { label: 'About EpiCodeSpace', icon: Info, action: () => setShowAbout(true) },
    ],
  }), [handleNewFile, handleNewProject, handleImportProject, handleExportProject, handleSave, handleTerminalCommand, editorCut, editorCopy, editorPaste, editorSelectAll, handleStartDebug, handleRunBuild, handleRunActiveFile, fileSystem]);

  // ═════════════════════════════════════════════════════════════════════════
  //  RENDER
  // ═════════════════════════════════════════════════════════════════════════
  return (
    <div className="flex flex-col h-screen bg-[#0a0412] text-purple-100 font-sans overflow-hidden selection:bg-fuchsia-500/30">

      {isDragging && <div className={`fixed inset-0 z-50 ${isDragging === 'terminal' ? 'cursor-row-resize' : 'cursor-col-resize'}`} style={{ touchAction: 'none' }} />}

      {/* ── Top Bar ───────────────────────────────────────────────────────── */}
      <header className="flex items-center justify-between px-2 sm:px-3 h-11 sm:h-12 bg-[#15092a] border-b border-fuchsia-500/20 z-20 shrink-0 shadow-[0_4px_20px_rgba(192,38,211,0.05)]" style={{ paddingTop: 'var(--sat)' }}>
        <div className="flex items-center gap-1.5 sm:gap-2 text-sm">
          <button onClick={() => setSidebarOpen(!sidebarOpen)} aria-label="Toggle Explorer" className="p-2 sm:p-1.5 hover:bg-[#25104a] rounded-md transition-colors text-purple-300">
            <Menu size={18} />
          </button>
          <div className="flex items-center gap-1.5 sm:gap-2 text-fuchsia-50 font-semibold px-1 sm:px-2">
            <Cpu className="text-fuchsia-400 drop-shadow-[0_0_8px_rgba(232,121,249,0.6)]" size={sm ? 16 : 18} />
            <span className="tracking-wide font-bold bg-clip-text text-transparent bg-gradient-to-r from-fuchsia-300 to-purple-300 text-xs sm:text-sm">EpiCodeSpace</span>
          </div>
          <div ref={menuBarRef} className="hidden md:flex items-center gap-1 ml-4 text-purple-300/80 relative">
            {Object.keys(menuDefinitions).map(menuName => (
              <div key={menuName} className="relative">
                <span
                  onClick={() => setActiveMenu(activeMenu === menuName ? null : menuName)}
                  className={`px-2 py-1 rounded-md cursor-pointer text-xs transition-colors select-none ${activeMenu === menuName ? 'bg-[#25104a] text-purple-100' : 'hover:bg-[#25104a] hover:text-purple-100'}`}
                >
                  {menuName}
                </span>
                {activeMenu === menuName && (
                  <div className="absolute top-full left-0 mt-0.5 w-64 bg-[#1a0b35] border border-fuchsia-500/30 rounded-lg shadow-[0_8px_32px_rgba(0,0,0,0.7)] z-50 py-1 overflow-hidden">
                    {menuDefinitions[menuName].map((item, idx) =>
                      item.type === 'separator'
                        ? <div key={idx} className="my-1 border-t border-fuchsia-500/15" />
                        : (
                          <button
                            key={idx}
                            disabled={item.disabled}
                            onClick={() => { if (item.action) item.action(); setActiveMenu(null); }}
                            className={`w-full flex items-center justify-between px-3 py-1.5 text-xs transition-colors ${item.disabled ? 'text-purple-500/35 cursor-not-allowed' : 'text-purple-200 hover:bg-fuchsia-500/15 hover:text-purple-50 cursor-pointer'}`}
                          >
                            <span className="flex items-center gap-2.5">
                              {item.icon ? <item.icon size={13} className="text-fuchsia-400/70 shrink-0" /> : <span className="w-[13px] shrink-0" />}
                              {item.label}
                            </span>
                            {item.shortcut && <span className="text-[10px] text-purple-500/55 ml-4 shrink-0 font-mono">{item.shortcut}</span>}
                          </button>
                        )
                    )}
                  </div>
                )}
              </div>
            ))}
          </div>
        </div>
        <div className="flex items-center gap-1 sm:gap-2">
          <button
            onClick={() => setRightSidebarOpen(!rightSidebarOpen)}
            className={`p-2 sm:p-1.5 rounded-md transition-colors ${rightSidebarOpen ? 'bg-fuchsia-500/20 text-fuchsia-300' : 'hover:bg-[#25104a] text-purple-300'}`}
            aria-label="Toggle AI Chat"
          >
            {sm ? <MessageSquare size={18} /> : <Layout size={18} />}
          </button>
        </div>
      </header>

      {/* ── Main Workspace ────────────────────────────────────────────────── */}
      <div className="flex flex-1 overflow-hidden relative">

        {/* Left Sidebar */}
        {sidebarOpen && (
          <>
            {sm && <div className="sidebar-backdrop" onClick={() => setSidebarOpen(false)} />}
            <aside className="absolute md:relative z-10 h-full bg-[#15092a] border-r border-fuchsia-500/20 flex flex-col shrink-0 panel-transition" style={{ width: sm ? Math.min(leftWidth, screenWidth * 0.85) : leftWidth }}>
              {!sm && <div className="absolute top-0 -right-[2px] w-1.5 h-full cursor-col-resize drag-handle hover:bg-fuchsia-400/50 active:bg-fuchsia-400 z-20 transition-colors" onMouseDown={(e) => { e.preventDefault(); setIsDragging('left'); }} onTouchStart={(e) => { e.preventDefault(); setIsDragging('left'); }} />}
            <div className="px-4 py-2.5 flex justify-between items-center text-[10px] font-bold text-fuchsia-400/70 uppercase tracking-widest">
              <span>Explorer</span>
              <div className="flex items-center gap-0.5">
                <button onClick={handleNewFile} aria-label="New file" className="p-1 hover:text-fuchsia-300 transition-colors" title="New File"><FilePlus size={13}/></button>
                <button onClick={handleImportProject} aria-label="Import project" className="p-1 hover:text-fuchsia-300 transition-colors" title="Import Project"><FolderOpen size={13}/></button>
                <button onClick={handleExportProject} aria-label="Export project" className="p-1 hover:text-fuchsia-300 transition-colors" title="Export Project"><Save size={13}/></button>
              </div>
            </div>
            <div className="p-1 flex-1 overflow-y-auto -webkit-overflow-scrolling-touch">
              <div className="px-2 py-1 flex items-center gap-1 text-xs font-semibold text-purple-200 mb-1">
                <ChevronDown size={14} />
                <span className="tracking-wide uppercase truncate" title={projectName} onDoubleClick={() => { const name = prompt('Rename project:', projectName); if (name) setProjectName(name); }}>{projectName}</span>
              </div>
              {Object.keys(fileSystem).length === 0 ? (
                <div className="px-4 py-6 text-center">
                  <div className="text-purple-500/50 text-xs mb-4">No files yet</div>
                  <div className="space-y-2">
                    <button onClick={handleNewFile} className="w-full text-[11px] text-purple-300 hover:text-purple-100 bg-white/5 hover:bg-white/10 border border-white/10 rounded-lg px-3 py-2 transition-colors flex items-center gap-2 justify-center"><FilePlus size={12}/> New File</button>
                    <button onClick={() => handleNewProject('react')} className="w-full text-[11px] text-purple-300 hover:text-purple-100 bg-white/5 hover:bg-white/10 border border-white/10 rounded-lg px-3 py-2 transition-colors">⚛️ React Project</button>
                    <button onClick={() => handleNewProject('node')} className="w-full text-[11px] text-purple-300 hover:text-purple-100 bg-white/5 hover:bg-white/10 border border-white/10 rounded-lg px-3 py-2 transition-colors">🟢 Node.js Project</button>
                    <button onClick={() => handleNewProject('html')} className="w-full text-[11px] text-purple-300 hover:text-purple-100 bg-white/5 hover:bg-white/10 border border-white/10 rounded-lg px-3 py-2 transition-colors">🌐 HTML/CSS/JS Project</button>
                    <button onClick={handleImportProject} className="w-full text-[11px] text-purple-300 hover:text-purple-100 bg-white/5 hover:bg-white/10 border border-white/10 rounded-lg px-3 py-2 transition-colors flex items-center gap-2 justify-center"><FolderOpen size={12}/> Import Project</button>
                  </div>
                </div>
              ) : (() => {
                // Group files by directory
                const folders = {};
                const rootFiles = [];
                Object.keys(fileSystem).forEach(path => {
                  const parts = path.split('/');
                  if (parts.length > 1) {
                    const dir = parts.slice(0, -1).join('/');
                    if (!folders[dir]) folders[dir] = [];
                    folders[dir].push(path);
                  } else {
                    rootFiles.push(path);
                  }
                });
                return (
                  <>
                    {rootFiles.map(path => {
                      const fileName = path.split('/').pop();
                      const isActive = activeFile === path;
                      return (
                        <div key={path} className="group">
                          {renamingFile === path ? (
                            <form onSubmit={(e) => { e.preventDefault(); handleRenameFile(path, renameValue); }} className="flex ml-2 px-2 py-1">
                              <input autoFocus value={renameValue} onChange={(e) => setRenameValue(e.target.value)} onBlur={() => setRenamingFile(null)} className="bg-[#0a0412] border border-fuchsia-500/40 text-purple-100 text-xs px-2 py-0.5 rounded w-full outline-none" />
                            </form>
                          ) : (
                            <div className="flex items-center">
                              <button onClick={() => handleFileClick(path)} className={`flex-1 flex items-center gap-2 px-3 py-2 sm:py-1 ml-2 text-xs rounded-md transition-colors ${isActive ? 'bg-fuchsia-500/15 text-fuchsia-100 shadow-[inset_2px_0_0_rgba(232,121,249,1)]' : 'text-purple-300 hover:bg-[#25104a] hover:text-purple-100'}`}>
                                <File size={13} className={isActive ? (path.endsWith('.md') ? "text-cyan-400" : "text-fuchsia-400") : ""} />
                                <span className="truncate">{fileName}</span>
                              </button>
                              <div className="flex gap-0.5 pr-1 opacity-0 group-hover:opacity-100 transition-opacity">
                                <button onClick={() => { setRenamingFile(path); setRenameValue(path); }} className="p-0.5 text-purple-500/40 hover:text-purple-200" title="Rename"><FileEdit size={11}/></button>
                                <button onClick={() => handleDeleteFile(path)} className="p-0.5 text-purple-500/40 hover:text-red-400" title="Delete"><Trash2 size={11}/></button>
                              </div>
                            </div>
                          )}
                        </div>
                      );
                    })}
                    {Object.entries(folders).map(([dir, files]) => (
                      <div key={dir}>
                        <div className="flex items-center gap-1 px-4 py-1 text-xs text-purple-400/80">
                          <ChevronDown size={14} />
                          <Folder size={14} className="text-fuchsia-400" />
                          <span>{dir}</span>
                        </div>
                        {files.map(path => {
                          const fileName = path.split('/').pop();
                          const isActive = activeFile === path;
                          return (
                            <div key={path} className="group">
                              {renamingFile === path ? (
                                <form onSubmit={(e) => { e.preventDefault(); handleRenameFile(path, renameValue); }} className="flex ml-8 px-2 py-1">
                                  <input autoFocus value={renameValue} onChange={(e) => setRenameValue(e.target.value)} onBlur={() => setRenamingFile(null)} className="bg-[#0a0412] border border-fuchsia-500/40 text-purple-100 text-xs px-2 py-0.5 rounded w-full outline-none" />
                                </form>
                              ) : (
                                <div className="flex items-center">
                                  <button onClick={() => handleFileClick(path)} className={`flex-1 flex items-center gap-2 px-3 py-2 sm:py-1 ml-6 text-xs rounded-md transition-colors ${isActive ? 'bg-fuchsia-500/15 text-fuchsia-100 shadow-[inset_2px_0_0_rgba(232,121,249,1)]' : 'text-purple-300 hover:bg-[#25104a] hover:text-purple-100'}`}>
                                    <File size={13} className={isActive ? (path.endsWith('.md') ? "text-cyan-400" : "text-fuchsia-400") : ""} />
                                    <span className="truncate">{fileName}</span>
                                  </button>
                                  <div className="flex gap-0.5 pr-1 opacity-0 group-hover:opacity-100 transition-opacity">
                                    <button onClick={() => { setRenamingFile(path); setRenameValue(path); }} className="p-0.5 text-purple-500/40 hover:text-purple-200" title="Rename"><FileEdit size={11}/></button>
                                    <button onClick={() => handleDeleteFile(path)} className="p-0.5 text-purple-500/40 hover:text-red-400" title="Delete"><Trash2 size={11}/></button>
                                  </div>
                                </div>
                              )}
                            </div>
                          );
                        })}
                      </div>
                    ))}
                  </>
                );
              })()}
            </div>
          </aside>
          </>
        )}

        {/* Middle Column */}
        <main className="flex-1 flex flex-col min-w-0 bg-[#0a0412]">
          <div className="flex-1 flex flex-col min-h-0">
            {/* Editor Tabs */}
            <div className="flex bg-[#15092a] overflow-x-auto no-scrollbar border-b border-fuchsia-500/20 shrink-0">
              {openTabs.map(path => {
                const isActive = activeFile === path;
                const file = fileSystem[path];
                if (!file) return null;
                return (
                  <div
                    key={path}
                    onClick={() => setActiveFile(path)}
                    className={`flex items-center gap-2 px-4 py-2 border-r border-fuchsia-500/20 min-w-max cursor-pointer transition-colors group ${isActive ? 'bg-[#0a0412] border-t-2 border-t-cyan-400 text-fuchsia-50 shadow-[0_-2px_10px_rgba(34,211,238,0.1)]' : 'text-purple-400/70 hover:bg-[#25104a] hover:text-purple-200 border-t-2 border-t-transparent'}`}
                  >
                    <File size={13} className={isActive ? 'text-cyan-400' : 'text-fuchsia-400/50'} />
                    <span className="text-xs">{file.name}</span>
                    <X size={13} onClick={(e) => handleCloseTab(path, e)} className="ml-1 text-purple-400/30 hover:text-fuchsia-300 opacity-0 group-hover:opacity-100 transition-all cursor-pointer" />
                  </div>
                );
              })}
              <div className="flex-1 flex justify-end items-center px-2">
                <button onClick={handleNewFile} className="p-1 hover:bg-[#25104a] rounded text-purple-400/70 transition-colors"><Plus size={14}/></button>
              </div>
            </div>

            {/* Text Editor */}
            <div className="flex-1 flex overflow-hidden relative">
              {!activeFile || !fileSystem[activeFile] ? (
                <div className="flex-1 flex flex-col items-center justify-center text-purple-500/40 gap-4">
                  <Cpu size={48} className="text-fuchsia-400/20" />
                  <div className="text-lg font-semibold text-purple-300/30">EpiCodeSpace</div>
                  <div className="text-xs text-purple-500/30">Create or open a file to start coding</div>
                  <div className="flex gap-2 mt-2">
                    <button onClick={handleNewFile} className="text-xs text-purple-300 hover:text-purple-100 bg-white/5 hover:bg-white/10 border border-white/10 rounded-lg px-4 py-2 transition-colors flex items-center gap-2"><FilePlus size={12}/> New File</button>
                    <button onClick={() => handleNewProject('react')} className="text-xs text-purple-300 hover:text-purple-100 bg-white/5 hover:bg-white/10 border border-white/10 rounded-lg px-4 py-2 transition-colors">⚛️ React</button>
                    <button onClick={() => handleNewProject('node')} className="text-xs text-purple-300 hover:text-purple-100 bg-white/5 hover:bg-white/10 border border-white/10 rounded-lg px-4 py-2 transition-colors">🟢 Node</button>
                  </div>
                </div>
              ) : (
              <>
              {showFind && (
                <div className="absolute top-2 right-4 z-30 bg-[#1a0b35] border border-fuchsia-500/30 rounded-lg shadow-xl flex items-center gap-2 px-3 py-2">
                  <Search size={13} className="text-fuchsia-400 shrink-0" />
                  <input autoFocus type="text" value={findQuery} onChange={(e) => setFindQuery(e.target.value)} placeholder="Find..." className="bg-transparent text-purple-100 text-xs outline-none placeholder:text-purple-500/50 w-44" />
                  <span className="text-purple-500/50 text-[10px] min-w-[60px]">
                    {findQuery ? `${(fileSystem[activeFile]?.content ?? '').split(findQuery).length - 1} match(es)` : 'Type to search'}
                  </span>
                  <button onClick={() => { setShowFind(false); setFindQuery(''); }} className="text-purple-400/60 hover:text-fuchsia-300 transition-colors ml-1"><X size={13} /></button>
                </div>
              )}
              <div className="w-12 bg-[#0a0412] border-r border-fuchsia-500/10 text-right pr-3 pt-4 text-xs text-purple-500/40 font-mono select-none overflow-hidden h-full">
                <pre className="m-0 leading-relaxed" aria-hidden="true">{getLineNumbers}</pre>
              </div>
              <textarea
                ref={editorRef}
                value={fileSystem[activeFile]?.content ?? ''}
                onChange={handleEditorChange}
                onKeyUp={handleCursorMove}
                onClick={handleCursorMove}
                onSelect={handleCursorMove}
                spellCheck={false}
                aria-label={`Editor: ${fileSystem[activeFile]?.name}`}
                aria-multiline="true"
                className="flex-1 w-full h-full bg-[#0a0412] text-purple-100 font-mono leading-relaxed p-4 resize-none focus:outline-none border-none overflow-auto"
                style={{ tabSize: 2, fontSize, whiteSpace: wordWrap ? 'pre-wrap' : 'pre' }}
              />
              </>
              )}
            </div>
          </div>

          {/* Terminal Pane */}
          {terminalState === 'open' && (
            <div className="border-t border-fuchsia-500/20 bg-[#0a0412] flex flex-col shrink-0 relative" style={{ height: sm ? Math.min(termHeight, window.innerHeight * 0.4) : termHeight }}>
              <div className="absolute top-0 left-0 w-full h-3 sm:h-1.5 -mt-[2px] cursor-row-resize drag-handle hover:bg-fuchsia-400/50 active:bg-fuchsia-400 z-20 transition-colors" onMouseDown={(e) => { e.preventDefault(); setIsDragging('terminal'); }} onTouchStart={(e) => { e.preventDefault(); setIsDragging('terminal'); }} />
              <div className="flex items-center px-2 sm:px-4 pt-2 gap-1 sm:gap-3 shrink-0 overflow-x-auto no-scrollbar">
                {[
                  { id: 'problems', label: 'PROBLEMS', badge: allProblems.length > 0 ? allProblems.length : null },
                  { id: 'output', label: 'OUTPUT' },
                  { id: 'terminal', label: 'TERMINAL' },
                  { id: 'debug', label: 'DEBUG CONSOLE' },
                  { id: 'ports', label: 'PORTS', badge: ports.filter(p => p.state === 'running').length || null },
                ].map((tab) => (
                  <button
                    key={tab.id}
                    onClick={() => setActiveTerminalTab(tab.id)}
                    className={`text-[11px] font-semibold tracking-wider pb-2 border-b-2 transition-colors whitespace-nowrap px-1 ${activeTerminalTab === tab.id ? 'border-cyan-400 text-cyan-50 drop-shadow-[0_0_5px_rgba(34,211,238,0.5)]' : 'border-transparent text-purple-400/60 hover:text-purple-200'}`}
                  >
                    {tab.label}
                    {tab.badge && <span className="ml-1.5 bg-fuchsia-500/20 text-fuchsia-300 px-1.5 rounded-full text-[10px]">{tab.badge}</span>}
                  </button>
                ))}
                <div className="flex-1 flex justify-end gap-2 pb-2">
                  <button className="p-1 hover:bg-[#25104a] rounded text-purple-400/60 transition-colors"><Plus size={14} /></button>
                  <button className="p-1 hover:bg-[#25104a] rounded text-purple-400/60 transition-colors" onClick={() => setTerminalState('closed')}><X size={14} /></button>
                </div>
              </div>

              {activeTerminalTab === 'terminal' && (
                <div className="flex-1 p-3 overflow-y-auto font-mono text-[13px]" onClick={() => termInputRef.current?.focus()} role="log" aria-live="polite" aria-label="Terminal output">
                  {terminalLines.map((line, i) => (
                    <div key={i} className={`break-all leading-relaxed ${
                      line.startsWith('✓') || line.startsWith('Done') ? 'text-green-400' :
                      line.startsWith('bash:') || line.startsWith('Error') || line.startsWith('fatal') ? 'text-red-400' :
                      line.startsWith('  ➜') ? 'text-cyan-400' :
                      line.startsWith('ubuntu@') ? 'text-cyan-400 font-semibold' :
                      'text-purple-200'
                    }`}>{line}</div>
                  ))}
                  <form onSubmit={(e) => { e.preventDefault(); if (!terminalInput.trim()) return; handleTerminalCommand(terminalInput.trim()); setTerminalInput(''); }} className="flex items-start mt-1">
                    <span className="text-cyan-400 mr-2 shrink-0 font-semibold drop-shadow-[0_0_2px_rgba(34,211,238,0.8)]">ubuntu@epicode:~/workspace (main) $</span>
                    <input ref={termInputRef} type="text" value={terminalInput} onChange={(e) => setTerminalInput(e.target.value)} aria-label="Terminal input" className="flex-1 bg-transparent border-none outline-none text-purple-100 focus:ring-0 p-0 caret-fuchsia-500" autoComplete="off" spellCheck="false" />
                  </form>
                </div>
              )}

              {activeTerminalTab === 'problems' && (
                <div className="flex-1 p-3 overflow-y-auto font-mono text-[12px]">
                  {allProblems.length === 0 ? (
                    <div className="text-purple-500/50 flex items-center gap-2 mt-2"><CheckCircle2 size={13} className="text-green-400"/> No problems detected.</div>
                  ) : allProblems.map((p, i) => (
                    <div key={i} onClick={() => handleFileClick(p.file)} className="flex items-start gap-2 py-1.5 px-2 rounded hover:bg-[#25104a] cursor-pointer group">
                      <AlertCircle size={12} className={`mt-0.5 shrink-0 ${p.severity === 'error' ? 'text-red-400' : p.severity === 'warning' ? 'text-yellow-400' : 'text-cyan-400'}`}/>
                      <div className="flex-1">
                        <span className="text-purple-200">{p.msg}</span>
                        <span className="text-purple-500/60 ml-2">{p.file}:{p.line}</span>
                      </div>
                    </div>
                  ))}
                </div>
              )}

              {activeTerminalTab === 'output' && (
                <div className="flex-1 p-3 overflow-y-auto font-mono text-[12px]">
                  {outputLog.length === 0 ? (
                    <div className="text-purple-500/50">No output yet. Run a build task to see output here.</div>
                  ) : outputLog.map((line, i) => (
                    <div key={i} className={`leading-relaxed ${line.startsWith('✓') ? 'text-green-400' : line.startsWith('Error') ? 'text-red-400' : line.startsWith('dist/') ? 'text-cyan-300' : 'text-purple-300'}`}>{line || '\u00a0'}</div>
                  ))}
                </div>
              )}

              {activeTerminalTab === 'debug' && (
                <div className="flex-1 flex flex-col overflow-hidden">
                  <div className="flex items-center gap-2 px-3 py-1.5 border-b border-fuchsia-500/10 bg-[#0f0620]">
                    <select className="bg-[#1a0b35] border border-fuchsia-500/20 text-purple-200 text-[11px] rounded px-2 py-1 outline-none">
                      <option>Node.js (default)</option>
                      <option>Chrome DevTools</option>
                    </select>
                    <div className="flex gap-1 ml-auto">
                      <button onClick={() => { setDebugConsoleLines(prev => [...prev, { type: 'info', text: `\u25b6 Debugger attached to pid ${Math.floor(1000 + Math.random() * 9000)}`, ts: Date.now() }]); }} className="p-1 hover:bg-[#25104a] rounded text-green-400/60 hover:text-green-400" title="Start"><Play size={13}/></button>
                      <button className="p-1 hover:bg-[#25104a] rounded text-red-400/60 hover:text-red-400" title="Stop"><Square size={13}/></button>
                      <button onClick={() => setDebugConsoleLines([{ type: 'info', text: 'Debug console cleared.', ts: Date.now() }])} className="p-1 hover:bg-[#25104a] rounded text-purple-400/60 hover:text-purple-200" title="Clear"><Trash2 size={13}/></button>
                    </div>
                  </div>
                  <div className="flex-1 p-3 overflow-y-auto font-mono text-[12px] space-y-0.5">
                    {debugConsoleLines.map((entry, i) => (
                      <div key={i} className={`flex items-start gap-2 py-0.5 ${entry.type === 'error' ? 'text-red-400' : entry.type === 'warn' ? 'text-yellow-400' : entry.type === 'info' ? 'text-cyan-300' : 'text-purple-200'}`}>
                        <span className="text-purple-500/30 text-[10px] shrink-0 w-16">{new Date(entry.ts).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' })}</span>
                        <span className={`text-[10px] shrink-0 w-10 uppercase font-semibold ${entry.type === 'error' ? 'text-red-400/70' : entry.type === 'warn' ? 'text-yellow-400/70' : 'text-cyan-400/70'}`}>{entry.type}</span>
                        <span className="break-all">{entry.text}</span>
                      </div>
                    ))}
                  </div>
                  <form onSubmit={(e) => {
                    e.preventDefault();
                    const input = e.target.elements.debugInput;
                    const expr = input.value.trim();
                    if (!expr) return;
                    setDebugConsoleLines(prev => [...prev, { type: 'log', text: `> ${expr}`, ts: Date.now() }]);
                    try {
                      const safeResult = expr === 'process.env' ? '{ NODE_ENV: "development" }'
                        : expr.startsWith('console.') ? 'undefined'
                        : expr === 'window.location' ? '{ href: "https://epicodespace.vercel.app" }'
                        : expr.match(/^\d[\d+\-*/. ()]*$/) ? String(Function('"use strict"; return (' + expr + ')')()) // safe math only
                        : `"${expr}"`;
                      setDebugConsoleLines(prev => [...prev, { type: 'info', text: safeResult, ts: Date.now() }]);
                    } catch {
                      setDebugConsoleLines(prev => [...prev, { type: 'error', text: `ReferenceError: ${expr} is not defined`, ts: Date.now() }]);
                    }
                    input.value = '';
                  }} className="flex items-center px-3 py-2 border-t border-fuchsia-500/10 gap-2">
                    <span className="text-cyan-400 text-[11px] font-mono shrink-0">&gt;</span>
                    <input name="debugInput" type="text" placeholder="Evaluate expression..." className="flex-1 bg-transparent border-none outline-none text-purple-100 text-[12px] font-mono caret-fuchsia-500" autoComplete="off" spellCheck="false" />
                  </form>
                </div>
              )}

              {activeTerminalTab === 'ports' && (
                <div className="flex-1 p-3 overflow-y-auto font-mono text-[12px]">
                  <div className="flex items-center gap-2 mb-3 justify-between">
                    <span className="text-purple-400/60 text-[11px] uppercase tracking-wider font-semibold">Forwarded Ports</span>
                    <button onClick={() => setPorts(prev => [...prev, { port: 3000 + Math.floor(Math.random() * 5000), protocol: 'https', state: 'running', label: 'New Service', visibility: 'private', pid: Math.floor(1000 + Math.random() * 9000) }])} className="text-[10px] text-purple-400/60 hover:text-purple-200 bg-white/5 hover:bg-white/10 px-2 py-1 rounded transition-colors flex items-center gap-1"><Plus size={11}/> Add Port</button>
                  </div>
                  {ports.length === 0 ? (
                    <div className="text-purple-500/50 flex items-center gap-2 mt-4"><Globe size={14}/> No forwarded ports. Run a server to see ports here.</div>
                  ) : (
                    <table className="w-full text-left">
                      <thead>
                        <tr className="text-purple-500/50 text-[10px] uppercase border-b border-fuchsia-500/10">
                          <th className="py-1.5 px-2 font-semibold">Port</th>
                          <th className="py-1.5 px-2 font-semibold">Protocol</th>
                          <th className="py-1.5 px-2 font-semibold hidden sm:table-cell">Label</th>
                          <th className="py-1.5 px-2 font-semibold">Visibility</th>
                          <th className="py-1.5 px-2 font-semibold">Status</th>
                          <th className="py-1.5 px-2 font-semibold w-20"></th>
                        </tr>
                      </thead>
                      <tbody>
                        {ports.map((p, i) => (
                          <tr key={i} className="hover:bg-[#25104a] transition-colors border-b border-fuchsia-500/5 group">
                            <td className="py-2 px-2">
                              <span className="text-cyan-300 font-semibold">{p.port}</span>
                            </td>
                            <td className="py-2 px-2 text-purple-300/70">{p.protocol}</td>
                            <td className="py-2 px-2 text-purple-200 hidden sm:table-cell">{p.label}</td>
                            <td className="py-2 px-2">
                              <button onClick={() => setPorts(prev => prev.map((pp, pi) => pi === i ? { ...pp, visibility: pp.visibility === 'private' ? 'public' : 'private' } : pp))} className={`text-[10px] px-2 py-0.5 rounded-full border ${p.visibility === 'public' ? 'border-green-500/30 text-green-400 bg-green-500/10' : 'border-yellow-500/30 text-yellow-400 bg-yellow-500/10'}`}>
                                {p.visibility}
                              </button>
                            </td>
                            <td className="py-2 px-2">
                              <span className={`flex items-center gap-1.5 ${p.state === 'running' ? 'text-green-400' : 'text-red-400'}`}>
                                {p.state === 'running' ? <Wifi size={11}/> : <WifiOff size={11}/>}
                                {p.state}
                              </span>
                            </td>
                            <td className="py-2 px-2">
                              <div className="flex gap-1 opacity-0 group-hover:opacity-100 transition-opacity">
                                <button onClick={() => setPorts(prev => prev.map((pp, pi) => pi === i ? { ...pp, state: pp.state === 'running' ? 'stopped' : 'running' } : pp))} className="p-1 hover:bg-white/10 rounded text-purple-400/60" title={p.state === 'running' ? 'Stop' : 'Start'}>
                                  {p.state === 'running' ? <Square size={11}/> : <Play size={11}/>}
                                </button>
                                <button onClick={() => setPorts(prev => prev.filter((_, pi) => pi !== i))} className="p-1 hover:bg-white/10 rounded text-red-400/60" title="Remove">
                                  <Trash2 size={11}/>
                                </button>
                              </div>
                            </td>
                          </tr>
                        ))}
                      </tbody>
                    </table>
                  )}
                </div>
              )}
            </div>
          )}
        </main>

        {/* Right Sidebar (AI Chat) */}
        {rightSidebarOpen && (
          <>
            {sm && <div className="sidebar-backdrop" onClick={() => setRightSidebarOpen(false)} />}
            <aside className={`${sm ? 'fixed inset-0 z-20' : 'relative'} border-l border-fuchsia-500/20 bg-[#15092a] flex flex-col shrink-0 shadow-[-4px_0_20px_rgba(192,38,211,0.03)] panel-transition`} style={sm ? {} : { width: rightWidth }}>
              {!sm && <div className="absolute top-0 -left-[2px] w-1.5 h-full cursor-col-resize drag-handle hover:bg-fuchsia-400/50 active:bg-fuchsia-400 z-20 transition-colors" onMouseDown={(e) => { e.preventDefault(); setIsDragging('right'); }} onTouchStart={(e) => { e.preventDefault(); setIsDragging('right'); }} />}

            {/* Chat Header */}
            <div className="flex justify-between items-center px-3 sm:px-4 py-2.5 sm:py-2 border-b border-fuchsia-500/20 shrink-0" style={sm ? { paddingTop: 'max(0.625rem, var(--sat))' } : {}}>
              <span className="text-[11px] font-bold text-purple-200 uppercase tracking-widest flex items-center gap-2">
                <MessageSquare size={14} className="text-fuchsia-400"/> CHAT
                <span className={`text-[9px] font-normal px-1.5 py-0.5 rounded-full ${AGENT_REGISTRY[activeAgent]?.color || 'text-fuchsia-400'} bg-white/5 border border-white/10`}>
                  {AGENT_REGISTRY[activeAgent]?.name || 'Agent'}
                </span>
              </span>
              <div className="flex gap-1 text-purple-400/60">
                <button onClick={handleNewConversation} className="p-1.5 sm:p-1 hover:text-purple-200 hover:bg-[#25104a] rounded transition-colors" title="New conversation"><Plus size={14} /></button>
                <button onClick={() => setShowConversations(p => !p)} className="p-1.5 sm:p-1 hover:text-purple-200 hover:bg-[#25104a] rounded transition-colors" title="Conversations"><MessageSquare size={14} /></button>
                <button className="p-1.5 sm:p-1 hover:text-purple-200 hover:bg-[#25104a] rounded transition-colors"><Settings size={14} /></button>
                <button className="p-1.5 sm:p-1 hover:text-purple-200 hover:bg-[#25104a] rounded transition-colors" onClick={() => setRightSidebarOpen(false)}><X size={14} /></button>
              </div>
            </div>

            {/* Mode Switcher (Ask / Agent / Plan) */}
            <div className="flex items-center border-b border-fuchsia-500/20 bg-[#0f0620] shrink-0">
              {[
                { id: 'ask', label: 'Ask', icon: HelpCircle, desc: 'Q&A chat' },
                { id: 'agent', label: 'Agent', icon: Zap, desc: 'Builds & edits files' },
                { id: 'plan', label: 'Plan', icon: ListChecks, desc: 'Plan then execute' },
              ].map(m => (
                <button
                  key={m.id}
                  onClick={() => setChatMode(m.id)}
                  className={`flex-1 flex items-center justify-center gap-1.5 py-2 text-[11px] font-semibold transition-all border-b-2 ${chatMode === m.id ? 'border-fuchsia-400 text-fuchsia-300 bg-fuchsia-500/5' : 'border-transparent text-purple-400/50 hover:text-purple-300 hover:bg-white/5'}`}
                  title={m.desc}
                >
                  <m.icon size={13} />
                  {m.label}
                </button>
              ))}
            </div>

            {/* Conversation Switcher Dropdown */}
            {showConversations && (
              <div className="border-b border-fuchsia-500/20 bg-[#1a0b35] max-h-40 overflow-y-auto">
                {conversations.map(c => (
                  <button
                    key={c.id}
                    onClick={() => handleSwitchConversation(c.id)}
                    className={`w-full text-left px-4 py-2 text-xs flex items-center justify-between transition-colors ${c.id === activeConvoId ? 'bg-fuchsia-500/15 text-fuchsia-200' : 'text-purple-300 hover:bg-[#25104a]'}`}
                  >
                    <span className="flex items-center gap-2">
                      <MessageSquare size={11} />
                      {c.name}
                      <span className="text-[9px] text-purple-500">({c.messages.length} msgs)</span>
                    </span>
                    <span className={`text-[9px] ${AGENT_REGISTRY[c.agent]?.color || ''}`}>{AGENT_REGISTRY[c.agent]?.name || c.agent}</span>
                  </button>
                ))}
              </div>
            )}

            {/* Chat Messages */}
            <div className="flex-1 overflow-y-auto p-4 space-y-5 font-sans text-[13px] bg-gradient-to-b from-[#15092a] to-[#0a0412]" role="log" aria-live="polite" aria-label="Chat history">
              {messages.length === 0 && (
                <div className="text-center pt-8 space-y-4">
                  <div className="flex justify-center">
                    <div className={`p-3 rounded-xl bg-white/5 border border-white/10 ${AGENT_REGISTRY[activeAgent]?.color}`}>
                      <Sparkles size={24} />
                    </div>
                  </div>
                  <div>
                    <h3 className="text-purple-200 font-semibold text-sm">{AGENT_REGISTRY[activeAgent]?.name}</h3>
                    <p className="text-purple-400/60 text-xs mt-1">{AGENT_REGISTRY[activeAgent]?.description}</p>
                  </div>
                  <div className="flex flex-wrap gap-1.5 justify-center mt-4">
                    {(AGENT_REGISTRY[activeAgent]?.capabilities || []).map(cap => (
                      <span key={cap} className="text-[9px] px-2 py-1 rounded-full bg-fuchsia-500/10 text-fuchsia-300/70 border border-fuchsia-500/20">
                        {cap.replace('_', ' ')}
                      </span>
                    ))}
                  </div>
                  <div className="space-y-2 pt-4">
                    <p className="text-[10px] text-purple-500/60 uppercase tracking-wider">Try asking</p>
                    {['Explain this file', 'Review my code', 'Generate a test', 'Find all TODOs'].map(q => (
                      <button key={q} onClick={() => { setChatInput(q); }} className="block mx-auto text-xs text-purple-300/60 hover:text-purple-200 bg-white/5 hover:bg-white/10 border border-white/10 rounded-lg px-3 py-1.5 transition-colors">
                        {q}
                      </button>
                    ))}
                  </div>
                </div>
              )}
              {messages.map((msg, i) => (
                <div key={i} className="flex flex-col gap-1.5">
                  <div className="flex items-center gap-2 text-purple-400/80 text-[11px] font-semibold uppercase tracking-wider mb-0.5">
                    {msg.role === 'user'
                      ? <><Terminal size={12} /> You</>
                      : <><Sparkles size={12} className={AGENT_REGISTRY[msg.agent]?.color || 'text-fuchsia-400'} /> {msg.agentName || AGENT_REGISTRY[msg.agent]?.name || 'Agent'}</>
                    }
                    {msg.timestamp && <span className="text-[9px] text-purple-500/40 font-normal normal-case ml-auto">{new Date(msg.timestamp).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}</span>}
                  </div>
                  {/* Tool call steps */}
                  {msg.steps && msg.steps.length > 0 && (
                    <div className="mb-1.5 space-y-0.5">
                      {msg.steps.map((step, si) => (
                        <div key={si} className="text-[10px] text-purple-400/50 font-mono flex items-center gap-1.5 pl-1">
                          <CheckCircle2 size={10} className="text-green-500/60 shrink-0" />
                          <span dangerouslySetInnerHTML={{ __html: step.replace(/\*\*(.*?)\*\*/g, '<strong class="text-purple-300/70">$1</strong>') }} />
                        </div>
                      ))}
                    </div>
                  )}
                  <div className={`rounded-xl px-4 py-3 ${msg.role === 'user' ? 'bg-[#1f0e40] border border-purple-500/30 text-purple-100 shadow-md' : 'bg-transparent border border-fuchsia-500/20 text-purple-200'} leading-relaxed whitespace-pre-wrap text-[13px]`}>
                    {msg.content}
                  </div>
                  {/* Tool calls summary */}
                  {msg.toolCalls && msg.toolCalls.length > 0 && (
                    <div className="space-y-0.5 mt-1">
                      <div className="flex items-center gap-2 text-[9px] text-purple-500/40 pl-1">
                        <Code2 size={10} />
                        <span>{msg.toolCalls.length} tool call{msg.toolCalls.length > 1 ? 's' : ''}</span>
                        {msg.mode && <span className="bg-fuchsia-500/10 text-fuchsia-400/60 px-1.5 py-0.5 rounded-full">{msg.mode}</span>}
                      </div>
                      <div className="flex flex-wrap gap-1 pl-1">
                        {msg.toolCalls.map((tc, ti) => {
                          const isWrite = tc.tool === 'writeFile' || tc.tool === 'editFile';
                          const isDel = tc.tool === 'deleteFile';
                          return (
                            <span key={ti} className={`text-[9px] px-1.5 py-0.5 rounded font-mono ${isWrite ? 'bg-green-500/10 text-green-400/70 border border-green-500/20' : isDel ? 'bg-red-500/10 text-red-400/70 border border-red-500/20' : 'bg-white/5 text-purple-400/50'}`}>
                              {tc.tool === 'writeFile' ? '📝' : tc.tool === 'editFile' ? '✏️' : tc.tool === 'deleteFile' ? '🗑️' : tc.tool === 'readFile' ? '📖' : tc.tool === 'runCommand' ? '💻' : '📋'}
                              {' '}{tc.tool}{tc.args?.path ? `("${tc.args.path}")` : tc.args?.command ? `("${tc.args.command}")` : '()'}
                            </span>
                          );
                        })}
                      </div>
                    </div>
                  )}
                  {/* Extracted TODOs from assistant messages */}
                  {msg.role === 'assistant' && msg.content && (() => {
                    const todoLines = msg.content.split('\n').filter(l => /^[-*]\s*\[[ x]\]/i.test(l.trim()) || /^\d+\.\s/.test(l.trim()));
                    if (todoLines.length === 0) return null;
                    const msgTodos = todoLines.map(l => l.replace(/^[-*]\s*\[[ x]\]\s*/i, '').replace(/^\d+\.\s*/, '').trim()).filter(t => t.length > 3);
                    if (msgTodos.length === 0) return null;
                    const alreadyAdded = chatTodos.map(t => t.text);
                    const newOnes = msgTodos.filter(t => !alreadyAdded.includes(t));
                    if (newOnes.length === 0 && msgTodos.every(t => alreadyAdded.includes(t))) return null;
                    return (
                      <div className="mt-2 bg-fuchsia-500/5 border border-fuchsia-500/20 rounded-lg p-2.5 space-y-1.5">
                        <div className="text-[10px] text-fuchsia-300/70 uppercase tracking-wider font-semibold flex items-center gap-1.5">
                          <ListChecks size={11}/> Tasks detected ({msgTodos.length})
                        </div>
                        {msgTodos.map((todo, ti) => {
                          const exists = alreadyAdded.includes(todo);
                          return (
                            <div key={ti} className="flex items-start gap-2 text-[11px] text-purple-200/80 py-0.5">
                              <span className="shrink-0 mt-0.5 text-fuchsia-400/50">•</span>
                              <span className="flex-1">{todo}</span>
                              {exists ? (
                                <span className="text-[9px] text-green-400/60 shrink-0">added</span>
                              ) : (
                                <button onClick={() => setChatTodos(prev => [...prev, { id: Date.now() + ti, text: todo, done: false }])} className="text-[9px] text-fuchsia-400 hover:text-fuchsia-300 bg-fuchsia-500/10 hover:bg-fuchsia-500/20 px-1.5 py-0.5 rounded shrink-0 transition-colors">+ Keep</button>
                              )}
                            </div>
                          );
                        })}
                        {newOnes.length > 1 && (
                          <button onClick={() => setChatTodos(prev => [...prev, ...newOnes.filter(t => !prev.some(p => p.text === t)).map((t, i) => ({ id: Date.now() + i, text: t, done: false }))])} className="text-[9px] text-fuchsia-300 hover:text-fuchsia-200 bg-fuchsia-500/10 hover:bg-fuchsia-500/20 px-2 py-1 rounded transition-colors mt-1">
                            + Keep All ({newOnes.length})
                          </button>
                        )}
                      </div>
                    );
                  })()}
                </div>
              ))}
              {isTyping && (
                <div className="flex flex-col gap-1.5">
                  <div className="flex items-center gap-2 text-purple-400/80 text-[11px] font-semibold uppercase tracking-wider mb-0.5">
                    <Sparkles size={12} className={`${AGENT_REGISTRY[activeAgent]?.color || 'text-fuchsia-400'} animate-pulse`} /> {AGENT_REGISTRY[activeAgent]?.name}
                  </div>
                  <div className="bg-transparent border border-fuchsia-500/20 text-purple-400 rounded-xl px-4 py-3 flex items-center gap-2 w-fit">
                    <Loader2 size={14} className={`animate-spin ${AGENT_REGISTRY[activeAgent]?.color || 'text-fuchsia-400'}`} />
                    <span className="text-xs">{chatMode === 'agent' ? 'Executing tools & writing code...' : chatMode === 'plan' ? 'Analyzing codebase & planning...' : 'Thinking...'}</span>
                  </div>
                </div>
              )}
              <div ref={chatEndRef} />
            </div>

            {/* Kept TODOs Panel */}
            {chatTodos.length > 0 && (
              <div className="px-3 py-2 bg-[#120825] border-t border-fuchsia-500/15 shrink-0">
                <div className="flex items-center justify-between mb-1.5">
                  <span className="text-[10px] text-fuchsia-300/70 uppercase tracking-wider font-semibold flex items-center gap-1"><ListChecks size={10}/> TODOs ({chatTodos.filter(t=>!t.done).length}/{chatTodos.length})</span>
                  <button onClick={() => setChatTodos([])} className="text-[9px] text-red-400/50 hover:text-red-300 transition-colors">Clear all</button>
                </div>
                <div className="space-y-1 max-h-[120px] overflow-y-auto">
                  {chatTodos.map(todo => (
                    <div key={todo.id} className={`flex items-start gap-2 text-[11px] py-0.5 px-1.5 rounded group ${todo.done ? 'opacity-50' : ''}`}>
                      <button onClick={() => setChatTodos(prev => prev.map(t => t.id === todo.id ? {...t, done: !t.done} : t))} className="shrink-0 mt-0.5">
                        {todo.done ? <CheckSquare size={12} className="text-green-400/70"/> : <Square size={12} className="text-purple-400/40 hover:text-fuchsia-300"/>}
                      </button>
                      <span className={`flex-1 text-purple-200/80 ${todo.done ? 'line-through' : ''}`}>{todo.text}</span>
                      <button onClick={() => setChatTodos(prev => prev.filter(t => t.id !== todo.id))} className="shrink-0 text-red-400/30 hover:text-red-400 opacity-0 group-hover:opacity-100 transition-opacity"><X size={11}/></button>
                    </div>
                  ))}
                </div>
              </div>
            )}

            {/* Chat Input */}
            <div className="p-3 bg-[#15092a] border-t border-fuchsia-500/20 shrink-0" style={{ paddingBottom: 'max(0.75rem, var(--sab))' }}>
              <form onSubmit={handleAgentSubmit} className="flex flex-col gap-2">
                <div className="relative bg-[#0a0412]/80 border border-fuchsia-500/30 focus-within:border-fuchsia-400 focus-within:shadow-[0_0_10px_rgba(232,121,249,0.2)] rounded-lg transition-all">
                  <textarea
                    value={chatInput}
                    onChange={(e) => setChatInput(e.target.value)}
                    placeholder={chatMode === 'agent' ? `Tell ${AGENT_REGISTRY[activeAgent]?.name || 'Agent'} what to build or fix...` : chatMode === 'plan' ? `Describe what you want planned...` : `Ask ${AGENT_REGISTRY[activeAgent]?.name || 'Agent'}...`}
                    className="w-full bg-transparent p-3 text-[13px] text-purple-100 outline-none placeholder:text-purple-400/40 resize-none min-h-[80px]"
                    onKeyDown={(e) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); handleAgentSubmit(e); } }}
                  />
                  <div className="flex items-center justify-between px-2 pb-2">
                    <div className="flex items-center gap-1">
                      <button type="button" className="p-1.5 text-purple-400/60 hover:text-purple-200 transition-colors"><Paperclip size={14}/></button>
                      <button type="button" className="p-1.5 text-purple-400/60 hover:text-purple-200 transition-colors text-xs font-semibold px-2">@</button>
                    </div>
                    <button
                      type="submit"
                      disabled={!chatInput.trim() || isTyping}
                      className="p-1.5 bg-fuchsia-600 hover:bg-fuchsia-500 disabled:bg-[#25104a] disabled:text-purple-500/50 text-white rounded-md transition-all shadow-md"
                    >
                      <Send size={14} className={isTyping ? "opacity-50" : ""} />
                    </button>
                  </div>
                </div>

                {/* Agent Picker */}
                <div className="flex justify-between items-center text-[10px] text-purple-400/70 mt-1 px-1 relative">
                  <div className="flex items-center gap-1 hover:text-purple-200 cursor-pointer" onClick={() => setShowConversations(p => !p)}>
                    <MessageSquare size={11} /> Chat {activeConvoId} <ChevronDown size={11} />
                  </div>
                  <div className="relative" data-agent-picker>
                    <div
                      className="flex items-center gap-1 hover:text-fuchsia-300 cursor-pointer transition-colors"
                      onClick={() => setShowAgentPicker(p => !p)}
                    >
                      <Sparkles size={12} className={AGENT_REGISTRY[activeAgent]?.color || 'text-fuchsia-400/70'} />
                      <span>{AGENT_REGISTRY[activeAgent]?.name || 'Select Agent'}</span>
                      <ChevronDown size={11} />
                    </div>
                    {showAgentPicker && (
                      <div className="absolute bottom-full right-0 mb-1 w-56 bg-[#1a0b35] border border-fuchsia-500/30 rounded-lg shadow-[0_8px_32px_rgba(0,0,0,0.7)] z-50 py-1 overflow-hidden">
                        <div className="px-3 py-1.5 text-[9px] text-purple-500/50 uppercase tracking-widest font-bold">Select Agent</div>
                        {Object.values(AGENT_REGISTRY).map(agent => (
                          <button
                            key={agent.id}
                            onClick={() => { setActiveAgent(agent.id); setShowAgentPicker(false); setConversations(prev => prev.map(c => c.id === activeConvoId ? { ...c, agent: agent.id } : c)); }}
                            className={`w-full text-left px-3 py-2 text-xs transition-colors flex items-center gap-2.5 ${activeAgent === agent.id ? 'bg-fuchsia-500/15 text-fuchsia-200' : 'text-purple-300 hover:bg-[#25104a] hover:text-purple-100'}`}
                          >
                            <Sparkles size={12} className={`${agent.color} shrink-0`} />
                            <div className="flex-1 min-w-0">
                              <div className="font-semibold flex items-center gap-1.5">
                                {agent.name}
                                {activeAgent === agent.id && <CheckCircle2 size={10} className="text-fuchsia-400" />}
                              </div>
                              <div className="text-[9px] text-purple-500/60 truncate">{agent.description}</div>
                            </div>
                          </button>
                        ))}
                      </div>
                    )}
                  </div>
                </div>
              </form>
            </div>
          </aside>
          </>
        )}
      </div>

      {/* Saved Toast */}
      {savedIndicator && (
        <div className="fixed top-14 left-1/2 -translate-x-1/2 z-[60] bg-[#1a0b35] border border-fuchsia-500/30 rounded-lg px-4 py-2 text-xs text-fuchsia-200 flex items-center gap-2 shadow-xl animate-pulse">
          <CheckCircle2 size={13} className="text-fuchsia-400" /> File saved
        </div>
      )}

      {/* About Modal */}
      {showAbout && (
        <div className="fixed inset-0 z-[100] flex items-center justify-center bg-black/60 backdrop-blur-sm" onClick={() => setShowAbout(false)}>
          <div className="bg-[#15092a] border border-fuchsia-500/30 rounded-xl shadow-[0_0_40px_rgba(192,38,211,0.25)] p-8 w-80 text-center" onClick={e => e.stopPropagation()}>
            <div className="flex justify-center mb-4">
              <Cpu size={44} className="text-fuchsia-400 drop-shadow-[0_0_20px_rgba(232,121,249,0.9)]" />
            </div>
            <h2 className="text-xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-fuchsia-300 to-purple-300 mb-1">EpiCodeSpace</h2>
            <p className="text-purple-400/60 text-xs mb-4">Version 2.0.0 &mdash; April 2026</p>
            <p className="text-purple-300/80 text-xs leading-relaxed mb-6">
              An AI-powered cloud IDE mimicking GitHub Codespaces.<br />
              Built with React, Vite, Tailwind CSS &amp; lucide-react.
            </p>
            <div className="text-[10px] text-purple-500/50 mb-6 space-y-0.5">
              <div>Node: v20.x</div>
              <div>React: 18</div>
              <div>Vite: 6</div>
            </div>
            <button onClick={() => setShowAbout(false)} className="px-6 py-2 bg-fuchsia-600 hover:bg-fuchsia-500 text-white text-xs rounded-lg transition-colors shadow-md">Close</button>
          </div>
        </div>
      )}

      {/* ── Status Bar ────────────────────────────────────────────────────── */}
      <footer className="h-6 flex items-center justify-between px-1 sm:px-2 bg-[#15092a] border-t border-fuchsia-500/30 text-[10px] sm:text-[11px] text-purple-300 z-20 shrink-0 overflow-x-auto no-scrollbar" style={{ paddingBottom: 'var(--sab)' }}>
        <div className="flex items-center h-full">
          <div className="hidden sm:flex items-center gap-1 h-full px-2 sm:px-3 bg-gradient-to-r from-cyan-600 to-blue-600 text-white font-semibold cursor-pointer hover:from-cyan-500 hover:to-blue-500 transition-colors rounded-tl-sm">
            <span className="text-[10px]">&gt;&lt;</span> <span className="hidden md:inline">EpiCodeSpace</span><span className="md:hidden">ECS</span>
          </div>
          <div className="flex items-center gap-1 px-2 sm:px-3 h-full hover:bg-[#25104a] cursor-pointer transition-colors border-r border-fuchsia-500/10">
            <GitBranch size={12} /> main*
          </div>
          <div className="hidden md:flex items-center gap-1 px-3 h-full hover:bg-[#25104a] cursor-pointer transition-colors border-r border-fuchsia-500/10">
            <GitCommit size={12} /> Sync Changes
          </div>
          <div onClick={() => { setTerminalState('open'); setActiveTerminalTab('problems'); }} className="flex items-center gap-2 sm:gap-3 px-2 sm:px-3 h-full hover:bg-[#25104a] cursor-pointer transition-colors">
            <div className="flex items-center gap-1"><AlertCircle size={12} className="text-red-400"/> {errorCount}</div>
            <div className="flex items-center gap-1"><AlertCircle size={12} className="text-yellow-400" /> {warningCount}</div>
            <div className="hidden sm:flex items-center gap-1"><AlertCircle size={12} className="text-cyan-400" /> {infoCount}</div>
          </div>
        </div>
        <div className="flex items-center h-full">
          <div className="px-2 h-full flex items-center hover:bg-[#25104a] cursor-pointer transition-colors">Ln {cursorPos.line}, Col {cursorPos.col}</div>
          <div className="hidden sm:flex px-2 h-full items-center hover:bg-[#25104a] cursor-pointer transition-colors" onClick={() => setWordWrap(p => !p)} title="Toggle Word Wrap (Alt+Z)">{wordWrap ? 'Wrap: On' : 'Spaces: 2'}</div>
          <div className="hidden md:flex px-2 h-full items-center hover:bg-[#25104a] cursor-pointer transition-colors">UTF-8</div>
          <div className="hidden lg:flex px-2 h-full items-center hover:bg-[#25104a] cursor-pointer transition-colors">LF</div>
          <div className="hidden md:flex px-2 h-full items-center hover:bg-[#25104a] cursor-pointer transition-colors font-semibold gap-1"><CheckCircle2 size={12} className="text-fuchsia-400"/> Prettier</div>
          <div className="hidden lg:flex px-2 h-full items-center hover:bg-[#25104a] cursor-pointer transition-colors">Layout: U.S.</div>
          <div className={`px-2 h-full flex items-center border-l border-fuchsia-500/10 ${AGENT_REGISTRY[activeAgent]?.color || 'text-fuchsia-400'}`}>⚡ <span className="hidden sm:inline ml-1">{AGENT_REGISTRY[activeAgent]?.name || 'Agent'}</span></div>
        </div>
      </footer>
    </div>
  );
}

/* ─── Wrapped Export with Error Boundary ─────────────────────────────────── */
function EpiCodeSpaceWithBoundary() {
  return <ErrorBoundary><EpiCodeSpaceApp /></ErrorBoundary>;
}

export default EpiCodeSpaceWithBoundary;
