import {
  addEntity, getEntity, getEntityByName, findEntities, getEntitiesByType,
  getEntitiesByWorkspace, deleteEntity, getEntityCount,
  addRelation, getRelations, getOutgoingRelations, deleteRelation, getRelationCount,
  getDb
} from './db.mjs';

export function initKG() {
  console.log('[kg] Knowledge graph initialized');
}

export function addKGEntity(name, type, workspaceId = 'default', metadata = null) {
  return addEntity(name, type, workspaceId, metadata);
}

export function addKGRelation(sourceId, targetId, relation, weight = 1.0, metadata = null) {
  return addRelation(sourceId, targetId, relation, weight, metadata);
}

export function findKGEntities(query, opts = {}) {
  return findEntities(query, opts);
}

export function getEntityGraph(entityId, depth = 2) {
  // BFS traversal starting from entityId, up to `depth` hops
  // Track visited nodes to avoid cycles. Max 100 nodes total.
  // Returns: { nodes: [{id, name, type, metadata}], edges: [{sourceId, targetId, relation, weight}], root: entityId }
  const visited = new Set();
  const nodes = [];
  const edges = [];
  const queue = [{ id: entityId, currentDepth: 0 }];

  while (queue.length > 0 && nodes.length < 100) {
    const { id, currentDepth } = queue.shift();
    if (visited.has(id)) continue;
    visited.add(id);

    const entity = getEntity(id);
    if (!entity) continue;
    nodes.push({ id: entity.id, name: entity.name, type: entity.type, metadata: entity.metadata });

    if (currentDepth < depth) {
      const rels = getRelations(id);
      for (const r of rels) {
        edges.push({ sourceId: r.source_id, targetId: r.target_id, relation: r.relation, weight: r.weight });
        const neighborId = r.source_id === id ? r.target_id : r.source_id;
        if (!visited.has(neighborId)) {
          queue.push({ id: neighborId, currentDepth: currentDepth + 1 });
        }
      }
    }
  }

  return { nodes, edges, root: entityId };
}

export function getRelatedEntities(entityId, relation = null) {
  return relation ? getOutgoingRelations(entityId, relation) : getRelations(entityId);
}

export function mergeEntities(keepId, removeId) {
  // Re-point all relations referencing removeId to keepId, merge metadata, delete removeId
  const db = getDb();
  const txn = db.transaction(() => {
    // Re-point source_id references
    db.prepare('UPDATE kg_relations SET source_id = ? WHERE source_id = ?').run(keepId, removeId);
    // Re-point target_id references
    db.prepare('UPDATE kg_relations SET target_id = ? WHERE target_id = ?').run(keepId, removeId);
    // Delete self-loops that may have been created
    db.prepare('DELETE FROM kg_relations WHERE source_id = target_id').run();
    // Merge metadata
    const keep = getEntity(keepId);
    const remove = getEntity(removeId);
    if (keep && remove) {
      try {
        const keepMeta = keep.metadata ? JSON.parse(keep.metadata) : {};
        const removeMeta = remove.metadata ? JSON.parse(remove.metadata) : {};
        const merged = { ...removeMeta, ...keepMeta };
        db.prepare('UPDATE kg_entities SET metadata = ?, updated_at = datetime(\'now\') WHERE id = ?')
          .run(JSON.stringify(merged), keepId);
      } catch {}
    }
    // Delete the removed entity
    deleteEntity(removeId);
  });
  txn();
  return keepId;
}

export function getKGStats() {
  return { entityCount: getEntityCount(), relationCount: getRelationCount() };
}

export function getKGContext(topic, maxEntities = 10) {
  // Build formatted context string for LLM prompts
  if (!topic) return '';
  const entities = findEntities(topic, { limit: maxEntities });
  if (!entities.length) return '';

  let context = `## Knowledge Graph Context\nRelevant entities for "${topic}":\n\n`;
  for (const e of entities) {
    context += `- **${e.name}** (${e.type})`;
    if (e.metadata) {
      try {
        const meta = JSON.parse(e.metadata);
        if (typeof meta === 'string') context += `: ${meta}`;
        else if (meta.description) context += `: ${meta.description}`;
      } catch { context += `: ${String(e.metadata).slice(0, 100)}`; }
    }
    context += '\n';
    // Get relations for this entity
    const rels = getOutgoingRelations(e.id);
    for (const r of rels.slice(0, 5)) {
      context += `  → ${r.relation}: ${r.target_name}\n`;
    }
  }
  return context;
}

export function pruneStaleEntities(olderThanDays = 90) {
  const db = getDb();
  const result = db.prepare(
    `DELETE FROM kg_entities WHERE updated_at < datetime('now', '-' || ? || ' days')`
  ).run(olderThanDays);
  return result.changes;
}
