import { describe, it, expect, beforeEach, vi } from 'vitest';
import Database from 'better-sqlite3';
import { runMigrations } from '../db/migrate.js';
import { createRegistry } from './registry.js';
import { createTokenManager } from './token-manager.js';
import { createToolCache } from './tool-cache.js';
import { createAggregator } from './aggregator.js';

describe('createAggregator', () => {
  const validKey = 'a'.repeat(64);
  let db: Database.Database;

  beforeEach(() => {
    process.env.MCP_ENCRYPTION_KEY = validKey;
    db = new Database(':memory:');
    db.exec(`CREATE TABLE users (id TEXT PRIMARY KEY);`);
    db.exec(`CREATE TABLE jobs (id TEXT PRIMARY KEY, wait_reason TEXT);`);
    db.exec(`CREATE TABLE local_tasks (id INTEGER PRIMARY KEY AUTOINCREMENT);`);
    runMigrations(db);
    db.prepare('INSERT INTO users(id) VALUES(?)').run('u1');
    const reg = createRegistry(db);
    reg.upsert({
      id: 'canva',
      name: 'Canva',
      url: 'https://mcp.canva.example/mcp',
      authKind: 'oauth',
      ownerId: null,
      oauthClientId: 'cid',
      oauthClientSecret: 'cs',
      oauthScopes: null,
    });
    const cache = createToolCache(db, 600);
    cache.replaceForServer('canva', [
      { name: 'generate_designs', description: 'g', inputSchema: { type: 'object', properties: {} } },
    ]);
  });

  it('returns ToolDefs only for servers the user is connected to', async () => {
    const tm = createTokenManager(db, { doRefresh: async () => ({ access_token: 'x' }) });
    const agg = createAggregator({
      registry: createRegistry(db),
      tokenManager: tm,
      toolCache: createToolCache(db, 600),
      executeCall: vi.fn(),
    });

    // No token → empty
    let defs = await agg.getToolDefs('u1', ['mcp__canva__*']);
    expect(defs).toEqual([]);

    tm.saveTokens({
      userId: 'u1',
      serverId: 'canva',
      accessToken: 'at',
      refreshToken: 'rt',
      expiresAt: new Date(Date.now() + 3600_000).toISOString(),
      scope: null,
    });

    defs = await agg.getToolDefs('u1', ['mcp__canva__*']);
    expect(defs).toHaveLength(1);
    expect(defs[0].function.name).toBe('mcp__canva__generate_designs');
  });

  it('delegates executeTool for mcp__ names and returns null otherwise', async () => {
    const executeCall = vi.fn().mockResolvedValue({ output: 'ok', isError: false });
    const agg = createAggregator({
      registry: createRegistry(db),
      tokenManager: createTokenManager(db, { doRefresh: async () => ({ access_token: 'x' }) }),
      toolCache: createToolCache(db, 600),
      executeCall,
    });

    const other = await agg.executeTool('Read', {}, { workspacePath: '/tmp', ownerId: 'u1', jobId: 'j' } as never);
    expect(other).toBeNull();

    const bad = await agg.executeTool('mcp__bad__name__extra', {}, { workspacePath: '/tmp', ownerId: 'u1', jobId: 'j' } as never);
    expect(bad?.isError).toBe(true);
  });
});
