// Phase-1 intelligence memory. Uses node:sqlite when available and degrades to no-op.

import { existsSync, mkdirSync, writeFileSync } from 'fs';
import { dirname, join } from 'path';

export class IntelligenceStore {
  constructor(dbPath) {
    this.dbPath = dbPath;
    this.db = null;
    this.available = false;
    this.reason = null;
  }

  async init() {
    const dir = dirname(this.dbPath);
    if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
    try {
      const sqlite = await import('node:sqlite');
      const DatabaseSync = sqlite.DatabaseSync;
      this.db = new DatabaseSync(this.dbPath);
      this.db.exec(`
        CREATE TABLE IF NOT EXISTS runs (
          id INTEGER PRIMARY KEY AUTOINCREMENT,
          timestamp TEXT NOT NULL,
          sources_ok INTEGER DEFAULT 0,
          sources_degraded INTEGER DEFAULT 0,
          sources_failed INTEGER DEFAULT 0,
          direction TEXT,
          summary_json TEXT NOT NULL
        );
        CREATE TABLE IF NOT EXISTS predictions (
          id INTEGER PRIMARY KEY AUTOINCREMENT,
          created_at TEXT NOT NULL,
          title TEXT NOT NULL,
          type TEXT,
          confidence TEXT,
          source TEXT,
          payload_json TEXT NOT NULL
        );
        CREATE TABLE IF NOT EXISTS entities (
          id INTEGER PRIMARY KEY AUTOINCREMENT,
          first_seen TEXT NOT NULL,
          last_seen TEXT NOT NULL,
          name TEXT NOT NULL,
          kind TEXT NOT NULL,
          count INTEGER DEFAULT 1,
          UNIQUE(name, kind)
        );
      `);
      this.available = true;
    } catch (err) {
      this.available = false;
      this.reason = err.message;
      if (!existsSync(this.dbPath)) {
        writeFileSync(this.dbPath, '');
      }
    }
    return this;
  }

  recordRun(data, delta) {
    if (!this.available || !this.db) return;
    const meta = data.meta || {};
    const timestamp = meta.timestamp || new Date().toISOString();
    this.db.prepare(`INSERT INTO runs (timestamp, sources_ok, sources_degraded, sources_failed, direction, summary_json)
      VALUES (?, ?, ?, ?, ?, ?)`).run(
      timestamp,
      meta.sourcesOk || 0,
      meta.sourcesDegraded || 0,
      meta.sourcesFailed || 0,
      delta?.summary?.direction || null,
      JSON.stringify({ meta, delta: delta?.summary || null }),
    );
    for (const idea of data.ideas || []) {
      this.db.prepare(`INSERT INTO predictions (created_at, title, type, confidence, source, payload_json)
        VALUES (?, ?, ?, ?, ?, ?)`).run(
        timestamp,
        idea.title || 'Untitled idea',
        idea.type || null,
        idea.confidence || null,
        idea.source || data.ideasSource || null,
        JSON.stringify(idea),
      );
    }
    this._recordEntities(data, timestamp);
  }

  status() {
    return { available: this.available, path: this.dbPath, reason: this.reason };
  }

  _recordEntities(data, timestamp) {
    const names = [];
    for (const item of data.acled?.deadliestEvents || []) {
      if (item.country) names.push([item.country, 'country']);
      if (item.location) names.push([item.location, 'location']);
    }
    for (const item of data.news || []) {
      if (item.region) names.push([item.region, 'region']);
    }
    for (const [name, kind] of names.slice(0, 200)) {
      this.db.prepare(`INSERT INTO entities (first_seen, last_seen, name, kind, count)
        VALUES (?, ?, ?, ?, 1)
        ON CONFLICT(name, kind) DO UPDATE SET last_seen=excluded.last_seen, count=count+1`).run(
        timestamp,
        timestamp,
        String(name).slice(0, 160),
        kind,
      );
    }
  }
}
