/**
 * Intercom MCP Server
 * Lazy-loaded tools for Intercom API integration
 */

import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
  Tool,
} from '@modelcontextprotocol/sdk/types.js';
import { IntercomClient } from './clients/intercom.js';
import { z } from 'zod';

export class IntercomMCPServer {
  private server: Server;
  private client: IntercomClient;
  private toolsMap: Map<string, Tool>;

  constructor(accessToken: string) {
    this.client = new IntercomClient({ accessToken });
    this.server = new Server(
      {
        name: '@mcpengine/intercom',
        version: '1.0.0',
      },
      {
        capabilities: {
          tools: {},
        },
      }
    );

    this.toolsMap = new Map();
    this.setupHandlers();
    this.registerTools();
  }

  private setupHandlers(): void {
    this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
      tools: Array.from(this.toolsMap.values()),
    }));

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

      try {
        const result = await this.executeTool(name, args || {});
        return {
          content: [
            {
              type: 'text',
              text: JSON.stringify(result, null, 2),
            },
          ],
        };
      } catch (error) {
        const errorMessage = error instanceof Error ? error.message : String(error);
        return {
          content: [
            {
              type: 'text',
              text: `Error: ${errorMessage}`,
            },
          ],
          isError: true,
        };
      }
    });
  }

  private registerTools(): void {
    // Contacts
    this.toolsMap.set('contacts_create', {
      name: 'contacts_create',
      description: 'Create a new contact (user or lead) in Intercom',
      inputSchema: {
        type: 'object',
        properties: {
          role: { type: 'string', enum: ['user', 'lead'], description: 'Contact role' },
          external_id: { type: 'string', description: 'External unique identifier' },
          email: { type: 'string', description: 'Email address' },
          phone: { type: 'string', description: 'Phone number' },
          name: { type: 'string', description: 'Full name' },
          signed_up_at: { type: 'number', description: 'Unix timestamp of signup' },
          custom_attributes: { type: 'object', description: 'Custom attributes object' },
        },
      },
    });

    this.toolsMap.set('contacts_get', {
      name: 'contacts_get',
      description: 'Retrieve a contact by ID',
      inputSchema: {
        type: 'object',
        properties: {
          id: { type: 'string', description: 'Contact ID' },
        },
        required: ['id'],
      },
    });

    this.toolsMap.set('contacts_update', {
      name: 'contacts_update',
      description: 'Update a contact',
      inputSchema: {
        type: 'object',
        properties: {
          id: { type: 'string', description: 'Contact ID' },
          email: { type: 'string' },
          name: { type: 'string' },
          phone: { type: 'string' },
          custom_attributes: { type: 'object' },
        },
        required: ['id'],
      },
    });

    this.toolsMap.set('contacts_delete', {
      name: 'contacts_delete',
      description: 'Delete a contact permanently',
      inputSchema: {
        type: 'object',
        properties: {
          id: { type: 'string', description: 'Contact ID' },
        },
        required: ['id'],
      },
    });

    this.toolsMap.set('contacts_list', {
      name: 'contacts_list',
      description: 'List all contacts with cursor pagination',
      inputSchema: {
        type: 'object',
        properties: {
          per_page: { type: 'number', description: 'Results per page (max 150)' },
          starting_after: { type: 'string', description: 'Cursor for pagination' },
        },
      },
    });

    this.toolsMap.set('contacts_search', {
      name: 'contacts_search',
      description: 'Search contacts using filters',
      inputSchema: {
        type: 'object',
        properties: {
          query: { type: 'object', description: 'Search filter object' },
          pagination: { type: 'object', description: 'Pagination params' },
          sort: { type: 'object', description: 'Sort configuration' },
        },
      },
    });

    // Conversations
    this.toolsMap.set('conversations_create', {
      name: 'conversations_create',
      description: 'Create a new conversation',
      inputSchema: {
        type: 'object',
        properties: {
          from: {
            type: 'object',
            description: 'Sender info (type, id/user_id/email)',
            properties: {
              type: { type: 'string', enum: ['user', 'lead', 'contact'] },
              id: { type: 'string' },
              user_id: { type: 'string' },
              email: { type: 'string' },
            },
            required: ['type'],
          },
          body: { type: 'string', description: 'Message body' },
        },
        required: ['from', 'body'],
      },
    });

    this.toolsMap.set('conversations_get', {
      name: 'conversations_get',
      description: 'Retrieve a conversation by ID',
      inputSchema: {
        type: 'object',
        properties: {
          id: { type: 'string', description: 'Conversation ID' },
        },
        required: ['id'],
      },
    });

    this.toolsMap.set('conversations_list', {
      name: 'conversations_list',
      description: 'List conversations',
      inputSchema: {
        type: 'object',
        properties: {
          per_page: { type: 'number' },
          starting_after: { type: 'string' },
        },
      },
    });

    this.toolsMap.set('conversations_search', {
      name: 'conversations_search',
      description: 'Search conversations using filters',
      inputSchema: {
        type: 'object',
        properties: {
          query: { type: 'object', description: 'Search filter' },
          pagination: { type: 'object' },
        },
      },
    });

    this.toolsMap.set('conversations_reply', {
      name: 'conversations_reply',
      description: 'Reply to a conversation',
      inputSchema: {
        type: 'object',
        properties: {
          id: { type: 'string', description: 'Conversation ID' },
          message_type: { type: 'string', enum: ['comment', 'note'] },
          type: { type: 'string', enum: ['admin', 'user'] },
          admin_id: { type: 'string', description: 'Admin ID (if type=admin)' },
          body: { type: 'string', description: 'Reply body' },
          attachment_urls: { type: 'array', items: { type: 'string' } },
        },
        required: ['id', 'message_type', 'type', 'body'],
      },
    });

    this.toolsMap.set('conversations_close', {
      name: 'conversations_close',
      description: 'Close a conversation',
      inputSchema: {
        type: 'object',
        properties: {
          id: { type: 'string', description: 'Conversation ID' },
          admin_id: { type: 'string', description: 'Admin ID' },
        },
        required: ['id', 'admin_id'],
      },
    });

    this.toolsMap.set('conversations_assign', {
      name: 'conversations_assign',
      description: 'Assign a conversation to an admin or team',
      inputSchema: {
        type: 'object',
        properties: {
          id: { type: 'string', description: 'Conversation ID' },
          assignee_type: { type: 'string', enum: ['admin', 'team'] },
          assignee_id: { type: 'string', description: 'Admin or Team ID' },
          admin_id: { type: 'string', description: 'Admin making the assignment' },
        },
        required: ['id', 'assignee_type', 'assignee_id'],
      },
    });

    // Companies
    this.toolsMap.set('companies_create', {
      name: 'companies_create',
      description: 'Create a new company',
      inputSchema: {
        type: 'object',
        properties: {
          name: { type: 'string', description: 'Company name' },
          company_id: { type: 'string', description: 'Unique company ID' },
          website: { type: 'string' },
          plan: { type: 'string' },
          size: { type: 'number' },
          industry: { type: 'string' },
          monthly_spend: { type: 'number' },
          custom_attributes: { type: 'object' },
        },
        required: ['name'],
      },
    });

    this.toolsMap.set('companies_get', {
      name: 'companies_get',
      description: 'Retrieve a company by ID',
      inputSchema: {
        type: 'object',
        properties: {
          id: { type: 'string', description: 'Company ID' },
        },
        required: ['id'],
      },
    });

    this.toolsMap.set('companies_list', {
      name: 'companies_list',
      description: 'List companies',
      inputSchema: {
        type: 'object',
        properties: {
          per_page: { type: 'number' },
          starting_after: { type: 'string' },
        },
      },
    });

    this.toolsMap.set('companies_update', {
      name: 'companies_update',
      description: 'Update a company',
      inputSchema: {
        type: 'object',
        properties: {
          id: { type: 'string', description: 'Company ID' },
          name: { type: 'string' },
          website: { type: 'string' },
          plan: { type: 'string' },
          size: { type: 'number' },
          monthly_spend: { type: 'number' },
          custom_attributes: { type: 'object' },
        },
        required: ['id'],
      },
    });

    // Articles
    this.toolsMap.set('articles_create', {
      name: 'articles_create',
      description: 'Create a help center article',
      inputSchema: {
        type: 'object',
        properties: {
          title: { type: 'string', description: 'Article title' },
          description: { type: 'string' },
          body: { type: 'string', description: 'Article body (HTML or markdown)' },
          author_id: { type: 'string', description: 'Admin ID' },
          state: { type: 'string', enum: ['published', 'draft'] },
          parent_id: { type: 'string', description: 'Collection or Section ID' },
          parent_type: { type: 'string', enum: ['collection', 'section'] },
        },
        required: ['title', 'author_id'],
      },
    });

    this.toolsMap.set('articles_get', {
      name: 'articles_get',
      description: 'Retrieve an article by ID',
      inputSchema: {
        type: 'object',
        properties: {
          id: { type: 'string', description: 'Article ID' },
        },
        required: ['id'],
      },
    });

    this.toolsMap.set('articles_list', {
      name: 'articles_list',
      description: 'List all articles',
      inputSchema: {
        type: 'object',
        properties: {
          per_page: { type: 'number' },
          page: { type: 'number' },
        },
      },
    });

    this.toolsMap.set('articles_update', {
      name: 'articles_update',
      description: 'Update an article',
      inputSchema: {
        type: 'object',
        properties: {
          id: { type: 'string', description: 'Article ID' },
          title: { type: 'string' },
          body: { type: 'string' },
          state: { type: 'string', enum: ['published', 'draft'] },
        },
        required: ['id'],
      },
    });

    this.toolsMap.set('articles_delete', {
      name: 'articles_delete',
      description: 'Delete an article',
      inputSchema: {
        type: 'object',
        properties: {
          id: { type: 'string', description: 'Article ID' },
        },
        required: ['id'],
      },
    });

    // Help Center
    this.toolsMap.set('help-center_list', {
      name: 'help-center_list',
      description: 'List all help centers',
      inputSchema: {
        type: 'object',
        properties: {},
      },
    });

    this.toolsMap.set('help-center_collections_list', {
      name: 'help-center_collections_list',
      description: 'List help center collections',
      inputSchema: {
        type: 'object',
        properties: {
          per_page: { type: 'number' },
          page: { type: 'number' },
        },
      },
    });

    this.toolsMap.set('help-center_collections_create', {
      name: 'help-center_collections_create',
      description: 'Create a collection',
      inputSchema: {
        type: 'object',
        properties: {
          name: { type: 'string', description: 'Collection name' },
          description: { type: 'string' },
        },
        required: ['name'],
      },
    });

    // Tickets
    this.toolsMap.set('tickets_create', {
      name: 'tickets_create',
      description: 'Create a ticket',
      inputSchema: {
        type: 'object',
        properties: {
          ticket_type_id: { type: 'string', description: 'Ticket type ID' },
          contacts: {
            type: 'array',
            items: {
              type: 'object',
              properties: {
                id: { type: 'string' },
                external_id: { type: 'string' },
                email: { type: 'string' },
              },
            },
          },
          ticket_attributes: { type: 'object', description: 'Ticket custom attributes' },
        },
        required: ['ticket_type_id'],
      },
    });

    this.toolsMap.set('tickets_get', {
      name: 'tickets_get',
      description: 'Retrieve a ticket by ID',
      inputSchema: {
        type: 'object',
        properties: {
          id: { type: 'string', description: 'Ticket ID' },
        },
        required: ['id'],
      },
    });

    this.toolsMap.set('tickets_list', {
      name: 'tickets_list',
      description: 'List tickets',
      inputSchema: {
        type: 'object',
        properties: {
          per_page: { type: 'number' },
          page: { type: 'number' },
        },
      },
    });

    this.toolsMap.set('tickets_search', {
      name: 'tickets_search',
      description: 'Search tickets',
      inputSchema: {
        type: 'object',
        properties: {
          query: { type: 'object' },
        },
      },
    });

    this.toolsMap.set('tickets_types_list', {
      name: 'tickets_types_list',
      description: 'List all ticket types',
      inputSchema: {
        type: 'object',
        properties: {},
      },
    });

    // Tags
    this.toolsMap.set('tags_create', {
      name: 'tags_create',
      description: 'Create a tag',
      inputSchema: {
        type: 'object',
        properties: {
          name: { type: 'string', description: 'Tag name' },
        },
        required: ['name'],
      },
    });

    this.toolsMap.set('tags_list', {
      name: 'tags_list',
      description: 'List all tags',
      inputSchema: {
        type: 'object',
        properties: {},
      },
    });

    this.toolsMap.set('tags_delete', {
      name: 'tags_delete',
      description: 'Delete a tag',
      inputSchema: {
        type: 'object',
        properties: {
          id: { type: 'string', description: 'Tag ID' },
        },
        required: ['id'],
      },
    });

    // Segments
    this.toolsMap.set('segments_list', {
      name: 'segments_list',
      description: 'List all segments',
      inputSchema: {
        type: 'object',
        properties: {
          include_count: { type: 'boolean', description: 'Include member count' },
        },
      },
    });

    this.toolsMap.set('segments_get', {
      name: 'segments_get',
      description: 'Retrieve a segment by ID',
      inputSchema: {
        type: 'object',
        properties: {
          id: { type: 'string', description: 'Segment ID' },
        },
        required: ['id'],
      },
    });

    // Events
    this.toolsMap.set('events_submit', {
      name: 'events_submit',
      description: 'Submit an event',
      inputSchema: {
        type: 'object',
        properties: {
          event_name: { type: 'string', description: 'Event name' },
          created_at: { type: 'number', description: 'Unix timestamp' },
          user_id: { type: 'string' },
          email: { type: 'string' },
          metadata: { type: 'object', description: 'Event metadata' },
        },
        required: ['event_name'],
      },
    });

    // Messages
    this.toolsMap.set('messages_send', {
      name: 'messages_send',
      description: 'Send a message (email, in-app, push)',
      inputSchema: {
        type: 'object',
        properties: {
          message_type: { type: 'string', enum: ['inapp', 'email', 'push'] },
          subject: { type: 'string' },
          body: { type: 'string' },
          from: { type: 'object', description: 'Sender (admin)' },
          to: { type: 'object', description: 'Recipient (contact/user/lead)' },
        },
        required: ['message_type', 'body'],
      },
    });

    // Teams
    this.toolsMap.set('teams_list', {
      name: 'teams_list',
      description: 'List all teams',
      inputSchema: {
        type: 'object',
        properties: {},
      },
    });

    this.toolsMap.set('teams_get', {
      name: 'teams_get',
      description: 'Retrieve a team by ID',
      inputSchema: {
        type: 'object',
        properties: {
          id: { type: 'string', description: 'Team ID' },
        },
        required: ['id'],
      },
    });

    // Admins
    this.toolsMap.set('admins_list', {
      name: 'admins_list',
      description: 'List all admins',
      inputSchema: {
        type: 'object',
        properties: {},
      },
    });

    this.toolsMap.set('admins_get', {
      name: 'admins_get',
      description: 'Retrieve an admin by ID',
      inputSchema: {
        type: 'object',
        properties: {
          id: { type: 'string', description: 'Admin ID' },
        },
        required: ['id'],
      },
    });
  }

  private async executeTool(name: string, args: Record<string, unknown>): Promise<unknown> {
    switch (name) {
      // Contacts
      case 'contacts_create':
        return this.client.createContact(args as any);
      case 'contacts_get':
        return this.client.getContact(args.id as any);
      case 'contacts_update':
        return this.client.updateContact(args.id as any, args as any);
      case 'contacts_delete':
        return this.client.deleteContact(args.id as any);
      case 'contacts_list':
        return this.client.listContacts(args as any);
      case 'contacts_search':
        return this.client.searchContacts(args as any);

      // Conversations
      case 'conversations_create':
        return this.client.createConversation(args as any);
      case 'conversations_get':
        return this.client.getConversation(args.id as any);
      case 'conversations_list':
        return this.client.listConversations(args as any);
      case 'conversations_search':
        return this.client.searchConversations(args as any);
      case 'conversations_reply':
        return this.client.replyToConversation(args.id as any, args as any);
      case 'conversations_close':
        return this.client.closeConversation(args.id as any, args.admin_id as any);
      case 'conversations_assign':
        return this.client.assignConversation(args.id as any, {
          type: args.assignee_type as any,
          id: args.assignee_id as any,
          admin_id: args.admin_id as any,
        });

      // Companies
      case 'companies_create':
        return this.client.createCompany(args as any);
      case 'companies_get':
        return this.client.getCompany(args.id as any);
      case 'companies_list':
        return this.client.listCompanies(args as any);
      case 'companies_update':
        return this.client.updateCompany(args.id as any, args as any);

      // Articles
      case 'articles_create':
        return this.client.createArticle(args as any);
      case 'articles_get':
        return this.client.getArticle(args.id as any);
      case 'articles_list':
        return this.client.listArticles(args as any);
      case 'articles_update':
        return this.client.updateArticle(args.id as any, args as any);
      case 'articles_delete':
        return this.client.deleteArticle(args.id as any);

      // Help Center
      case 'help-center_list':
        return this.client.listHelpCenters();
      case 'help-center_collections_list':
        return this.client.listCollections(args as any);
      case 'help-center_collections_create':
        return this.client.createCollection(args as any);

      // Tickets
      case 'tickets_create':
        return this.client.createTicket(args as any);
      case 'tickets_get':
        return this.client.getTicket(args.id as any);
      case 'tickets_list':
        return this.client.listTickets(args as any);
      case 'tickets_search':
        return this.client.searchTickets(args as any);
      case 'tickets_types_list':
        return this.client.listTicketTypes();

      // Tags
      case 'tags_create':
        return this.client.createTag(args.name as string);
      case 'tags_list':
        return this.client.listTags();
      case 'tags_delete':
        return this.client.deleteTag(args.id as any);

      // Segments
      case 'segments_list':
        return this.client.listSegments(args as any);
      case 'segments_get':
        return this.client.getSegment(args.id as any);

      // Events
      case 'events_submit':
        return this.client.submitEvent(args as any);

      // Messages
      case 'messages_send':
        return this.client.sendMessage(args as any);

      // Teams
      case 'teams_list':
        return this.client.listTeams();
      case 'teams_get':
        return this.client.getTeam(args.id as any);

      // Admins
      case 'admins_list':
        return this.client.listAdmins();
      case 'admins_get':
        return this.client.getAdmin(args.id as any);

      default:
        throw new Error(`Unknown tool: ${name}`);
    }
  }

  async run(): Promise<void> {
    const transport = new StdioServerTransport();
    await this.server.connect(transport);
    console.error('Intercom MCP Server running on stdio');
  }
}
