// engine/db/migrations/006-metrics.js
//
// Phase 5: move engine/metrics.json into a `metrics` table.
//
// metrics.json's shape is heterogeneous: a flat object whose top-level
// keys mix per-agent counters (regular agent ids) with reserved keys
// (`_engine`, `_daily`, `_contextPressure`). The SQL projection uses a
// single table with a (kind, key) primary key so each top-level entry
// becomes one row:
//
//   kind                | key                | data (JSON blob)
//   --------------------+--------------------+-----------------------------
//   agent               | dallas             | { tasksCompleted, ... }
//   agent               | ripley             | { ...                 }
//   engine_category     | command-center     | { calls, costUsd, ... }
//   engine_category     | doc-chat           | { ...                 }
//   daily               | 2026-05-28         | { costUsd, tasks, ... }
//   context_pressure    | current            | { ...                 }
//
// Engineless extensions land transparently in `data` — no schema bump
// required to add a new counter field per category. New top-level kinds
// (e.g. `pipeline`) only need a new sentinel in the reserved-key list
// inside the store; the table schema is forward-compatible.
//
// Backfill: read metrics.json once, split by reserved-key sentinel,
// INSERT one row per entry. The JSON file stays on disk as a dual-write
// mirror so legacy direct-readers (none in engine, a few in tests) keep
// working.

const path = require('path');
const fs = require('fs');

function _resolveMinionsDir() {
  // Canonical order: MINIONS_TEST_DIR wins over MINIONS_HOME (matches
  // engine/db/index.js + migrations 002/003/004). Reversing this lets a
  // test that sets both env vars open the DB at MINIONS_TEST_DIR but
  // backfill its tables from MINIONS_HOME — cross-directory corruption.
  const envHome = process.env.MINIONS_TEST_DIR || process.env.MINIONS_HOME;
  if (envHome) return envHome;
  try { return require('../../shared').MINIONS_DIR; } catch { return null; }
}

const RESERVED_KEYS = new Map([
  ['_engine', 'engine_category'],
  ['_daily', 'daily'],
  ['_contextPressure', 'context_pressure'],
]);

module.exports = {
  version: 6,
  description: 'metrics: schema + metrics.json backfill',
  up(db) {
    db.exec(`
      CREATE TABLE metrics (
        kind        TEXT NOT NULL,
        key         TEXT NOT NULL,
        data        TEXT NOT NULL,
        updated_at  INTEGER NOT NULL,
        PRIMARY KEY (kind, key)
      );
      CREATE INDEX idx_metrics_kind ON metrics(kind);
    `);

    const minionsDir = _resolveMinionsDir();
    if (!minionsDir) return;
    const metricsPath = path.join(minionsDir, 'engine', 'metrics.json');
    if (!fs.existsSync(metricsPath)) return;

    let raw;
    try { raw = JSON.parse(fs.readFileSync(metricsPath, 'utf8')); }
    catch (e) {
      throw new Error(`engine/db/006-metrics: cannot parse metrics.json: ${e.message}`);
    }
    if (!raw || typeof raw !== 'object') return;

    const insert = db.prepare(`
      INSERT INTO metrics (kind, key, data, updated_at)
      VALUES (?, ?, ?, ?)
    `);

    const now = Date.now();
    let inserted = 0;

    for (const [topKey, topValue] of Object.entries(raw)) {
      const reservedKind = RESERVED_KEYS.get(topKey);
      if (reservedKind) {
        if (reservedKind === 'context_pressure') {
          // Single-blob reserved key — store as one row keyed 'current'.
          insert.run('context_pressure', 'current', JSON.stringify(topValue), now);
          inserted += 1;
          continue;
        }
        // Nested reserved key (_engine / _daily) — one row per inner key.
        if (topValue && typeof topValue === 'object') {
          for (const [innerKey, innerValue] of Object.entries(topValue)) {
            insert.run(reservedKind, innerKey, JSON.stringify(innerValue), now);
            inserted += 1;
          }
        }
        continue;
      }
      // Regular agent counter row.
      insert.run('agent', topKey, JSON.stringify(topValue), now);
      inserted += 1;
    }

    // eslint-disable-next-line no-console
    console.log(`[db-migrate] v6: backfilled ${inserted} metrics rows; metrics.json kept as dual-write mirror`);
  },
};
