'use strict';

const Database = require('better-sqlite3');
const fs = require('node:fs');
const path = require('node:path');
const os = require('node:os');

/**
 * Get the database path.
 * Priority: RAH_DB_PATH env var > default app data location
 */
function getDatabasePath() {
  if (process.env.RAH_DB_PATH) {
    return process.env.RAH_DB_PATH;
  }

  // Default: ~/Library/Application Support/RA-H/db/rah.sqlite
  return path.join(
    os.homedir(),
    'Library',
    'Application Support',
    'RA-H',
    'db',
    'rah.sqlite'
  );
}

let db = null;

/**
 * Initialize the database connection.
 * Call this once at startup.
 */
function initDatabase() {
  if (db) {
    return db;
  }

  const dbPath = getDatabasePath();

  // Auto-create database if it doesn't exist
  if (!fs.existsSync(dbPath)) {
    fs.mkdirSync(path.dirname(dbPath), { recursive: true });
    db = new Database(dbPath);
    console.error('[RA-H] Creating new database at:', dbPath);

    // Create core schema
    db.exec(`
      CREATE TABLE IF NOT EXISTS nodes (
        id INTEGER PRIMARY KEY,
        title TEXT,
        description TEXT,
        notes TEXT,
        link TEXT,
        event_date TEXT,
        created_at TEXT,
        updated_at TEXT,
        metadata TEXT,
        chunk TEXT,
        embedding BLOB,
        embedding_updated_at TEXT,
        embedding_text TEXT,
        chunk_status TEXT DEFAULT 'not_chunked'
      );

      CREATE TABLE IF NOT EXISTS edges (
        id INTEGER PRIMARY KEY,
        from_node_id INTEGER NOT NULL,
        to_node_id INTEGER NOT NULL,
        source TEXT,
        created_at TEXT,
        context TEXT,
        FOREIGN KEY (from_node_id) REFERENCES nodes(id) ON DELETE CASCADE,
        FOREIGN KEY (to_node_id) REFERENCES nodes(id) ON DELETE CASCADE
      );
      CREATE INDEX IF NOT EXISTS idx_edges_from ON edges(from_node_id);
      CREATE INDEX IF NOT EXISTS idx_edges_to ON edges(to_node_id);

      CREATE TABLE IF NOT EXISTS node_dimensions (
        node_id INTEGER NOT NULL,
        dimension TEXT NOT NULL,
        PRIMARY KEY (node_id, dimension),
        FOREIGN KEY (node_id) REFERENCES nodes(id) ON DELETE CASCADE
      ) WITHOUT ROWID;
      CREATE INDEX IF NOT EXISTS idx_dim_by_dimension ON node_dimensions(dimension, node_id);
      CREATE INDEX IF NOT EXISTS idx_dim_by_node ON node_dimensions(node_id, dimension);

      CREATE TABLE IF NOT EXISTS dimensions (
        name TEXT PRIMARY KEY,
        description TEXT,
        icon TEXT,
        is_priority INTEGER DEFAULT 0,
        updated_at TEXT DEFAULT CURRENT_TIMESTAMP
      );

      -- Seed default dimensions
      INSERT OR IGNORE INTO dimensions (name, is_priority) VALUES ('research', 1);
      INSERT OR IGNORE INTO dimensions (name, is_priority) VALUES ('ideas', 1);
      INSERT OR IGNORE INTO dimensions (name, is_priority) VALUES ('projects', 1);
      INSERT OR IGNORE INTO dimensions (name, is_priority) VALUES ('memory', 1);
      INSERT OR IGNORE INTO dimensions (name, is_priority) VALUES ('preferences', 1);
    `);

    console.error('[RA-H] Database created successfully');
  } else {
    db = new Database(dbPath);
  }

  // Configure SQLite for performance
  db.pragma('journal_mode = WAL');
  db.pragma('synchronous = NORMAL');
  db.pragma('cache_size = 5000');
  db.pragma('busy_timeout = 5000');

  return db;
}

/**
 * Get the database instance.
 * Throws if not initialized.
 */
function getDb() {
  if (!db) {
    throw new Error('Database not initialized. Call initDatabase() first.');
  }
  return db;
}

/**
 * Execute a query and return rows.
 */
function query(sql, params = []) {
  const database = getDb();
  const stmt = database.prepare(sql);

  const sqlLower = sql.trim().toLowerCase();
  if (sqlLower.startsWith('select') || sqlLower.startsWith('with') || sqlLower.startsWith('pragma') || sqlLower.includes('returning')) {
    return params.length > 0 ? stmt.all(...params) : stmt.all();
  } else {
    const result = params.length > 0 ? stmt.run(...params) : stmt.run();
    return {
      changes: result.changes,
      lastInsertRowid: Number(result.lastInsertRowid)
    };
  }
}

/**
 * Execute a query in a transaction.
 */
function transaction(callback) {
  const database = getDb();
  const txn = database.transaction(callback);
  return txn();
}

/**
 * Close the database connection.
 */
function closeDatabase() {
  if (db) {
    db.close();
    db = null;
  }
}

module.exports = {
  initDatabase,
  getDb,
  query,
  transaction,
  closeDatabase,
  getDatabasePath
};
