import { storage } from './storage';
import * as db from './db';

/**
 * Knowledge-base mutations for the R42 chatbot path.
 *
 * Topics and relations live in PocketBase (via db.js). The suggestions queue
 * (pending / approved / rejected) is ephemeral and stored in localStorage
 * since there is no PocketBase collection for it.
 *
 * Every write dispatches `respellion:kb-updated` so the D3 graph and the
 * suggestions panel refresh without a page reload.
 */

function dispatchUpdated() {
  try {
    window.dispatchEvent(new CustomEvent('respellion:kb-updated'));
  } catch {
    // non-browser environment — no-op
  }
}

export const kbStore = {
  /**
   * Apply a validated delta directly to PocketBase topics + relations.
   * Skips topics/relations that already exist.
   */
  async applyDelta(delta) {
    if (!delta) return { addedTopics: 0, addedRelations: 0 };

    const [existingTopics, existingRelations] = await Promise.all([
      db.getTopics(),
      db.getRelations(),
    ]);

    const existingIds = new Set(existingTopics.map(t => t.id));
    const existingLabels = new Set(existingTopics.map(t => (t.label || '').toLowerCase()));

    let addedTopics = 0;
    for (const t of delta.topics || []) {
      if (existingIds.has(t.id) || existingLabels.has((t.label || '').toLowerCase())) continue;
      await db.upsertTopic({
        id: t.id,
        label: t.label,
        type: t.type || 'concept',
        description: t.description || '',
      });
      existingIds.add(t.id);
      existingLabels.add((t.label || '').toLowerCase());
      addedTopics++;
    }

    let addedRelations = 0;
    const allIds = new Set([...existingTopics.map(t => t.id), ...(delta.topics || []).map(t => t.id)]);
    for (const r of delta.relations || []) {
      if (!allIds.has(r.source) || !allIds.has(r.target) || r.source === r.target) continue;
      const dup = existingRelations.some(x => {
        const sx = typeof x.source === 'object' ? x.source.id : x.source;
        const tx = typeof x.target === 'object' ? x.target.id : x.target;
        return sx === r.source && tx === r.target && x.type === r.type;
      });
      if (dup) continue;
      await db.addRelation({ source: r.source, target: r.target, type: r.type });
      addedRelations++;
    }

    dispatchUpdated();
    return { addedTopics, addedRelations };
  },

  /** Queue a suggestion for admin review (stored in localStorage). */
  appendSuggestion(suggestion) {
    const list = storage.get('kb:suggestions', []) || [];
    const entry = {
      id: `sug_${Date.now()}_${Math.random().toString(36).slice(2, 7)}`,
      ts: Date.now(),
      status: 'pending',
      reason: suggestion.reason || '',
      proposedBy: suggestion.proposedBy || null,
      proposedByName: suggestion.proposedByName || null,
      topics: suggestion.topics || [],
      relations: suggestion.relations || [],
    };
    storage.set('kb:suggestions', [...list, entry]);
    dispatchUpdated();
    return entry;
  },

  listSuggestions(status) {
    const all = storage.get('kb:suggestions', []) || [];
    if (!status) return all;
    return all.filter(s => s.status === status);
  },

  async approveSuggestion(id) {
    const all = storage.get('kb:suggestions', []) || [];
    const target = all.find(s => s.id === id);
    if (!target || target.status !== 'pending') return null;
    const result = await this.applyDelta(target);
    target.status = 'approved';
    target.appliedAt = Date.now();
    storage.set('kb:suggestions', all);
    dispatchUpdated();
    return result;
  },

  rejectSuggestion(id) {
    const all = storage.get('kb:suggestions', []) || [];
    const target = all.find(s => s.id === id);
    if (!target || target.status !== 'pending') return null;
    target.status = 'rejected';
    target.rejectedAt = Date.now();
    storage.set('kb:suggestions', all);
    dispatchUpdated();
    return target;
  },
};
