/**
 * Smoke test: favourite-index tool presentation end-to-end.
 *
 * Provisions an ungated project with favourite-index enabled + two pinned tools
 * from the smoke-aws-docs server, then verifies through the LIVE mcplocal proxy:
 *   - initialize instructions carry the load-bearing "prefer favourite/" line,
 *   - tools/list presents favourite/<tool> (curated) + all/<server>/<tool> (full),
 *   - a favourite/ call and an all/ call both ROUTE to the real upstream
 *     (they reach the server's arg validation, not a -32601 "unknown tool").
 *
 * Run with: pnpm test:smoke
 */
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import { SmokeMcpSession, isMcplocalRunning, mcpctl } from './mcp-client.js';
import { ChatReporter } from './reporter.js';
import { resolve } from 'node:path';

const PROJECT_NAME = 'smoke-favindex';
const SMOKE_DATA = 'smoke-data';
const FIXTURE_PATH = resolve(import.meta.dirname, 'fixtures', 'smoke-data.yaml');
const FAV_TOOL = 'smoke-aws-docs/read_documentation';

describe('Smoke: favourite-index presentation', () => {
  let ready = false;

  beforeAll(async () => {
    console.log('\n  ━━━ Smoke Test: favourite-index ━━━');
    if (!(await isMcplocalRunning())) {
      console.log('  ✗ mcplocal not running — skipping\n');
      return;
    }

    // Ensure the shared smoke-aws-docs server exists (from the smoke-data fixture).
    try {
      await mcpctl(`describe project ${SMOKE_DATA}`);
    } catch {
      try { await mcpctl(`apply -f ${FIXTURE_PATH}`); } catch { /* best effort */ }
    }

    // Dedicated ungated project with favourite-index on + two pins.
    try {
      await mcpctl(
        `create project ${PROJECT_NAME} --force --no-gated --server smoke-aws-docs ` +
          `--favourite-index --favourite ${FAV_TOOL} --favourite smoke-aws-docs/search_documentation`,
      );
    } catch (err) {
      console.log(`  ⚠ project setup error: ${err instanceof Error ? err.message : err}`);
      return;
    }

    const preflight = new SmokeMcpSession(PROJECT_NAME);
    try {
      await preflight.initialize();
      ready = true;
      console.log('  ✓ Server responding');
    } catch (err) {
      console.log(`  ✗ Server not responding: ${err instanceof Error ? err.message : err}`);
    } finally {
      await preflight.close();
    }
  }, 60_000);

  afterAll(async () => {
    try { await mcpctl(`delete project ${PROJECT_NAME}`); } catch { /* best effort cleanup */ }
    console.log('\n  ━━━ favourite-index smoke complete ━━━\n');
  });

  it('presents favourite/ + all/ namespaces with the prefer-favourite instruction', async () => {
    if (!ready) return;
    const chat = new ChatReporter(new SmokeMcpSession(PROJECT_NAME));
    chat.section('favourite-index presentation');
    try {
      const initResult = (await chat.initialize()) as { instructions?: string };
      const instructions = initResult?.instructions ?? '';
      chat.check('Instruction mentions favourite/', String(instructions.includes('favourite/')), (v) => v === 'true');
      expect(instructions).toContain('favourite/');

      const tools = await chat.listTools();
      const names = tools.map((t) => t.name);
      const favNames = names.filter((n) => n.startsWith('favourite/'));
      const allNames = names.filter((n) => n.startsWith('all/'));

      chat.check('Has favourite/ tools', favNames.length, (v) => v >= 1);
      chat.check('Has all/ catalog', allNames.length, (v) => v >= 1);
      chat.check('favourite/read_documentation present', String(names.includes('favourite/read_documentation')), (v) => v === 'true');
      chat.check('all/smoke-aws-docs/read_documentation present', String(names.includes('all/smoke-aws-docs/read_documentation')), (v) => v === 'true');

      // Favourites are listed before the all/ catalog.
      const firstFav = names.findIndex((n) => n.startsWith('favourite/'));
      const firstAll = names.findIndex((n) => n.startsWith('all/'));
      chat.check('favourites precede all/', String(firstFav < firstAll), (v) => v === 'true');

      expect(names).toContain('favourite/read_documentation');
      expect(names).toContain('all/smoke-aws-docs/read_documentation');
      expect(firstFav).toBeLessThan(firstAll);
    } finally {
      await chat.close();
    }
  }, 30_000);

  it('routes favourite/ and all/ calls to the real upstream tool', async () => {
    if (!ready) return;
    const chat = new ChatReporter(new SmokeMcpSession(PROJECT_NAME));
    chat.section('favourite-index routing');
    try {
      await chat.initialize();
      await chat.listTools(); // real clients list before calling — populates the resolver

      // Calling with no args → the UPSTREAM tool's arg validation fires, proving
      // the presented name routed to the real server (not a -32601 unknown tool).
      const favRes = await chat.callTool('favourite/read_documentation', {}, 20_000).catch((e: Error) => ({ error: e.message }));
      const allRes = await chat.callTool('all/smoke-aws-docs/read_documentation', {}, 20_000).catch((e: Error) => ({ error: e.message }));

      const favStr = JSON.stringify(favRes).toLowerCase();
      const allStr = JSON.stringify(allRes).toLowerCase();
      // Reached the upstream (arg validation / real response), not "unknown tool".
      const routed = (s: string): boolean => !s.includes('-32601') && !s.includes('unknown') && !s.includes('method not found');
      chat.check('favourite/ routed to upstream', String(routed(favStr)), (v) => v === 'true');
      chat.check('all/ routed to upstream', String(routed(allStr)), (v) => v === 'true');
      expect(routed(favStr)).toBe(true);
      expect(routed(allStr)).toBe(true);
    } finally {
      await chat.close();
    }
  }, 30_000);
});
