/**
 * Basecamp MCP Server
 */

import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
  ErrorCode,
  McpError,
} from '@modelcontextprotocol/sdk/types.js';
import { BasecampClient } from './clients/basecamp.js';
import { registerProjectsTools } from './tools/projects-tools.js';
import { registerTodolistsTools } from './tools/todolists-tools.js';
import { registerTodosTools } from './tools/todos-tools.js';
import { registerMessagesTools } from './tools/messages-tools.js';
import { registerCommentsTools } from './tools/comments-tools.js';
import { registerCampfiresTools } from './tools/campfires-tools.js';
import { registerSchedulesTools } from './tools/schedules-tools.js';
import { registerDocumentsTools } from './tools/documents-tools.js';
import { registerUploadsTools } from './tools/uploads-tools.js';
import { registerPeopleTools } from './tools/people-tools.js';
import { registerQuestionnairesTools } from './tools/questionnaires-tools.js';
import { registerWebhooksTools } from './tools/webhooks-tools.js';
import { registerRecordingsTools } from './tools/recordings-tools.js';

interface BasecampServerConfig {
  accountId: string;
  accessToken: string;
  userAgent?: string;
}

export class BasecampServer {
  private server: Server;
  private client: BasecampClient;
  private tools: Map<string, any>;

  constructor(config: BasecampServerConfig) {
    this.server = new Server(
      {
        name: 'basecamp-mcp-server',
        version: '1.0.0',
      },
      {
        capabilities: {
          tools: {},
        },
      }
    );

    this.client = new BasecampClient({
      accountId: config.accountId,
      accessToken: config.accessToken,
      userAgent: config.userAgent,
    });

    this.tools = new Map();
    this.registerAllTools();
    this.setupHandlers();

    // Error handling
    this.server.onerror = (error) => {
      console.error('[MCP Error]', error);
    };

    process.on('SIGINT', async () => {
      await this.server.close();
      process.exit(0);
    });
  }

  private registerAllTools() {
    const toolRegistrars = [
      registerProjectsTools,
      registerTodolistsTools,
      registerTodosTools,
      registerMessagesTools,
      registerCommentsTools,
      registerCampfiresTools,
      registerSchedulesTools,
      registerDocumentsTools,
      registerUploadsTools,
      registerPeopleTools,
      registerQuestionnairesTools,
      registerWebhooksTools,
      registerRecordingsTools,
    ];

    for (const registrar of toolRegistrars) {
      const tools = registrar(this.client);
      for (const tool of tools) {
        this.tools.set(tool.name, tool);
      }
    }

    console.error(`[Basecamp MCP] Registered ${this.tools.size} tools`);
  }

  private setupHandlers() {
    // List available tools
    this.server.setRequestHandler(ListToolsRequestSchema, async () => {
      const tools = Array.from(this.tools.values()).map((tool) => ({
        name: tool.name,
        description: tool.description,
        inputSchema: tool.inputSchema,
      }));

      return { tools };
    });

    // Handle tool calls
    this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
      const { name, arguments: args } = request.params;

      const tool = this.tools.get(name);
      if (!tool) {
        throw new McpError(
          ErrorCode.MethodNotFound,
          `Tool not found: ${name}`
        );
      }

      try {
        return await tool.handler(args || {});
      } catch (error: any) {
        const errorMessage = error.message || 'Unknown error occurred';
        console.error(`[Tool Error] ${name}:`, errorMessage);
        
        throw new McpError(
          ErrorCode.InternalError,
          `Tool execution failed: ${errorMessage}`
        );
      }
    });
  }

  async run() {
    const transport = new StdioServerTransport();
    await this.server.connect(transport);
    console.error('[Basecamp MCP] Server running on stdio');
  }
}
