/**
 * GoHighLevel MCP Apps Server (Slimmed Down)
 * Only includes MCP Apps - no other tools
 */

import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
  CallToolRequestSchema,
  ErrorCode,
  ListToolsRequestSchema,
  ListResourcesRequestSchema,
  ReadResourceRequestSchema,
  McpError
} from '@modelcontextprotocol/sdk/types.js';
import * as dotenv from 'dotenv';

import { GHLApiClient } from './clients/ghl-api-client.js';
import { MCPAppsManager } from './apps/index.js';
import { GHLConfig } from './types/ghl-types.js';

// Load environment variables
dotenv.config();

/**
 * MCP Apps Only Server
 */
class GHLMCPAppsServer {
  private server: Server;
  private ghlClient: GHLApiClient;
  private mcpAppsManager: MCPAppsManager;

  constructor() {
    // Initialize MCP server with capabilities
    this.server = new Server(
      {
        name: 'ghl-mcp-apps-only',
        version: '1.0.0',
      },
      {
        capabilities: {
          tools: {},
          resources: {},
        },
      }
    );

    // Initialize GHL API client
    this.ghlClient = this.initializeGHLClient();

    // Initialize MCP Apps Manager
    this.mcpAppsManager = new MCPAppsManager(this.ghlClient);

    this.setupHandlers();
    this.setupErrorHandling();
  }

  /**
   * Initialize the GHL API client with config from environment
   */
  private initializeGHLClient(): GHLApiClient {
    const config: GHLConfig = {
      accessToken: process.env.GHL_API_KEY || '',
      locationId: process.env.GHL_LOCATION_ID || '',
      baseUrl: process.env.GHL_BASE_URL || 'https://services.leadconnectorhq.com',
      version: '2021-07-28'
    };

    if (!config.accessToken) {
      process.stderr.write('Warning: GHL_API_KEY not set in environment\n');
    }
    if (!config.locationId) {
      process.stderr.write('Warning: GHL_LOCATION_ID not set in environment\n');
    }

    return new GHLApiClient(config);
  }

  /**
   * Setup request handlers
   */
  private setupHandlers(): void {
    // List tools - only MCP App tools
    this.server.setRequestHandler(ListToolsRequestSchema, async () => {
      const appTools = this.mcpAppsManager.getToolDefinitions();
      process.stderr.write(`[MCP Apps Only] Listing ${appTools.length} app tools\n`);
      return { tools: appTools };
    });

    // List resources - MCP App UI resources
    this.server.setRequestHandler(ListResourcesRequestSchema, async () => {
      const resourceUris = this.mcpAppsManager.getResourceURIs();
      const resources = resourceUris.map(uri => {
        const handler = this.mcpAppsManager.getResourceHandler(uri);
        return {
          uri: uri,
          name: uri,
          mimeType: handler?.mimeType || 'text/html;profile=mcp-app'
        };
      });
      process.stderr.write(`[MCP Apps Only] Listing ${resources.length} UI resources\n`);
      return { resources };
    });

    // Read resource - serve UI HTML
    this.server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
      const uri = request.params.uri;
      process.stderr.write(`[MCP Apps Only] Reading resource: ${uri}\n`);

      const handler = this.mcpAppsManager.getResourceHandler(uri);
      if (!handler) {
        throw new McpError(ErrorCode.InvalidRequest, `Resource not found: ${uri}`);
      }

      return {
        contents: [{
          uri: uri,
          mimeType: handler.mimeType,
          text: handler.getContent()
        }]
      };
    });

    // Call tool - execute MCP App tools
    this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
      const { name, arguments: args } = request.params;
      process.stderr.write(`[MCP Apps Only] Calling tool: ${name}\n`);

      if (!this.mcpAppsManager.isAppTool(name)) {
        throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
      }

      try {
        const result = await this.mcpAppsManager.executeTool(name, args || {});
        return result;
      } catch (error: any) {
        process.stderr.write(`[MCP Apps Only] Tool error: ${error.message}\n`);
        throw new McpError(ErrorCode.InternalError, error.message);
      }
    });
  }

  /**
   * Setup error handling
   */
  private setupErrorHandling(): void {
    this.server.onerror = (error) => {
      process.stderr.write(`[MCP Apps Only] Server error: ${error}\n`);
    };

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

  /**
   * Start the server
   */
  async run(): Promise<void> {
    const transport = new StdioServerTransport();
    await this.server.connect(transport);
    process.stderr.write('[MCP Apps Only] Server started - Apps only mode\n');
  }
}

// Start server
const server = new GHLMCPAppsServer();
server.run().catch((error) => {
  process.stderr.write(`Failed to start server: ${error}\n`);
  process.exit(1);
});
