// engine/db/migrations/009-qa.js
//
// Phase 8: move the two QA state files into SQL.
//
//   engine/qa-runs.json      -> qa_runs       (top-level array → row per id)
//   engine/qa-sessions.json  -> qa_sessions   (top-level array → row per id)
//
// Mirrors the dual-write / content-hash divergence pattern established by
// the watches and Phase 7 small-state stores. JSON sidecars stay in place as
// dual-write mirrors for one release cycle (gated by `engine.qaDualWriteJson`).

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

function _resolveMinionsDir() {
  const envHome = process.env.MINIONS_HOME || process.env.MINIONS_TEST_DIR;
  if (envHome) return envHome;
  try { return require('../../shared').MINIONS_DIR; } catch { return null; }
}

function _toMs(v) {
  if (v == null) return null;
  if (typeof v === 'number') return Number.isFinite(v) ? v : null;
  const parsed = Date.parse(v);
  return Number.isFinite(parsed) ? parsed : null;
}

function _readJsonOr(filePath, fallback) {
  try {
    const raw = fs.readFileSync(filePath, 'utf8');
    return JSON.parse(raw);
  } catch { return fallback; }
}

module.exports = {
  version: 9,
  description: 'qa_runs + qa_sessions',
  up(db) {
    db.exec(`
      CREATE TABLE qa_runs (
        id            TEXT PRIMARY KEY,
        runbook_id    TEXT NOT NULL,
        target_name   TEXT NOT NULL,
        project       TEXT,
        work_item_id  TEXT,
        status        TEXT NOT NULL,
        started_at    INTEGER,
        completed_at  INTEGER,
        created_at    INTEGER NOT NULL,
        data          TEXT NOT NULL
      );
      CREATE INDEX idx_qa_runs_status        ON qa_runs(status);
      CREATE INDEX idx_qa_runs_created_at    ON qa_runs(created_at DESC);
      CREATE INDEX idx_qa_runs_runbook       ON qa_runs(runbook_id);
      CREATE INDEX idx_qa_runs_target        ON qa_runs(target_name);
      CREATE INDEX idx_qa_runs_work_item     ON qa_runs(work_item_id) WHERE work_item_id IS NOT NULL;

      CREATE TABLE qa_sessions (
        id                TEXT PRIMARY KEY,
        state             TEXT NOT NULL,
        primary_project   TEXT,
        qa_run_id         TEXT,
        created_at        INTEGER NOT NULL,
        updated_at        INTEGER NOT NULL,
        completed_at      INTEGER,
        data              TEXT NOT NULL
      );
      CREATE INDEX idx_qa_sessions_state         ON qa_sessions(state);
      CREATE INDEX idx_qa_sessions_created_at    ON qa_sessions(created_at DESC);
      CREATE INDEX idx_qa_sessions_project       ON qa_sessions(primary_project);
      CREATE INDEX idx_qa_sessions_qa_run        ON qa_sessions(qa_run_id) WHERE qa_run_id IS NOT NULL;
    `);

    const minionsDir = _resolveMinionsDir();
    if (!minionsDir) return;
    const now = Date.now();
    let inserted = 0;

    // ── qa_runs ────────────────────────────────────────────────────────────
    {
      const raw = _readJsonOr(path.join(minionsDir, 'engine', 'qa-runs.json'), null);
      if (Array.isArray(raw)) {
        const ins = db.prepare(`
          INSERT INTO qa_runs (id, runbook_id, target_name, project, work_item_id, status, started_at, completed_at, created_at, data)
          VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
          ON CONFLICT(id) DO NOTHING
        `);
        for (const run of raw) {
          if (!run || !run.id) continue;
          try {
            ins.run(
              String(run.id),
              String(run.runbookId || ''),
              String(run.targetName || ''),
              run.project || null,
              run.workItemId || null,
              String(run.status || 'pending'),
              _toMs(run.startedAt),
              _toMs(run.completedAt),
              _toMs(run.createdAt) || now,
              JSON.stringify(run),
            );
            inserted += 1;
          } catch { /* duplicate / corrupt — skip */ }
        }
      }
    }

    // ── qa_sessions ────────────────────────────────────────────────────────
    {
      const raw = _readJsonOr(path.join(minionsDir, 'engine', 'qa-sessions.json'), null);
      if (Array.isArray(raw)) {
        const ins = db.prepare(`
          INSERT INTO qa_sessions (id, state, primary_project, qa_run_id, created_at, updated_at, completed_at, data)
          VALUES (?, ?, ?, ?, ?, ?, ?, ?)
          ON CONFLICT(id) DO NOTHING
        `);
        for (const session of raw) {
          if (!session || !session.id) continue;
          try {
            ins.run(
              String(session.id),
              String(session.state || 'pending'),
              session.primaryProject || (session.spec && session.spec.project) || null,
              session.qaRunId || null,
              _toMs(session.createdAt) || now,
              _toMs(session.updatedAt) || _toMs(session.createdAt) || now,
              _toMs(session.completedAt),
              JSON.stringify(session),
            );
            inserted += 1;
          } catch { /* duplicate / corrupt — skip */ }
        }
      }
    }

    // eslint-disable-next-line no-console
    console.log(`[db-migrate] v9: backfilled ${inserted} QA rows; JSON files kept as dual-write mirrors`);
  },
};
