/**
 * Familiar MCP (Model Context Protocol) Endpoint
 * 
 * Allows external AIs (Claude, ChatGPT, etc.) to connect and
 * query/write to the Familiar memory system.
 * 
 * JSON-RPC 2.0 compliant.
 */

import { NextRequest, NextResponse } from 'next/server';
import { prisma } from '@/lib/db';
import { BRAND } from '@/lib/white-label/constants';

export const dynamic = 'force-dynamic';

const MCP_VERSION = '1.0.0';

interface MCPRequest {
  jsonrpc: '2.0';
  id: string | number;
  method: string;
  params?: any;
}

interface MCPResponse {
  jsonrpc: '2.0';
  id: string | number;
  result?: any;
  error?: {
    code: number;
    message: string;
    data?: any;
  };
}

function mcpSuccess(id: string | number, result: any): MCPResponse {
  return { jsonrpc: '2.0', id, result };
}

function mcpError(id: string | number, code: number, message: string, data?: any): MCPResponse {
  return { jsonrpc: '2.0', id, error: { code, message, data } };
}

// Verify API key if configured
async function verifyApiKey(request: NextRequest): Promise<boolean> {
  const apiKey = process.env.GHOST_MCP_API_KEY;
  if (!apiKey) return true; // No auth required if not configured

  const authHeader = request.headers.get('authorization');
  if (!authHeader) return false;

  const token = authHeader.replace('Bearer ', '');
  return token === apiKey;
}

// Check if MCP is enabled
async function isMCPEnabled(): Promise<boolean> {
  const config = await prisma.memorySystemConfig.findFirst({
    where: { organizationId: 'default' }
  });
  return config?.mcpEndpointEnabled ?? true; // Default to enabled
}

// MCP Methods
const methods: Record<string, (params: any) => Promise<any>> = {
  // Server info
  'mcp.info': async () => ({
    name: `${BRAND.companyName} Agent Memory`,
    version: MCP_VERSION,
    capabilities: [
      'memory.query',
      'memory.write',
      'memory.search',
      'memory.stale',
      'memory.crossref',
      'memory.stats',
      'insights.query',
      'insights.create',
      'agents.list',
      'agents.query'
    ]
  }),

  // Query agent memory
  'memory.query': async (params: {
    agentId?: string;
    category?: string;
    scope?: 'agent' | 'shared' | 'all';
    limit?: number;
    minImportance?: number;
  }) => {
    const { agentId, category, scope = 'all', limit = 50, minImportance = 0 } = params;

    const results: any[] = [];

    if ((scope === 'agent' || scope === 'all') && agentId) {
      const agentMemories = await prisma.domainAgentMemory.findMany({
        where: {
          agentId,
          ...(category && { category }),
          importance: { gte: minImportance }
        },
        orderBy: { importance: 'desc' },
        take: limit
      });
      results.push(...agentMemories.map((m: any) => ({ ...m, scope: 'agent' })));
    }

    if (scope === 'shared' || scope === 'all') {
      const sharedMemories = await prisma.ghostMemory.findMany({
        where: category ? { category } : {},
        orderBy: { confidence: 'desc' },
        take: limit
      });
      results.push(...sharedMemories.map((m: any) => ({ ...m, scope: 'shared' })));
    }

    return { memories: results, count: results.length };
  },

  // Write memory
  'memory.write': async (params: {
    agentId?: string;
    category: string;
    key: string;
    content: any;
    scope?: 'agent' | 'shared';
    confidence?: number;
    importance?: number;
  }) => {
    const { agentId, category, key, content, scope = 'shared', confidence = 0.8, importance = 0.5 } = params;

    if (scope === 'agent' && !agentId) {
      throw new Error('agentId required for agent scope');
    }

    if (scope === 'shared') {
      const memory = await prisma.ghostMemory.upsert({
        where: { category_key: { category, key } },
        update: {
          value: content,
          confidence,
          source: agentId ? `agent:${agentId}` : 'mcp',
          usageCount: { increment: 1 },
          lastUsed: new Date(),
          updatedAt: new Date()
        },
        create: {
          id: `ghost_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
          category,
          key,
          value: content,
          confidence,
          source: agentId ? `agent:${agentId}` : 'mcp',
          updatedAt: new Date()
        }
      });
      return { success: true, memory, scope: 'shared' };
    } else {
      const memory = await prisma.domainAgentMemory.upsert({
        where: { agentId_category_key: { agentId: agentId!, category, key } },
        update: {
          content,
          confidence,
          importance,
          source: 'mcp',
          accessCount: { increment: 1 },
          updatedAt: new Date()
        },
        create: {
          id: `mem_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
          agentId: agentId!,
          category,
          key,
          content,
          confidence,
          importance,
          source: 'mcp',
          updatedAt: new Date()
        }
      });
      return { success: true, memory, scope: 'agent' };
    }
  },

  // Search memories
  'memory.search': async (params: { query: string; limit?: number }) => {
    const { query, limit = 20 } = params;
    const searchTerms = query.toLowerCase().split(' ');

    // Search shared memories
    const sharedMemories = await prisma.ghostMemory.findMany({
      take: limit * 2,
      orderBy: { confidence: 'desc' }
    });

    // Simple text matching (production would use vector search)
    const matches = sharedMemories.filter((m: any) => {
      const text = JSON.stringify(m.value).toLowerCase() + m.key.toLowerCase() + m.category.toLowerCase();
      return searchTerms.some(term => text.includes(term));
    }).slice(0, limit);

    return { results: matches, count: matches.length };
  },

  // Find stale memories
  'memory.stale': async (params: { agentId?: string; daysUnused?: number }) => {
    const { agentId, daysUnused = 30 } = params;
    const staleDate = new Date();
    staleDate.setDate(staleDate.getDate() - daysUnused);

    const stale = await prisma.ghostMemory.findMany({
      where: {
        OR: [
          { lastUsed: { lt: staleDate } },
          { lastUsed: null }
        ]
      },
      orderBy: { createdAt: 'asc' },
      take: 50
    });

    return { staleMemories: stale, count: stale.length };
  },

  // Cross-reference memories
  'memory.crossref': async (params: { category: string; key: string }) => {
    const { category, key } = params;

    const related = await prisma.ghostMemory.findMany({
      where: {
        OR: [
          { category },
          { key: { contains: key } }
        ]
      },
      take: 20
    });

    return { related, count: related.length };
  },

  // Memory statistics
  'memory.stats': async (params: { agentId?: string }) => {
    const { agentId } = params;

    const [sharedCount, agentCount, insightCount, categoryBreakdown] = await Promise.all([
      prisma.ghostMemory.count(),
      agentId ? prisma.domainAgentMemory.count({ where: { agentId } }) : prisma.domainAgentMemory.count(),
      agentId ? prisma.agentInsight.count({ where: { agentId } }) : prisma.agentInsight.count(),
      prisma.ghostMemory.groupBy({ by: ['category'], _count: true })
    ]);

    return {
      sharedMemories: sharedCount,
      agentMemories: agentCount,
      insights: insightCount,
      categoryCounts: Object.fromEntries(categoryBreakdown.map((c: any) => [c.category, c._count]))
    };
  },

  // Query insights
  'insights.query': async (params: { agentId?: string; type?: string; severity?: string; limit?: number }) => {
    const { agentId, type, severity, limit = 50 } = params;

    const where: any = {};
    if (agentId) where.agentId = agentId;
    if (type) where.type = type;
    if (severity) where.severity = severity;

    const insights = await prisma.agentInsight.findMany({
      where,
      orderBy: [{ severity: 'desc' }, { createdAt: 'desc' }],
      take: limit
    });

    return { insights, count: insights.length };
  },

  // Create insight
  'insights.create': async (params: {
    agentId: string;
    type: string;
    title: string;
    content: string;
    severity?: string;
    confidence?: number;
    tags?: string[];
  }) => {
    const { agentId, type, title, content, severity = 'info', confidence = 0.8, tags = [] } = params;

    const insight = await prisma.agentInsight.create({
      data: {
        agentId,
        type,
        title,
        content,
        severity,
        confidence,
        tags
      }
    });

    return { success: true, insight };
  },

  // List agents
  'agents.list': async () => {
    const agents = await prisma.domainAgent.findMany({
      select: {
        agentId: true,
        name: true,
        title: true,
        domain: true,
        status: true,
        avatarColor: true
      },
      orderBy: { name: 'asc' }
    });

    return { agents, count: agents.length };
  },

  // Query specific agent
  'agents.query': async (params: { agentId: string }) => {
    const { agentId } = params;

    const [agent, memoryCount, insightCount, recentInsights] = await Promise.all([
      prisma.domainAgent.findUnique({ where: { agentId } }),
      prisma.domainAgentMemory.count({ where: { agentId } }),
      prisma.agentInsight.count({ where: { agentId } }),
      prisma.agentInsight.findMany({
        where: { agentId },
        orderBy: { createdAt: 'desc' },
        take: 5
      })
    ]);

    if (!agent) throw new Error('Agent not found');

    return {
      agent,
      stats: { memoryCount, insightCount },
      recentInsights
    };
  }
};

export async function POST(request: NextRequest) {
  try {
    // Verify authentication
    if (!await verifyApiKey(request)) {
      return NextResponse.json(
        mcpError(0, -32001, 'Unauthorized'),
        { status: 401 }
      );
    }

    // Check if MCP is enabled
    if (!await isMCPEnabled()) {
      return NextResponse.json(
        mcpError(0, -32002, 'MCP endpoint is disabled'),
        { status: 403 }
      );
    }

    const body: MCPRequest = await request.json();
    const { jsonrpc, id, method, params } = body;

    if (jsonrpc !== '2.0') {
      return NextResponse.json(mcpError(id || 0, -32600, 'Invalid Request: must use JSON-RPC 2.0'));
    }

    if (!method || !methods[method]) {
      return NextResponse.json(mcpError(id, -32601, `Method not found: ${method}`));
    }

    const result = await methods[method](params || {});
    return NextResponse.json(mcpSuccess(id, result));

  } catch (error: any) {
    console.error('MCP Error:', error);
    return NextResponse.json(mcpError(0, -32603, error.message || 'Internal error'));
  }
}

// GET - Server info
export async function GET() {
  return NextResponse.json({
    name: `${BRAND.companyName} Agent MCP Server`,
    version: MCP_VERSION,
    protocol: 'JSON-RPC 2.0',
    endpoints: {
      'POST /api/gfs/agent-memory/mcp': 'JSON-RPC endpoint for all operations'
    },
    methods: Object.keys(methods),
    documentation: '/ghost-control/memory-system'
  });
}
