/**
 * @fileoverview MCP Server module for DeepSource integration
 *
 * This module provides a configurable MCP server that can be used
 * to integrate DeepSource functionality with Model Context Protocol.
 * It separates the server setup logic from the main entry point,
 * allowing for better testability and reusability.
 *
 * @packageDocumentation
 */

import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { createLogger } from '../utils/logging/logger.js';
import { ToolRegistry } from './tool-registry.js';
import { BaseHandlerDeps } from '../handlers/base/handler.interface.js';
import { createDefaultHandlerDeps } from '../handlers/base/handler.factory.js';
import { registerDeepSourceTools } from './tool-registration.js';
import { VERSION } from '../version.js';

const logger = createLogger('MCPServer');

/**
 * Configuration options for the MCP server
 */
export interface MCPServerConfig {
  /** Server name */
  name?: string;
  /** Server version */
  version?: string;
  /** Custom handler dependencies */
  handlerDeps?: BaseHandlerDeps;
  /** Whether to auto-register DeepSource tools */
  autoRegisterTools?: boolean;
  /** Custom transport (defaults to StdioServerTransport) */
  transport?: StdioServerTransport;
  /** Whether to start the server immediately */
  autoStart?: boolean;
}

/**
 * Default configuration values
 */
const DEFAULT_CONFIG: Required<Omit<MCPServerConfig, 'handlerDeps' | 'transport'>> = {
  name: 'deepsource-mcp-server',
  version: VERSION,
  autoRegisterTools: true,
  autoStart: false,
};

/**
 * DeepSource MCP Server class
 *
 * This class encapsulates the MCP server setup and configuration,
 * providing a clean API for creating and managing the server.
 */
export class DeepSourceMCPServer {
  private mcpServer: McpServer;
  private toolRegistry: ToolRegistry;
  private transport?: StdioServerTransport;
  private config: Required<Omit<MCPServerConfig, 'handlerDeps' | 'transport'>> &
    Pick<MCPServerConfig, 'handlerDeps' | 'transport'>;
  private isConnected = false;

  constructor(config: MCPServerConfig = {}) {
    this.config = { ...DEFAULT_CONFIG, ...config };

    logger.info('Initializing DeepSource MCP Server', {
      name: this.config.name,
      version: this.config.version,
    });

    // Initialize MCP server
    this.mcpServer = new McpServer({
      name: this.config.name,
      version: this.config.version,
    });

    // Set transport FIRST (default to stdio if not provided)
    // This must be set before registering tools
    this.transport = this.config.transport || new StdioServerTransport();

    // Initialize tool registry
    const handlerDeps = this.config.handlerDeps || createDefaultHandlerDeps();
    this.toolRegistry = new ToolRegistry(this.mcpServer, handlerDeps);

    // Auto-register tools if configured (AFTER transport is set)
    if (this.config.autoRegisterTools) {
      this.registerDefaultTools();
    }
  }

  /**
   * Registers the default DeepSource tools
   */
  private registerDefaultTools(): void {
    try {
      logger.info('Starting registration of default DeepSource tools', {
        mcpServerType: typeof this.mcpServer,
        mcpServerExists: Boolean(this.mcpServer),
        toolRegistryExists: Boolean(this.toolRegistry),
      });

      registerDeepSourceTools(this.toolRegistry);

      const registeredTools = this.toolRegistry.getToolNames();
      logger.info('Successfully registered DeepSource tools', {
        registeredTools,
        toolCount: registeredTools.length,
      });

      // Verify tools are actually registered with the MCP server
      // The MCP server doesn't expose a direct way to query tools,
      // but we can log what we've registered
      logger.info('Tool registration verification', {
        toolRegistryCount: registeredTools.length,
        mcpServerConnected: this.isConnected,
        transportSet: Boolean(this.transport),
      });
    } catch (error) {
      logger.error('Failed to register DeepSource tools', {
        error,
        message: error instanceof Error ? error.message : String(error),
        stack: error instanceof Error ? error.stack : undefined,
      });
      throw error;
    }
  }

  /**
   * Gets the MCP server instance
   */
  getMcpServer(): McpServer {
    return this.mcpServer;
  }

  /**
   * Gets the tool registry
   */
  getToolRegistry(): ToolRegistry {
    return this.toolRegistry;
  }

  /**
   * Connects the server to the transport
   *
   * @param transport - Optional transport to use (overrides constructor transport)
   */
  async connect(transport?: StdioServerTransport): Promise<void> {
    if (this.isConnected) {
      logger.warn('Server is already connected');
      return;
    }

    const transportToUse = transport || this.transport || new StdioServerTransport();

    logger.info('Connecting MCP server to transport');
    await this.mcpServer.connect(transportToUse);

    this.isConnected = true;
    logger.info('MCP server connected successfully');
  }

  /**
   * Starts the server (convenience method that creates transport and connects)
   */
  async start(): Promise<void> {
    if (!this.transport) {
      this.transport = new StdioServerTransport();
    }
    await this.connect();
  }

  /**
   * Checks if the server is connected
   */
  isServerConnected(): boolean {
    return this.isConnected;
  }

  /**
   * Updates handler dependencies
   *
   * @param deps - New handler dependencies
   */
  updateHandlerDeps(deps: BaseHandlerDeps): void {
    this.toolRegistry.updateDefaultDeps(deps);
    logger.info('Handler dependencies updated');
  }

  /**
   * Gets registered tool names
   */
  getRegisteredTools(): string[] {
    return this.toolRegistry.getToolNames();
  }

  /**
   * Discovers and loads tools from filesystem (requires FEATURE_TOOL_DISCOVERY)
   *
   * @param options - Discovery options
   * @returns Array of discovered tool names
   */
  async discoverTools(options?: Record<string, unknown>): Promise<string[]> {
    logger.info('Starting tool discovery from DeepSourceMCPServer');
    return this.toolRegistry.discoverTools(options);
  }

  /**
   * Gets enhanced tool information including metadata
   */
  getToolsInfo(): Array<{
    name: string;
    description: string;
    category?: string;
    version?: string;
    tags?: string[];
    enabled?: boolean;
    discovered?: boolean;
  }> {
    return this.toolRegistry.getToolsInfo();
  }

  /**
   * Creates and optionally starts a DeepSource MCP server
   *
   * @param config - Server configuration
   * @returns The created server instance
   */
  static async create(config: MCPServerConfig = {}): Promise<DeepSourceMCPServer> {
    const server = new DeepSourceMCPServer(config);

    if (config.autoStart) {
      await server.start();
    }

    return server;
  }
}

/**
 * Convenience function to create a server with default configuration
 *
 * @param autoStart - Whether to start the server immediately
 * @returns The created server instance
 */
export async function createDeepSourceMCPServer(autoStart = false): Promise<DeepSourceMCPServer> {
  return DeepSourceMCPServer.create({ autoStart });
}
