/**
 * Vibn MCP (Model Context Protocol) Server
 * 
 * Exposes Vibn project data, sessions, and capabilities to AI assistants
 * through a standardized protocol.
 */

import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
  CallToolRequestSchema,
  ListResourcesRequestSchema,
  ListToolsRequestSchema,
  ReadResourceRequestSchema,
} from '@modelcontextprotocol/sdk/types.js';
import { getAdminDb } from '@/lib/firebase/admin';

interface VibnResource {
  uri: string;
  name: string;
  description: string;
  mimeType: string;
}

class VibnMCPServer {
  private server: Server;

  constructor() {
    this.server = new Server(
      {
        name: 'vibn-mcp-server',
        version: '1.0.0',
      },
      {
        capabilities: {
          resources: {},
          tools: {},
          prompts: {},
        },
      }
    );

    this.setupHandlers();
  }

  private setupHandlers() {
    // List available resources
    this.server.setRequestHandler(ListResourcesRequestSchema, async () => {
      return {
        resources: [
          {
            uri: 'vibn://projects',
            name: 'Projects',
            description: 'List all user projects',
            mimeType: 'application/json',
          },
          {
            uri: 'vibn://sessions',
            name: 'Coding Sessions',
            description: 'List all coding sessions',
            mimeType: 'application/json',
          },
          {
            uri: 'vibn://conversations',
            name: 'AI Conversations',
            description: 'List all AI conversation history',
            mimeType: 'application/json',
          },
        ] as VibnResource[],
      };
    });

    // Read a specific resource
    this.server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
      const { uri } = request.params;
      const db = getAdminDb();

      try {
        if (uri === 'vibn://projects') {
          // Fetch all projects (would need user context in real implementation)
          const projectsSnapshot = await db
            .collection('projects')
            .orderBy('createdAt', 'desc')
            .limit(50)
            .get();

          const projects = projectsSnapshot.docs.map(doc => ({
            id: doc.id,
            ...doc.data(),
          }));

          return {
            contents: [
              {
                uri,
                mimeType: 'application/json',
                text: JSON.stringify(projects, null, 2),
              },
            ],
          };
        }

        if (uri.startsWith('vibn://projects/')) {
          const projectId = uri.replace('vibn://projects/', '');
          const projectDoc = await db.collection('projects').doc(projectId).get();

          if (!projectDoc.exists) {
            throw new Error(`Project ${projectId} not found`);
          }

          return {
            contents: [
              {
                uri,
                mimeType: 'application/json',
                text: JSON.stringify({ id: projectDoc.id, ...projectDoc.data() }, null, 2),
              },
            ],
          };
        }

        if (uri.startsWith('vibn://sessions/')) {
          const projectId = uri.replace('vibn://sessions/', '');
          const sessionsSnapshot = await db
            .collection('sessions')
            .where('projectId', '==', projectId)
            .orderBy('createdAt', 'desc')
            .limit(50)
            .get();

          const sessions = sessionsSnapshot.docs.map(doc => ({
            id: doc.id,
            ...doc.data(),
          }));

          return {
            contents: [
              {
                uri,
                mimeType: 'application/json',
                text: JSON.stringify(sessions, null, 2),
              },
            ],
          };
        }

        if (uri.startsWith('vibn://conversations/')) {
          const projectId = uri.replace('vibn://conversations/', '');
          const conversationsSnapshot = await db
            .collection('projects')
            .doc(projectId)
            .collection('aiConversations')
            .orderBy('createdAt', 'asc')
            .limit(100)
            .get();

          const conversations = conversationsSnapshot.docs.map(doc => ({
            id: doc.id,
            ...doc.data(),
          }));

          return {
            contents: [
              {
                uri,
                mimeType: 'application/json',
                text: JSON.stringify(conversations, null, 2),
              },
            ],
          };
        }

        throw new Error(`Unknown resource: ${uri}`);
      } catch (error) {
        throw new Error(`Failed to read resource: ${error instanceof Error ? error.message : String(error)}`);
      }
    });

    // List available tools
    this.server.setRequestHandler(ListToolsRequestSchema, async () => {
      return {
        tools: [
          {
            name: 'get_project_summary',
            description: 'Get a summary of a specific project including sessions, costs, and activity',
            inputSchema: {
              type: 'object',
              properties: {
                projectId: {
                  type: 'string',
                  description: 'The project ID',
                },
              },
              required: ['projectId'],
            },
          },
          {
            name: 'search_sessions',
            description: 'Search coding sessions by workspace path, date range, or project',
            inputSchema: {
              type: 'object',
              properties: {
                projectId: {
                  type: 'string',
                  description: 'Filter by project ID',
                },
                workspacePath: {
                  type: 'string',
                  description: 'Filter by workspace path',
                },
                startDate: {
                  type: 'string',
                  description: 'Start date (ISO format)',
                },
                endDate: {
                  type: 'string',
                  description: 'End date (ISO format)',
                },
              },
            },
          },
          {
            name: 'get_conversation_context',
            description: 'Get the full AI conversation history for a project',
            inputSchema: {
              type: 'object',
              properties: {
                projectId: {
                  type: 'string',
                  description: 'The project ID',
                },
                limit: {
                  type: 'number',
                  description: 'Maximum number of messages to return (default: 50)',
                },
              },
              required: ['projectId'],
            },
          },
        ],
      };
    });

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

      try {
        if (name === 'get_project_summary') {
          const { projectId } = args as { projectId: string };
          
          const projectDoc = await db.collection('projects').doc(projectId).get();
          if (!projectDoc.exists) {
            throw new Error(`Project ${projectId} not found`);
          }

          const project = { id: projectDoc.id, ...projectDoc.data() };

          // Get sessions
          const sessionsSnapshot = await db
            .collection('sessions')
            .where('projectId', '==', projectId)
            .get();

          const sessions = sessionsSnapshot.docs.map(doc => doc.data());
          const totalCost = sessions.reduce((sum, s: any) => sum + (s.cost || 0), 0);
          const totalTokens = sessions.reduce((sum, s: any) => sum + (s.tokensUsed || 0), 0);
          const totalDuration = sessions.reduce((sum, s: any) => sum + (s.duration || 0), 0);

          const summary = {
            project,
            stats: {
              totalSessions: sessions.length,
              totalCost,
              totalTokens,
              totalDuration,
            },
            recentSessions: sessions.slice(0, 5),
          };

          return {
            content: [
              {
                type: 'text',
                text: JSON.stringify(summary, null, 2),
              },
            ],
          };
        }

        if (name === 'search_sessions') {
          const { projectId, workspacePath, startDate, endDate } = args as {
            projectId?: string;
            workspacePath?: string;
            startDate?: string;
            endDate?: string;
          };

          let query = db.collection('sessions');

          if (projectId) {
            query = query.where('projectId', '==', projectId) as any;
          }
          if (workspacePath) {
            query = query.where('workspacePath', '==', workspacePath) as any;
          }

          const snapshot = await query.orderBy('createdAt', 'desc').limit(50).get();
          const sessions = snapshot.docs.map(doc => ({
            id: doc.id,
            ...doc.data(),
          }));

          return {
            content: [
              {
                type: 'text',
                text: JSON.stringify(sessions, null, 2),
              },
            ],
          };
        }

        if (name === 'get_conversation_context') {
          const { projectId, limit = 50 } = args as { projectId: string; limit?: number };

          const conversationsSnapshot = await db
            .collection('projects')
            .doc(projectId)
            .collection('aiConversations')
            .orderBy('createdAt', 'asc')
            .limit(limit)
            .get();

          const conversations = conversationsSnapshot.docs.map(doc => ({
            id: doc.id,
            ...doc.data(),
          }));

          return {
            content: [
              {
                type: 'text',
                text: JSON.stringify(conversations, null, 2),
              },
            ],
          };
        }

        throw new Error(`Unknown tool: ${name}`);
      } catch (error) {
        throw new Error(`Tool execution failed: ${error instanceof Error ? error.message : String(error)}`);
      }
    });
  }

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

// Start the server
const server = new VibnMCPServer();
server.start().catch(console.error);

