import { prisma } from '@/lib/db';

/**
 * Tesa Insight Generation System
 * 
 * Analyzes existing memories to:
 * - Detect patterns across categories
 * - Find gaps and neglected areas
 * - Surface connections between memories
 * - Generate proactive suggestions
 * - Time-bridge across sessions
 */

export interface InsightResult {
  type: 'pattern' | 'gap' | 'connection' | 'suggestion' | 'stale';
  title: string;
  description: string;
  relatedMemoryIds: string[];
  importance: number;
  actionable: boolean;
}

/**
 * Analyze memory patterns and generate insights
 */
export async function generateInsights(): Promise<InsightResult[]> {
  const insights: InsightResult[] = [];

  // Fetch all active memories for analysis
  const memories = await prisma.tesaMemory.findMany({
    where: { isActive: true },
    orderBy: { createdAt: 'desc' },
  });

  if (memories.length === 0) {
    return [{
      type: 'gap',
      title: 'No memories recorded',
      description: 'Start logging decisions, preferences, and context to build institutional knowledge.',
      relatedMemoryIds: [],
      importance: 10,
      actionable: true,
    }];
  }

  // 1. Analyze category distribution
  const categoryInsights = await analyzeCategoryDistribution(memories);
  insights.push(...categoryInsights);

  // 2. Find stale/neglected memories
  const staleInsights = await findStaleMemories();
  insights.push(...staleInsights);

  // 3. Detect patterns in tags
  const tagPatterns = analyzeTagPatterns(memories);
  insights.push(...tagPatterns);

  // 4. Find potential connections
  const connections = findPotentialConnections(memories);
  insights.push(...connections);

  // 5. Check for time-based patterns
  const timePatterns = analyzeTimePatterns(memories);
  insights.push(...timePatterns);

  return insights;
}

/**
 * Analyze category distribution for gaps
 */
async function analyzeCategoryDistribution(memories: { category: string; id: string }[]): Promise<InsightResult[]> {
  const insights: InsightResult[] = [];
  const categories = ['decision', 'preference', 'context', 'insight', 'fact'];
  
  const counts = new Map<string, number>();
  memories.forEach(m => {
    counts.set(m.category, (counts.get(m.category) || 0) + 1);
  });

  // Find missing or underrepresented categories
  for (const cat of categories) {
    const count = counts.get(cat) || 0;
    if (count === 0) {
      insights.push({
        type: 'gap',
        title: `No ${cat}s recorded`,
        description: `Consider logging ${cat}s to build a more complete knowledge base.`,
        relatedMemoryIds: [],
        importance: 6,
        actionable: true,
      });
    } else if (count < 3 && memories.length > 10) {
      insights.push({
        type: 'gap',
        title: `Few ${cat}s recorded`,
        description: `Only ${count} ${cat}(s) logged. This category might be underrepresented.`,
        relatedMemoryIds: memories.filter(m => m.category === cat).map(m => m.id),
        importance: 4,
        actionable: true,
      });
    }
  }

  // Check for category dominance
  const total = memories.length;
  for (const [cat, count] of counts) {
    if (count / total > 0.6 && total > 5) {
      insights.push({
        type: 'pattern',
        title: `Heavy ${cat} focus`,
        description: `${Math.round((count / total) * 100)}% of memories are ${cat}s. Consider diversifying.`,
        relatedMemoryIds: memories.filter(m => m.category === cat).slice(0, 5).map(m => m.id),
        importance: 3,
        actionable: false,
      });
    }
  }

  return insights;
}

/**
 * Find stale memories that need attention
 */
async function findStaleMemories(): Promise<InsightResult[]> {
  const insights: InsightResult[] = [];
  const thirtyDaysAgo = new Date();
  thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);

  const staleMemories = await prisma.tesaMemory.findMany({
    where: {
      isActive: true,
      importance: { gte: 6 },
      updatedAt: { lt: thirtyDaysAgo },
      OR: [
        { lastAccessed: { lt: thirtyDaysAgo } },
        { lastAccessed: null },
      ],
    },
    orderBy: { importance: 'desc' },
    take: 10,
  });

  if (staleMemories.length > 0) {
    insights.push({
      type: 'stale',
      title: `${staleMemories.length} important memories need review`,
      description: `These high-importance memories haven't been accessed in 30+ days. They may need updating or verification.`,
      relatedMemoryIds: staleMemories.map((m: any) => m.id),
      importance: 7,
      actionable: true,
    });

    // Add individual stale items if very important
    for (const mem of staleMemories.filter((m: any) => m.importance >= 8)) {
      const daysSinceUpdate = Math.floor(
        (Date.now() - new Date(mem.updatedAt).getTime()) / (1000 * 60 * 60 * 24)
      );
      insights.push({
        type: 'stale',
        title: `Review: ${mem.key}`,
        description: `This ${mem.category} (importance: ${mem.importance}/10) hasn't been updated in ${daysSinceUpdate} days.`,
        relatedMemoryIds: [mem.id],
        importance: 6,
        actionable: true,
      });
    }
  }

  return insights;
}

/**
 * Analyze tag patterns for insights
 */
function analyzeTagPatterns(memories: { tags: unknown; id: string; key: string }[]): InsightResult[] {
  const insights: InsightResult[] = [];
  const tagCounts = new Map<string, { count: number; memoryIds: string[] }>();

  for (const mem of memories) {
    if (Array.isArray(mem.tags)) {
      for (const tag of mem.tags as string[]) {
        const existing = tagCounts.get(tag) || { count: 0, memoryIds: [] };
        existing.count++;
        existing.memoryIds.push(mem.id);
        tagCounts.set(tag, existing);
      }
    }
  }

  // Find heavily used tags (potential themes)
  for (const [tag, data] of tagCounts) {
    if (data.count >= 3) {
      insights.push({
        type: 'pattern',
        title: `Theme: "${tag}"`,
        description: `${data.count} memories share the "${tag}" tag. This appears to be an important theme.`,
        relatedMemoryIds: data.memoryIds.slice(0, 5),
        importance: 5,
        actionable: false,
      });
    }
  }

  return insights;
}

/**
 * Find potential connections between memories
 */
function findPotentialConnections(memories: { id: string; key: string; value: string; category: string; tags: unknown }[]): InsightResult[] {
  const insights: InsightResult[] = [];
  const processedPairs = new Set<string>();

  // Simple keyword matching for connections
  for (let i = 0; i < memories.length; i++) {
    for (let j = i + 1; j < memories.length; j++) {
      const m1 = memories[i];
      const m2 = memories[j];
      const pairKey = [m1.id, m2.id].sort().join('-');

      if (processedPairs.has(pairKey)) continue;
      processedPairs.add(pairKey);

      // Check for keyword overlap
      const words1 = new Set(
        `${m1.key} ${m1.value}`.toLowerCase().split(/\s+/).filter(w => w.length > 4)
      );
      const words2 = new Set(
        `${m2.key} ${m2.value}`.toLowerCase().split(/\s+/).filter(w => w.length > 4)
      );

      const overlap = [...words1].filter(w => words2.has(w));

      if (overlap.length >= 3 && m1.category !== m2.category) {
        insights.push({
          type: 'connection',
          title: `Possible connection: ${m1.key} ↔ ${m2.key}`,
          description: `These memories share keywords (${overlap.slice(0, 3).join(', ')}) but are in different categories. They might be related.`,
          relatedMemoryIds: [m1.id, m2.id],
          importance: 4,
          actionable: false,
        });
      }
    }

    // Limit connections to avoid overwhelming
    if (insights.filter(i => i.type === 'connection').length >= 5) break;
  }

  return insights;
}

/**
 * Analyze time-based patterns
 */
function analyzeTimePatterns(memories: { createdAt: Date; category: string; id: string }[]): InsightResult[] {
  const insights: InsightResult[] = [];

  // Check for recent activity burst
  const lastWeek = new Date();
  lastWeek.setDate(lastWeek.getDate() - 7);
  const recentMemories = memories.filter(m => new Date(m.createdAt) > lastWeek);

  if (recentMemories.length >= 5) {
    insights.push({
      type: 'pattern',
      title: 'Active knowledge building',
      description: `${recentMemories.length} memories logged in the past week. Great momentum!`,
      relatedMemoryIds: recentMemories.slice(0, 5).map(m => m.id),
      importance: 3,
      actionable: false,
    });
  }

  // Check for inactivity
  const latestMemory = memories[0];
  if (latestMemory) {
    const daysSinceLatest = Math.floor(
      (Date.now() - new Date(latestMemory.createdAt).getTime()) / (1000 * 60 * 60 * 24)
    );

    if (daysSinceLatest > 14) {
      insights.push({
        type: 'gap',
        title: 'Knowledge logging paused',
        description: `No new memories in ${daysSinceLatest} days. Consider logging recent decisions or learnings.`,
        relatedMemoryIds: [],
        importance: 5,
        actionable: true,
      });
    }
  }

  return insights;
}

/**
 * Save generated insights as memories
 */
export async function saveInsightsAsMemories(insights: InsightResult[]): Promise<number> {
  let saved = 0;

  for (const insight of insights) {
    // Check if this insight already exists (avoid duplicates)
    const existing = await prisma.tesaMemory.findFirst({
      where: {
        category: 'insight',
        key: insight.title,
        isActive: true,
        createdAt: { gte: new Date(Date.now() - 24 * 60 * 60 * 1000) }, // Within last 24h
      },
    });

    if (!existing) {
      await prisma.tesaMemory.create({
        data: {
          category: 'insight',
          key: insight.title,
          value: insight.description,
          source: 'system_analysis',
          importance: insight.importance,
          confidence: 0.85,
          tags: [insight.type, insight.actionable ? 'actionable' : 'informational'],
          relatedIds: insight.relatedMemoryIds,
        },
      });
      saved++;
    }
  }

  return saved;
}

/**
 * Generate LLM-powered insights using existing context
 */
export async function generateLLMInsights(): Promise<InsightResult[]> {
  const apiKey = process.env.ABACUSAI_API_KEY;
  if (!apiKey) {
    console.warn('ABACUSAI_API_KEY not set, skipping LLM insights');
    return [];
  }

  // Fetch recent memories for context
  const memories = await prisma.tesaMemory.findMany({
    where: { isActive: true },
    orderBy: { importance: 'desc' },
    take: 30,
  });

  if (memories.length < 5) {
    return []; // Not enough data for LLM analysis
  }

  const memoryContext = memories.map((m: any) => 
    `[${m.category.toUpperCase()}] ${m.key}: ${m.value}`
  ).join('\n');

  try {
    const controller = new AbortController();
    const timeoutId = setTimeout(() => controller.abort(), 90_000);
    const response = await fetch('https://routellm.abacus.ai/v1/chat/completions', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${apiKey}`,
      },
      signal: controller.signal,
      body: JSON.stringify({
        model: 'claude-sonnet-4-20250514',
        messages: [
          {
            role: 'system',
            content: `You are Tesa, an AI agent analyzing a knowledge base. Generate 2-3 actionable insights based on the memories below. Focus on:
1. Patterns or themes that emerge
2. Potential gaps or missing information
3. Connections between different areas
4. Proactive suggestions

Respond in JSON format:
{"insights": [{"title": "...", "description": "...", "type": "pattern|gap|connection|suggestion", "importance": 1-10}]}`,
          },
          {
            role: 'user',
            content: `Here are the current memories:\n\n${memoryContext}\n\nGenerate insights based on this knowledge base.`,
          },
        ],
        max_tokens: 1000,
      }),
    });

    clearTimeout(timeoutId);

    if (!response.ok) {
      console.error('LLM API error:', await response.text());
      return [];
    }

    const data = await response.json();
    const content = data.choices?.[0]?.message?.content;

    if (!content) return [];

    // Parse JSON from response
    const jsonMatch = content.match(/\{[\s\S]*\}/);
    if (!jsonMatch) return [];

    const parsed = JSON.parse(jsonMatch[0]);
    
    return (parsed.insights || []).map((i: { title: string; description: string; type: string; importance: number }) => ({
      type: i.type as InsightResult['type'],
      title: i.title,
      description: i.description,
      relatedMemoryIds: [],
      importance: i.importance || 5,
      actionable: i.type === 'gap' || i.type === 'suggestion',
    }));
  } catch (error) {
    console.error('LLM insight generation error:', error);
    return [];
  }
}
