import { ToolRegistryService } from './tool-registry.service';
import { ToolLoggerService } from './tool-logger.service';
import {
  McpToolDefinition,
  McpContext,
  McpResource,
  McpResourceWithHandler,
} from '../interfaces';
import { ToolCallResultDto, CallHistoryFilters, PaginatedResult } from '../dto';
import { ToolCall } from '../entities';

export class McpServerService {
  private resources: Map<string, McpResourceWithHandler> = new Map();

  constructor(
    private readonly toolRegistry: ToolRegistryService,
    private readonly toolLogger: ToolLoggerService
  ) {
    this.initializeResources();
  }

  // ============================================
  // TOOLS
  // ============================================

  listTools(): McpToolDefinition[] {
    return this.toolRegistry.getAllTools();
  }

  getTool(name: string): McpToolDefinition | null {
    return this.toolRegistry.getTool(name);
  }

  async callTool(
    toolName: string,
    params: Record<string, any>,
    context: McpContext
  ): Promise<ToolCallResultDto> {
    // 1. Get tool definition
    const tool = this.toolRegistry.getTool(toolName);
    if (!tool) {
      return {
        success: false,
        toolName,
        error: `Tool '${toolName}' not found`,
        callId: '',
      };
    }

    // 2. Check permissions
    if (tool.permissions && tool.permissions.length > 0) {
      const hasPermission = tool.permissions.some((p) =>
        context.permissions.includes(p)
      );
      if (!hasPermission) {
        return {
          success: false,
          toolName,
          error: `Missing permissions for tool '${toolName}'`,
          callId: '',
        };
      }
    }

    // 3. Start logging
    const callId = await this.toolLogger.startCall({
      tenantId: context.tenantId,
      toolName,
      parameters: params,
      agentId: context.agentId,
      conversationId: context.conversationId,
      callerType: context.callerType,
      userId: context.userId,
    });

    try {
      // 4. Get and execute handler
      const handler = this.toolRegistry.getHandler(toolName);
      if (!handler) {
        await this.toolLogger.failCall(callId, 'Handler not found', 'HANDLER_NOT_FOUND');
        return {
          success: false,
          toolName,
          error: `Handler for tool '${toolName}' not found`,
          callId,
        };
      }

      const result = await handler(params, context);

      // 5. Log success
      await this.toolLogger.completeCall(callId, result);

      return {
        success: true,
        toolName,
        result,
        callId,
      };
    } catch (error: any) {
      // 6. Log error
      await this.toolLogger.failCall(
        callId,
        error.message || 'Execution error',
        error.code || 'EXECUTION_ERROR'
      );

      return {
        success: false,
        toolName,
        error: error.message || 'Tool execution failed',
        callId,
      };
    }
  }

  // ============================================
  // RESOURCES
  // ============================================

  listResources(): McpResource[] {
    return Array.from(this.resources.values()).map(({ handler, ...resource }) => resource);
  }

  async getResource(uri: string, context: McpContext): Promise<any> {
    const resource = this.resources.get(uri);
    if (!resource) {
      throw new Error(`Resource '${uri}' not found`);
    }

    return resource.handler(context);
  }

  private initializeResources(): void {
    // Business config resource
    this.resources.set('erp://config/business', {
      uri: 'erp://config/business',
      name: 'Business Configuration',
      description: 'Basic business information and settings',
      mimeType: 'application/json',
      handler: async (context) => ({
        tenantId: context.tenantId,
        message: 'Business configuration - connect to tenant config service',
        // TODO: Connect to actual tenant config service
      }),
    });

    // Categories catalog resource
    this.resources.set('erp://catalog/categories', {
      uri: 'erp://catalog/categories',
      name: 'Product Categories',
      description: 'List of product categories',
      mimeType: 'application/json',
      handler: async (context) => ({
        tenantId: context.tenantId,
        categories: [],
        message: 'Categories catalog - connect to products service',
        // TODO: Connect to actual products service
      }),
    });

    // Inventory summary resource
    this.resources.set('erp://inventory/summary', {
      uri: 'erp://inventory/summary',
      name: 'Inventory Summary',
      description: 'Summary of current inventory status',
      mimeType: 'application/json',
      handler: async (context) => ({
        tenantId: context.tenantId,
        totalProducts: 0,
        totalValue: 0,
        lowStockCount: 0,
        message: 'Inventory summary - connect to inventory service',
        // TODO: Connect to actual inventory service
      }),
    });
  }

  // ============================================
  // HISTORY / AUDIT
  // ============================================

  async getCallHistory(
    tenantId: string,
    filters: CallHistoryFilters
  ): Promise<PaginatedResult<ToolCall>> {
    return this.toolLogger.getCallHistory(tenantId, filters);
  }

  async getCallDetails(id: string, tenantId: string): Promise<ToolCall | null> {
    return this.toolLogger.getCallById(id, tenantId);
  }

  async getToolStats(tenantId: string, startDate: Date, endDate: Date) {
    return this.toolLogger.getToolStats(tenantId, startDate, endDate);
  }
}
