/**
 * Module import & export verification for VLCode Lite
 * Tests: import succeeds, exports exist, basic function calls work
 */
import { fileURLToPath } from 'url';
import path from 'path';

const __dirname = path.dirname(fileURLToPath(import.meta.url));
const results = [];
let passCount = 0, failCount = 0, warnCount = 0;

function ok(mod, msg) { passCount++; results.push(`  ✅ ${mod}: ${msg}`); }
function fail(mod, msg) { failCount++; results.push(`  ❌ ${mod}: ${msg}`); }
function warn(mod, msg) { warnCount++; results.push(`  ⚠️  ${mod}: ${msg}`); }

// ─── 1. Utils ────────────────────────────────────────────────────────
async function testUtils() {
  console.log('\n═══ utils/ ═══');
  try {
    const { loadConfig, APP_VERSION } = await import('./src/utils/config.js');
    if (typeof loadConfig !== 'function') throw new Error('loadConfig not a function');
    if (!APP_VERSION) throw new Error('APP_VERSION is empty');
    const cfg = loadConfig(['--web', '--port', '9999']);
    if (cfg.port !== 9999) throw new Error(`port should be 9999, got ${cfg.port}`);
    if (!['cli', 'api-key'].includes(cfg.llmProvider)) {
      throw new Error(`llmProvider should be cli or api-key, got ${cfg.llmProvider}`);
    }
    ok('config.js', `v${APP_VERSION}, loadConfig() works, port=9999, llmProvider=${cfg.llmProvider}`);
  } catch (e) { fail('config.js', e.message); }

  try {
    const { extractZip, extractZipToDir, createZipFromDir } = await import('./src/utils/zip-extract.js');
    if (typeof extractZip !== 'function') throw new Error('extractZip not a function');
    if (typeof extractZipToDir !== 'function') throw new Error('extractZipToDir not a function');
    if (typeof createZipFromDir !== 'function') throw new Error('createZipFromDir not a function');
    const fns = ['extractZip', 'extractZipToDir', 'createZipFromDir'];
    ok('zip-extract.js', `exports: ${fns.join(', ')}`);
  } catch (e) { fail('zip-extract.js', e.message); }
}

// ─── 2. Data ─────────────────────────────────────────────────────────
async function testData() {
  console.log('\n═══ data/ ═══');
  try {
    const { VL_VERSION, THEME_VERSION, PARSEVL_URL } = await import('./src/data/versions.js');
    if (!VL_VERSION || !THEME_VERSION || !PARSEVL_URL) throw new Error('missing constants');
    ok('versions.js', `VL=${VL_VERSION}, Theme=${THEME_VERSION}`);
  } catch (e) { fail('versions.js', e.message); }

  try {
    const { DOCCENTER_API_URL, DOC_REGISTRY, pathFor, docIdFor, resolveDocRef } = await import('./src/data/doc-paths.js');
    if (!DOCCENTER_API_URL) throw new Error('DOCCENTER_API_URL missing');
    if (typeof pathFor !== 'function') throw new Error('pathFor not a function');
    const p = pathFor('vlSyntax');
    if (p !== 1) throw new Error(`pathFor('vlSyntax') should be 1, got ${p}`);
    ok('doc-paths.js', `API=${DOCCENTER_API_URL.substring(0,30)}..., ${Object.keys(DOC_REGISTRY).length} entries`);
  } catch (e) { fail('doc-paths.js', e.message); }

  try {
    const mod = await import('./src/data/default-theme.js');
    ok('default-theme.js', `exports: ${Object.keys(mod).join(', ').substring(0, 60)}`);
  } catch (e) { fail('default-theme.js', e.message); }
}

// ─── 3. Core ─────────────────────────────────────────────────────────
async function testCore() {
  console.log('\n═══ core/ ═══');

  // tool-registry
  try {
    const { ToolRegistry } = await import('./src/core/tool-registry.js');
    const reg = new ToolRegistry();
    reg.register('TestTool', { description: 'test', parameters: {}, execute: async () => 'ok' });
    if (!reg.has('TestTool')) throw new Error('has() failed');
    const result = await reg.execute('TestTool', {});
    if (!result || result.result !== 'ok') throw new Error(`execute returned ${JSON.stringify(result)}`);
    const schemas = reg.getToolSchemas();
    if (schemas.length !== 1) throw new Error(`schemas.length should be 1, got ${schemas.length}`);
    reg.clear();
    if (reg.listTools().length !== 0) throw new Error('clear() failed');
    ok('tool-registry.js', 'register/has/execute/getToolSchemas/clear all work');
  } catch (e) { fail('tool-registry.js', e.message); }

  // context-manager
  try {
    const { ContextManager } = await import('./src/core/context-manager.js');
    const cm = new ContextManager({ maxOutputTokens: 4096 });
    cm.addUserMessage('hello');
    cm.addAssistantMessage('hi there');
    const msgs = cm.getMessages();
    if (msgs.length !== 2) throw new Error(`expected 2 msgs, got ${msgs.length}`);
    const usage = cm.getUsage();
    if (typeof usage.usedTokens !== 'number') throw new Error('getUsage() missing usedTokens');
    ok('context-manager.js', `addUser/addAssistant/getMessages/getUsage work, ${msgs.length} msgs, ${usage.usedTokens} tokens`);
  } catch (e) { fail('context-manager.js', e.message); }

  // session
  try {
    const { SessionManager } = await import('./src/core/session.js');
    const sm = new SessionManager('/tmp/vlcode-lite-test');
    await sm.init();
    const { resumed } = await sm.startOrResume();
    ok('session.js', `init/startOrResume work, resumed=${resumed}`);
  } catch (e) { fail('session.js', e.message); }

  // session-pool
  try {
    const { SessionPool } = await import('./src/core/session-pool.js');
    // SessionPool needs shared modules, just verify import
    ok('session-pool.js', 'import OK (needs shared modules to construct)');
  } catch (e) { fail('session-pool.js', e.message); }

  // llm-provider
  try {
    const { CLIProvider, createProvider, isCLIAvailable } = await import('./src/core/llm-provider.js');
    if (typeof CLIProvider !== 'function') throw new Error('CLIProvider not a class');
    if (typeof createProvider !== 'function') throw new Error('createProvider not a function');
    if (typeof isCLIAvailable !== 'function') throw new Error('isCLIAvailable not a function');
    const available = await isCLIAvailable();
    const provider = createProvider({ model: 'claude-opus-4-6', port: 4002, llmProvider: available ? 'cli' : 'api-key', cliAvailable: available, apiKey: available ? undefined : 'test-key' });
    if (!['cli', 'api-key'].includes(provider.name)) {
      throw new Error(`provider.name should be cli or api-key, got ${provider.name}`);
    }
    ok('llm-provider.js', `Provider OK (${provider.name}), claude CLI available=${available}`);
  } catch (e) { fail('llm-provider.js', e.message); }

  // prompt-assembler
  try {
    const { PromptAssembler } = await import('./src/core/prompt-assembler.js');
    const pa = new PromptAssembler(
      { workDir: '/tmp', model: 'test' },
      { isVLProject: () => false, getSummary: () => ({}), getVLConfig: () => '', getProjectMd: () => '', getRules: () => [] }
    );
    const manual = pa.buildInstructionManual();
    if (!manual || manual.length === 0) throw new Error('buildInstructionManual returned empty');
    ok('prompt-assembler.js', `buildInstructionManual() returns ${manual.length} chars`);
  } catch (e) { fail('prompt-assembler.js', e.message); }

  // orchestrator (import only — needs full wiring)
  try {
    const { AgentOrchestrator } = await import('./src/core/orchestrator.js');
    if (typeof AgentOrchestrator !== 'function') throw new Error('not a class');
    ok('orchestrator.js', 'import OK (needs full wiring to construct)');
  } catch (e) { fail('orchestrator.js', e.message); }

  // cli
  try {
    const { CLIInterface } = await import('./src/core/cli.js');
    if (typeof CLIInterface !== 'function') throw new Error('not a class');
    ok('cli.js', 'import OK');
  } catch (e) { fail('cli.js', e.message); }

  // hooks
  try {
    const { HooksManager } = await import('./src/core/hooks.js');
    const hm = new HooksManager('/tmp/no-hooks');
    if (typeof hm.hasHooks !== 'function') throw new Error('hasHooks not a function');
    if (hm.hasHooks()) throw new Error('should have no hooks');
    ok('hooks.js', 'HooksManager works, hasHooks()=false for empty dir');
  } catch (e) { fail('hooks.js', e.message); }
}

// ─── 4. VL ───────────────────────────────────────────────────────────
async function testVL() {
  console.log('\n═══ vl/ ═══');

  try {
    const { VLProjectContext } = await import('./src/vl/project-context.js');
    const ctx = new VLProjectContext('/tmp/empty-vl-test');
    await ctx.load();
    if (ctx.isVLProject()) throw new Error('empty dir should not be VL project');
    const summary = ctx.getSummary();
    if (summary !== null) throw new Error('getSummary should return null for non-VL project');
    ok('project-context.js', `load/isVLProject/getSummary work, non-VL returns null`);
  } catch (e) { fail('project-context.js', e.message); }

  try {
    const { VLSymbolIndex } = await import('./src/vl/symbol-index.js');
    const { VLProjectContext } = await import('./src/vl/project-context.js');
    const ctx = new VLProjectContext('/tmp/empty-vl-test');
    await ctx.load();
    const si = new VLSymbolIndex(ctx);
    await si.build();
    const stats = si.getStats();
    if (typeof stats.totalSymbols !== 'number') throw new Error('missing totalSymbols');
    ok('symbol-index.js', `build/getStats work, symbols=${stats.totalSymbols}`);
  } catch (e) { fail('symbol-index.js', e.message); }

  try {
    const { SmartContextLoader } = await import('./src/vl/smart-context.js');
    ok('smart-context.js', 'import OK');
  } catch (e) { fail('smart-context.js', e.message); }

  try {
    const { BlueprintContext } = await import('./src/vl/blueprint-context.js');
    const { VLProjectContext } = await import('./src/vl/project-context.js');
    const ctx = new VLProjectContext('/tmp/empty-vl-test');
    await ctx.load();
    const bp = new BlueprintContext(ctx);
    await bp.load();
    if (bp.hasBlueprints()) throw new Error('empty project should have no blueprints');
    ok('blueprint-context.js', 'load/hasBlueprints work');
  } catch (e) { fail('blueprint-context.js', e.message); }

  try {
    const { ImpactAnalyzer } = await import('./src/vl/impact-analyzer.js');
    ok('impact-analyzer.js', 'import OK');
  } catch (e) { fail('impact-analyzer.js', e.message); }

  try {
    const { VLAutoFix } = await import('./src/vl/auto-fix.js');
    ok('auto-fix.js', 'import OK');
  } catch (e) { fail('auto-fix.js', e.message); }

  try {
    const { FileCache } = await import('./src/vl/file-cache.js');
    const fc = new FileCache('/tmp');
    const stats = fc.getStats();
    if (typeof stats.hits !== 'number') throw new Error('getStats missing hits');
    ok('file-cache.js', `FileCache works, hitRate=${stats.hitRate}`);
  } catch (e) { fail('file-cache.js', e.message); }

  try {
    const { FileWatcher } = await import('./src/vl/file-watcher.js');
    ok('file-watcher.js', 'import OK');
  } catch (e) { fail('file-watcher.js', e.message); }

  try {
    const mod = await import('./src/vl/metadata-extractor.js');
    const fns = Object.keys(mod);
    ok('metadata-extractor.js', `exports: ${fns.join(', ')}`);
  } catch (e) { fail('metadata-extractor.js', e.message); }

  try {
    const { computeMetaDiff } = await import('./src/vl/meta-diff.js');
    if (typeof computeMetaDiff !== 'function') throw new Error('not a function');
    const diff = computeMetaDiff({ apps: [], sections: [] }, { apps: [], sections: [] });
    if (!diff.summary && diff.summary !== '') throw new Error('missing summary');
    ok('meta-diff.js', 'computeMetaDiff() works on empty metas');
  } catch (e) { fail('meta-diff.js', e.message); }

  try {
    const { parseSections, sectionDiff, mergeSections, smartMerge } = await import('./src/vl/section-diff.js');
    const sections = parseSections('# Header\nline1\n# Body\nline2');
    if (!(sections instanceof Map)) throw new Error('parseSections should return Map');
    if (sections.size < 2) throw new Error(`expected >=2 sections, got ${sections.size}`);
    const diff = sectionDiff('# A\nfoo', '# A\nbar\n# B\nnew');
    if (!diff.modified && !diff.added) throw new Error('diff should detect changes');
    ok('section-diff.js', `parseSections=${sections.size} sections, sectionDiff/mergeSections/smartMerge exported`);
  } catch (e) { fail('section-diff.js', e.message); }

  try {
    const { GenerationPipeline } = await import('./src/vl/generation-pipeline.js');
    ok('generation-pipeline.js', 'import OK');
  } catch (e) { fail('generation-pipeline.js', e.message); }

  try {
    const { WorkflowGenerationPipeline } = await import('./src/vl/workflow-generation-pipeline.js');
    ok('workflow-generation-pipeline.js', 'import OK');
  } catch (e) { fail('workflow-generation-pipeline.js', e.message); }

  try {
    const { WorkflowExecutor } = await import('./src/vl/workflow-executor.js');
    ok('workflow-executor.js', 'import OK');
  } catch (e) { fail('workflow-executor.js', e.message); }

  try {
    const { generateTestSkeleton } = await import('./src/vl/meta-test-generator.js');
    if (typeof generateTestSkeleton !== 'function') throw new Error('not a function');
    const result = generateTestSkeleton({ apps: [], sections: [], serviceDomains: [] }, {});
    if (!Array.isArray(result.testCases)) throw new Error('should return testCases array');
    ok('meta-test-generator.js', `generateTestSkeleton() returns ${result.testCases.length} cases for empty meta`);
  } catch (e) { fail('meta-test-generator.js', e.message); }
}

// ─── 5. Engine ───────────────────────────────────────────────────────
async function testEngine() {
  console.log('\n═══ engine/ ═══');

  try {
    const { LocalWorkspace } = await import('./src/engine/local-workspace.js');
    const lw = new LocalWorkspace('/tmp/vlcode-lite-ws-test');
    await lw.createFile({ gid: 'test', path: 'hello.txt', content: 'world' });
    const read = await lw.readFile({ gid: 'test', path: 'hello.txt' });
    if (!read.content && read.content !== 'world') throw new Error(`readFile failed: ${JSON.stringify(read)}`);
    await lw.deleteFile({ gid: 'test', path: 'hello.txt' });
    ok('local-workspace.js', 'createFile/readFile/deleteFile work');
  } catch (e) { fail('local-workspace.js', e.message); }

  try {
    const { parseSSEChunk, mapEngineEvent } = await import('./src/engine/sse-parser.js');
    if (typeof parseSSEChunk !== 'function') throw new Error('parseSSEChunk not a function');
    const events = parseSSEChunk('event: test\ndata: {"foo":"bar"}\n\n');
    if (!Array.isArray(events)) throw new Error('should return array');
    ok('sse-parser.js', `parseSSEChunk works, parsed ${events.length} events`);
  } catch (e) { fail('sse-parser.js', e.message); }

  try {
    const { WorkflowEngineManager } = await import('./src/engine/workflow-engine-manager.js');
    ok('workflow-engine-manager.js', 'import OK');
  } catch (e) { fail('workflow-engine-manager.js', e.message); }
}

// ─── 6. Cloud / MCP ─────────────────────────────────────────────────
async function testCloudMcp() {
  console.log('\n═══ cloud/ + mcp/ ═══');

  try {
    const { CloudAPI } = await import('./src/cloud/cloud-api.js');
    const api = new CloudAPI({ cookie: 'test' });
    if (typeof api.login !== 'function') throw new Error('login not a function');
    if (typeof api.listApps !== 'function') throw new Error('listApps not a function');
    if (typeof api.compileWorkspace !== 'function') throw new Error('compileWorkspace not a function');
    if (typeof api.syncPush !== 'function') throw new Error('syncPush not a function');
    ok('cloud-api.js', 'CloudAPI class OK, all key methods present');
  } catch (e) { fail('cloud-api.js', e.message); }

  // MCP server is a stdio process, just verify import
  try {
    // Can't import directly (it starts listening on stdin), just check file exists
    const fs = await import('fs');
    if (!fs.existsSync('./src/mcp/mcp-server.js')) throw new Error('file missing');
    ok('mcp-server.js', 'file exists (stdio process, cannot import test)');
  } catch (e) { fail('mcp-server.js', e.message); }
}

// ─── 7. Tools ────────────────────────────────────────────────────────
async function testTools() {
  console.log('\n═══ tools/ ═══');

  const config = {
    workDir: '/tmp/vlcode-lite-tool-test',
    model: 'claude-opus-4-6',
    port: 3300,
    maxOutputTokens: 32000,
    llmProvider: 'cli',
    workspaceApiUrl: 'https://editor.visuallogic.ai/ih5/editor/workspace',
    autotest: { headless: true, parallelWorkers: 1, maxCases: 3, useWorkflowEngine: true },
  };

  const toolFiles = [
    ['read-file.js', 'createReadFileTool', config],
    ['edit-file.js', 'createEditFileTool', config],
    ['write-file.js', 'createWriteFileTool', config],
    ['bash.js', 'createBashTool', config],
    ['grep.js', 'createGrepTool', config],
    ['glob.js', 'createGlobTool', config],
    ['todo-write.js', 'createTodoWriteTool', null],
    ['sub-agent.js', 'createSubAgentTool', null],
    ['ask-user.js', 'createAskUserTool', null],
    ['tool-search.js', 'createToolSearchTool', null],
    ['memory.js', 'createMemoryTool', config],
    ['doc-center.js', 'createDocCenterTool', config],
    ['component-fetch.js', 'createComponentFetchTool', config],
    ['browser-inspect.js', 'createBrowserInspectTool', config],
    ['vl-compile.js', 'createVLCompileTool', config],
    ['vl-lint.js', 'createVLLintTool', config],
    ['vl-parse.js', 'createVLParseTool', config],
    ['vl-syntax-ref.js', 'createVLSyntaxRefTool', config],
    ['vl-validate.js', 'createVLValidateTool', config],
    ['vl-metadata.js', 'createVLMetadataTool', config],
    ['vl-component-test.js', 'createVLComponentTestTool', config],
    ['vl-generate.js', 'createVLGenerateTool', config],
    ['vl-adjust.js', 'createVLAdjustTool', config],
    ['vl-edit-section.js', 'createVLEditSectionTool', config],
    ['vl-autofix.js', 'createVLAutoFixTool', config],
    ['vl-cascade-edit.js', 'createVLCascadeEditTool', config],
    ['vl-symbols.js', 'createVLSymbolsTool', config],
    ['vl-impact.js', 'createVLImpactTool', config],
    ['meta-diff.js', 'createMetaDiffTool', config],
    ['section-diff.js', 'createSectionDiffTool', config],
    ['vl-meta-test.js', 'createVLMetaTestTool', config],
    ['workflow-run.js', 'createWorkflowRunTool', config],
    ['workspace-api.js', 'createWorkspaceAPITool', config],
    ['autotest-pipeline.js', 'createAutoTestPipelineTool', config],
  ];

  for (const [file, fnName, arg] of toolFiles) {
    try {
      const mod = await import(`./src/tools/${file}`);
      const fn = mod[fnName] || mod.default;
      if (!fn) {
        // Check what's actually exported
        const exports = Object.keys(mod);
        throw new Error(`${fnName} not found. Exports: [${exports.join(', ')}]`);
      }
      if (typeof fn !== 'function') throw new Error(`${fnName} is ${typeof fn}, not function`);

      let tool;
      if (arg === null) {
        tool = fn();
      } else if (file === 'workspace-api.js') {
        const { LocalWorkspace } = await import('./src/engine/local-workspace.js');
        tool = fn(config, new LocalWorkspace('/tmp'));
      } else if (file === 'autotest-pipeline.js') {
        const { VLProjectContext } = await import('./src/vl/project-context.js');
        const ctx = new VLProjectContext('/tmp');
        tool = fn(config, ctx);
      } else {
        tool = fn(arg);
      }

      if (!tool) throw new Error('factory returned null/undefined');
      if (!tool.description) throw new Error('missing description');
      if (!tool.parameters) throw new Error('missing parameters');
      if (typeof tool.execute !== 'function') throw new Error('missing execute function');

      ok(file, `${fnName}() → tool with description + parameters + execute`);
    } catch (e) {
      fail(file, e.message);
    }
  }

  // Test tool registration integration
  try {
    const { ToolRegistry } = await import('./src/core/tool-registry.js');
    const { registerAllTools } = await import('./src/tools/index.js');
    const { VLProjectContext } = await import('./src/vl/project-context.js');
    const { LocalWorkspace } = await import('./src/engine/local-workspace.js');

    const reg = new ToolRegistry();
    const ctx = new VLProjectContext('/tmp');
    await ctx.load();
    registerAllTools(reg, config, ctx, { localWorkspace: new LocalWorkspace('/tmp') });
    const tools = reg.listTools();
    ok('index.js', `registerAllTools() registered ${tools.length} tools: ${tools.join(', ')}`);
  } catch (e) { fail('index.js (registerAllTools)', e.message); }
}

// ─── 8. Server ───────────────────────────────────────────────────────
async function testServer() {
  console.log('\n═══ server/ ═══');

  try {
    const { WebServer } = await import('./src/server/server.js');
    if (typeof WebServer !== 'function') throw new Error('not a class');
    ok('server.js', 'WebServer class import OK');
  } catch (e) { fail('server.js', e.message); }

  try {
    const mod = await import('./src/server/sse.js');
    if (typeof mod.setupSSE !== 'function') throw new Error('setupSSE not a function');
    ok('sse.js', 'setupSSE function OK');
  } catch (e) { fail('sse.js', e.message); }

  try {
    const mod = await import('./src/server/helpers.js');
    const fns = ['getCookie', 'clearCookie', 'saveCookie', 'loadWorkspaces', 'saveWorkspaces',
                 'ensureVLBible', 'hasVLFiles', 'ensureProjectProfile', 'ensureVLCodeHome'];
    const missing = fns.filter(f => typeof mod[f] !== 'function');
    if (missing.length > 0) throw new Error(`missing functions: ${missing.join(', ')}`);
    ok('helpers.js', `all ${fns.length} helper functions exported`);
  } catch (e) { fail('helpers.js', e.message); }

  try {
    const { WebServer } = await import('./src/server/index.js');
    if (typeof WebServer !== 'function') throw new Error('re-export failed');
    ok('index.js', 'WebServer re-export OK');
  } catch (e) { fail('server/index.js', e.message); }

  // Route modules — verify they export setup functions
  const routes = [
    'chat.js', 'files.js', 'project.js', 'workspace.js', 'compile.js',
    'workflow.js', 'cloud.js', 'intelligence.js', 'tools.js', 'conversation.js', 'misc.js'
  ];
  const setupFnNames = {
    'chat.js': 'setupChatRoutes',
    'files.js': 'setupFileRoutes',
    'project.js': 'setupProjectRoutes',
    'workspace.js': 'setupWorkspaceRoutes',
    'compile.js': 'setupCompileRoutes',
    'workflow.js': 'setupWorkflowRoutes',
    'cloud.js': 'setupCloudRoutes',
    'intelligence.js': 'setupIntelligenceRoutes',
    'tools.js': 'setupToolRoutes',
    'conversation.js': 'setupConversationRoutes',
    'misc.js': 'setupMiscRoutes',
  };

  for (const route of routes) {
    try {
      const mod = await import(`./src/server/routes/${route}`);
      const expectedFn = setupFnNames[route];
      if (expectedFn && typeof mod[expectedFn] !== 'function') {
        throw new Error(`${expectedFn} not found. Exports: [${Object.keys(mod).join(', ')}]`);
      }
      ok(`routes/${route}`, `${expectedFn}() exported`);
    } catch (e) {
      fail(`routes/${route}`, e.message);
    }
  }
}

// ─── 9. Autotest sub-modules ─────────────────────────────────────────
async function testAutotest() {
  console.log('\n═══ tools/autotest/ ═══');
  const files = [
    'test-generator.js', 'test-runner.js', 'test-evaluator.js',
    'auto-fixer.js', 'case-parser.js', 'report-generator.js',
    'workflow-builder.js', 'workflow-runner.js'
  ];
  for (const file of files) {
    try {
      const mod = await import(`./src/tools/autotest/${file}`);
      const exports = Object.keys(mod);
      if (exports.length === 0) throw new Error('no exports');
      ok(`autotest/${file}`, `exports: ${exports.join(', ')}`);
    } catch (e) {
      fail(`autotest/${file}`, e.message);
    }
  }
}

// ─── 10. Functional tests (deeper) ──────────────────────────────────
async function testFunctional() {
  console.log('\n═══ Functional Tests ═══');

  // ReadFile tool — actually read a file
  try {
    const { createReadFileTool } = await import('./src/tools/read-file.js');
    const tool = createReadFileTool({ workDir: '/tmp' });
    const result = await tool.execute({ file_path: path.join(__dirname, 'package.json') });
    const text = result.result || result;
    if (!text.includes('vlcode-lite')) throw new Error('ReadFile did not return package.json content');
    ok('ReadFile.execute', 'successfully reads package.json');
  } catch (e) { fail('ReadFile.execute', e.message); }

  // WriteFile + EditFile + ReadFile round-trip
  try {
    const { createWriteFileTool } = await import('./src/tools/write-file.js');
    const { createEditFileTool } = await import('./src/tools/edit-file.js');
    const { createReadFileTool } = await import('./src/tools/read-file.js');
    const cfg = { workDir: '/tmp' };

    const testFile = '/tmp/vlcode-lite-test-roundtrip.txt';
    const wt = createWriteFileTool(cfg);
    await wt.execute({ file_path: testFile, content: 'hello world' });

    const et = createEditFileTool(cfg);
    await et.execute({ file_path: testFile, old_string: 'hello', new_string: 'goodbye' });

    const rt = createReadFileTool(cfg);
    const readResult = await rt.execute({ file_path: testFile });
    const content = readResult.result || readResult;
    if (!content.includes('goodbye world')) throw new Error(`expected 'goodbye world', got: ${String(content).substring(0, 100)}`);
    ok('Write→Edit→Read roundtrip', 'file operations work correctly');
  } catch (e) { fail('Write→Edit→Read roundtrip', e.message); }

  // Bash tool
  try {
    const { createBashTool } = await import('./src/tools/bash.js');
    const tool = createBashTool({ workDir: '/tmp' });
    const result = await tool.execute({ command: 'echo "vlcode-lite-test"' });
    if (!result.includes('vlcode-lite-test')) throw new Error(`expected echo output, got: ${result}`);
    ok('Bash.execute', 'echo command works');
  } catch (e) { fail('Bash.execute', e.message); }

  // Grep tool
  try {
    const { createGrepTool } = await import('./src/tools/grep.js');
    const tool = createGrepTool({ workDir: __dirname });
    const result = await tool.execute({ pattern: 'vlcode-lite', path: path.join(__dirname, 'package.json') });
    if (!result) throw new Error('grep returned empty');
    ok('Grep.execute', 'finds "vlcode-lite" in package.json');
  } catch (e) { fail('Grep.execute', e.message); }

  // Glob tool
  try {
    const { createGlobTool } = await import('./src/tools/glob.js');
    const tool = createGlobTool({ workDir: __dirname });
    const result = await tool.execute({ pattern: 'src/core/*.js', path: __dirname });
    if (!result.includes('orchestrator.js')) throw new Error(`glob did not find orchestrator.js: ${result.substring(0, 200)}`);
    ok('Glob.execute', 'finds src/core/*.js files');
  } catch (e) { fail('Glob.execute', e.message); }

  // Memory tool
  try {
    const { createMemoryTool } = await import('./src/tools/memory.js');
    const tool = createMemoryTool({ workDir: '/tmp/vlcode-lite-mem-test' });
    await tool.execute({ operation: 'write', scope: 'project', key: 'test-key', value: 'test-value-123' });
    const readResult = await tool.execute({ operation: 'read', scope: 'project', key: 'test-key' });
    if (!readResult.includes('test-value-123')) throw new Error(`memory read failed: ${readResult}`);
    await tool.execute({ operation: 'delete', scope: 'project', key: 'test-key' });
    ok('Memory.execute', 'write/read/delete cycle works');
  } catch (e) { fail('Memory.execute', e.message); }

  // LocalWorkspace advanced
  try {
    const { LocalWorkspace } = await import('./src/engine/local-workspace.js');
    const lw = new LocalWorkspace('/tmp/vlcode-lite-lw-test');
    await lw.writeFiles({ gid: 'test', files: [
      { path: 'a.txt', content: 'aaa' },
      { path: 'sub/b.txt', content: 'bbb' },
    ]});
    const list = await lw.listFile({ gid: 'test' });
    if (!list.files || list.files.length < 2) throw new Error(`listFile should find >=2 files, got ${JSON.stringify(list)}`);
    const reads = await lw.readFiles({ gid: 'test', paths: ['a.txt', 'sub/b.txt'] });
    if (!reads.files || reads.files.length !== 2) throw new Error(`readFiles should return 2, got ${JSON.stringify(reads)}`);
    ok('LocalWorkspace batch', 'writeFiles/listFile/readFiles work');
  } catch (e) { fail('LocalWorkspace batch', e.message); }
}

// ─── Run all ─────────────────────────────────────────────────────────
async function main() {
  console.log('╔══════════════════════════════════════════════════╗');
  console.log('║  VLCode Lite — Module Verification Suite        ║');
  console.log('╚══════════════════════════════════════════════════╝');

  await testUtils();
  await testData();
  await testCore();
  await testVL();
  await testEngine();
  await testCloudMcp();
  await testTools();
  await testServer();
  await testAutotest();
  await testFunctional();

  console.log('\n══════════════════════════════════════════════════');
  console.log(`  Results: ${passCount} passed, ${failCount} failed, ${warnCount} warnings`);
  console.log('══════════════════════════════════════════════════');

  if (failCount > 0) {
    console.log('\n❌ FAILURES:');
    results.filter(r => r.includes('❌')).forEach(r => console.log(r));
  }
  if (warnCount > 0) {
    console.log('\n⚠️  WARNINGS:');
    results.filter(r => r.includes('⚠️')).forEach(r => console.log(r));
  }

  console.log('\n✅ PASSED:');
  results.filter(r => r.includes('✅')).forEach(r => console.log(r));

  process.exit(failCount > 0 ? 1 : 0);
}

main().catch(e => { console.error('FATAL:', e); process.exit(2); });
