'use strict';

/**
 * Memory indexer: generates lightweight index entries for fast initial filtering.
 * Rule-based: extracts first sentence as summary, identifies key entities and topics.
 * No LLM needed.
 */

/**
 * Extract a concise summary from memory content (first sentence, <=200 chars).
 */
function extractSummary(content) {
  if (!content) return '';
  // First sentence: up to first period, exclamation, question mark, or newline
  const match = content.match(/^(.{10,}?)[.!?\n]/);
  if (match && match[1].length <= 200) return match[1].trim();
  // Fallback: first 200 chars
  return content.slice(0, 200).trim();
}

/**
 * Extract key entity names from content using simple heuristics.
 */
function extractKeyEntities(content) {
  if (!content) return [];
  const entities = new Set();

  // Capitalized multi-word names (e.g., "John Smith", "New York")
  const nameMatches = content.match(/\b[A-Z][a-z]+(?:\s+[A-Z][a-z]+)+\b/g);
  if (nameMatches) nameMatches.forEach(n => entities.add(n));

  // @mentions
  const mentions = content.match(/@(\w+)/g);
  if (mentions) mentions.forEach(m => entities.add(m.replace('@', '')));

  // #channels
  const channels = content.match(/#(\w[\w-]*)/g);
  if (channels) channels.forEach(c => entities.add(c));

  return Array.from(entities).slice(0, 10);
}

/**
 * Extract key topics from content.
 */
function extractKeyTopics(content) {
  if (!content) return [];
  const lower = content.toLowerCase();
  const topics = [];

  const topicPatterns = [
    { pattern: /\b(deploy|deployment|release|ship)\b/, topic: 'deployment' },
    { pattern: /\b(test|testing|coverage)\b/, topic: 'testing' },
    { pattern: /\b(bug|error|crash|fix)\b/, topic: 'bugs' },
    { pattern: /\b(meeting|standup|sync|1:1)\b/, topic: 'meetings' },
    { pattern: /\b(review|feedback|pr)\b/, topic: 'reviews' },
    { pattern: /\b(design|ui|ux)\b/, topic: 'design' },
    { pattern: /\b(security|auth|permissions)\b/, topic: 'security' },
    { pattern: /\b(database|sql|migration)\b/, topic: 'database' },
    { pattern: /\b(api|endpoint|graphql)\b/, topic: 'api' },
    { pattern: /\b(infra|docker|k8s|cloud)\b/, topic: 'infrastructure' },
    { pattern: /\b(financ|payment|invoice|billing|budget|salary|tax|revenue|expense)\b/, topic: 'finance' },
    { pattern: /\b(health|fitness|workout|sleep|nutrition|medical|doctor|exercise)\b/, topic: 'health' },
    { pattern: /\b(travel|flight|hotel|booking|itinerary|trip|vacation)\b/, topic: 'travel' },
    { pattern: /\b(learn|course|tutorial|study|certif|training|education)\b/, topic: 'learning' },
    { pattern: /\b(hire|hiring|recruit|interview|resume|candidate|onboard)\b/, topic: 'hiring' },
    { pattern: /\b(legal|contract|agreement|compliance|regulation|policy)\b/, topic: 'legal' },
  ];

  for (const { pattern, topic } of topicPatterns) {
    if (pattern.test(lower)) topics.push(topic);
  }

  return topics.slice(0, 5);
}

/**
 * Generate an index entry for a memory.
 * @param {object} memory - Memory object with { id, content, domain, topic, timestamp }
 * @returns {object} Index entry ready for insertMemoryIndex
 */
function generateMemoryIndex(memory) {
  if (!memory || !memory.content) return null;

  const summary = extractSummary(memory.content);
  if (!summary || summary.length < 10) return null;

  const keyEntities = extractKeyEntities(memory.content);
  const keyTopics = extractKeyTopics(memory.content);

  return {
    memory_id: memory.id,
    summary,
    key_entities: keyEntities.length > 0 ? JSON.stringify(keyEntities) : null,
    key_topics: keyTopics.length > 0 ? JSON.stringify(keyTopics) : null,
    domain: memory.domain || null,
    topic: memory.topic || null,
    timestamp: memory.timestamp,
  };
}

/**
 * Generate index entries for a batch of memories.
 */
function batchGenerateIndex(memories) {
  return memories.map(generateMemoryIndex).filter(Boolean);
}

/**
 * Generate an enriched index entry using LLM (optional).
 * Falls back to rule-based if LLM unavailable.
 * @param {object} memory - Memory object
 * @param {object} [opts] - Options
 * @param {object} [opts.client] - LLM client
 * @param {string} [opts.model] - Model to use
 * @returns {Promise<object>} Index entry
 */
async function generateEnrichedIndex(memory, opts = {}) {
  if (!memory || !memory.content) return generateMemoryIndex(memory);
  if (!opts.client) return generateMemoryIndex(memory);

  try {
    const prompt = `You are indexing a memory for later retrieval. Generate a topic-dense index.

CONTENT:
${memory.content.slice(0, 2000)}

Output a JSON object with EXACTLY these fields:
{
  "summary": "2-3 sentences describing what this content is about",
  "topics": ["distinctive_word_or_phrase_1", "topic_2", ...],
  "quotes": ["verbatim quote from content", ...]
}

RULES:
- summary: mention WHO, WHAT, and WHY. 2-3 sentences.
- topics: 8-15 entries. Include proper nouns, distinctive technical terms, key concepts.
- quotes: 2-5 entries. EXACT verbatim from content (15-150 chars each).
- Output valid JSON only. No code fences. No commentary.`;

    const { getDefaultModel, resolveCompatibleModel } = require('../llm/client');
    const response = await opts.client.chat({
      model: resolveCompatibleModel(opts.model || process.env.WALLE_MODEL || getDefaultModel(), opts.client.type),
      maxTokens: 1024,
      messages: [{ role: 'user', content: prompt }],
    });

    const text = (response.content || '').trim();
    // Parse JSON (strip fences if present)
    let cleaned = text;
    const fenceMatch = cleaned.match(/^```(?:json)?\s*\n?([\s\S]*?)\n?\s*```$/);
    if (fenceMatch) cleaned = fenceMatch[1].trim();

    const parsed = JSON.parse(cleaned);

    return {
      memory_id: memory.id,
      summary: (parsed.summary || '').slice(0, 500),
      key_entities: JSON.stringify(extractKeyEntities(memory.content)),
      key_topics: JSON.stringify(parsed.topics || extractKeyTopics(memory.content)),
      domain: memory.domain || null,
      topic: memory.topic || null,
      timestamp: memory.timestamp,
      _quotes: parsed.quotes || [], // not stored in DB but useful for callers
    };
  } catch {
    // Fallback to rule-based
    return generateMemoryIndex(memory);
  }
}

module.exports = { generateMemoryIndex, batchGenerateIndex, generateEnrichedIndex, extractSummary, extractKeyEntities, extractKeyTopics };
