#!/usr/bin/env node

/**
 * Twilio MCP Server — The Twilio MCP that doesn't suck.
 * Workflow-first tools, lazy loading, rich MCP Apps.
 */

import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
} from '@modelcontextprotocol/sdk/types.js';
import { parseCredentials } from './auth.js';
import { TwilioClient } from './client.js';
import { ToolRegistry } from './tool-registry.js';
import { LazyLoader, PACK_KEYWORDS } from './lazy-loader.js';
import type { BasePack } from './packs/base-pack.js';

// Import packs (Tier 1 always loaded, rest lazy)
import { Tier1Pack } from './packs/tier1/index.js';
import { MessagingPack } from './packs/messaging/index.js';
import { VoicePack } from './packs/voice/index.js';
import { IntelligencePack } from './packs/intelligence/index.js';
import { VerifyPack } from './packs/verify/index.js';
import { NumbersPack } from './packs/numbers/index.js';
import { StudioPack } from './packs/studio/index.js';
import { ContactCenterPack } from './packs/contact-center/index.js';
import { ConversationsPack } from './packs/conversations/index.js';
import { AnalyticsPack } from './packs/analytics/index.js';
import { ServerlessPack } from './packs/serverless/index.js';
import { CompliancePack } from './packs/compliance/index.js';

async function main() {
  // Parse credentials from CLI args or env
  const credArg = process.argv[2];
  const credentials = parseCredentials(credArg);
  const twilioClient = new TwilioClient(credentials);

  // Create registry and lazy loader
  const registry = new ToolRegistry();
  const loader = new LazyLoader(registry, twilioClient);

  // Create MCP server (low-level for lazy loading support)
  const server = new Server(
    { name: 'twilio-mcp', version: '0.1.0' },
    { capabilities: { tools: { listChanged: true } } }
  );

  // Wire up tools/list_changed notifications
  registry.setOnToolsChanged(() => {
    server.notification({ method: 'notifications/tools/list_changed' });
  });

  // Initialize Tier 1 (always loaded)
  const tier1 = new Tier1Pack(twilioClient, loader);
  tier1.setup();
  registry.registerPack('tier1', tier1.getTools());

  // Register lazy-loadable packs
  const lazyPacks: Array<{ PackClass: new (client: TwilioClient) => BasePack; name: string }> = [
    { PackClass: MessagingPack, name: 'messaging' },
    { PackClass: VoicePack, name: 'voice' },
    { PackClass: IntelligencePack, name: 'intelligence' },
    { PackClass: VerifyPack, name: 'verify' },
    { PackClass: NumbersPack, name: 'numbers' },
    { PackClass: StudioPack, name: 'studio' },
    { PackClass: ContactCenterPack, name: 'contact-center' },
    { PackClass: ConversationsPack, name: 'conversations' },
    { PackClass: AnalyticsPack, name: 'analytics' },
    { PackClass: ServerlessPack, name: 'serverless' },
    { PackClass: CompliancePack, name: 'compliance' },
  ];

  for (const { PackClass, name } of lazyPacks) {
    const keywords = PACK_KEYWORDS[name] || [];
    loader.registerPack({
      name,
      description: `${name} tools and apps`,
      keywords,
      loadTools: (client) => {
        const pack = new PackClass(client);
        pack.setup();
        return pack.getTools();
      },
    });
  }

  // Handle tools/list requests
  server.setRequestHandler(ListToolsRequestSchema, async () => ({
    tools: registry.toMCPToolsList(),
  }));

  // Handle tools/call requests
  server.setRequestHandler(CallToolRequestSchema, async (request) => {
    const { name, arguments: args } = request.params;
    const tool = registry.get(name);

    if (!tool) {
      return {
        content: [{ type: 'text' as const, text: `Unknown tool: ${name}` }],
        isError: true,
      };
    }

    try {
      const parsed = tool.inputSchema.parse(args || {});
      const result = await tool.handler(parsed);
      return result as any;
    } catch (err: unknown) {
      const message = err instanceof Error ? err.message : String(err);
      return {
        content: [{ type: 'text' as const, text: `Error: ${message}` }],
        isError: true,
      };
    }
  });

  // Start the server
  const transport = new StdioServerTransport();
  await server.connect(transport);
}

main().catch((err) => {
  console.error('Fatal error:', err);
  process.exit(1);
});
