#!/usr/bin/env node
// tools/test-rollback.mjs — Rollback planner + executor for the LLM-first router overhaul.
//
// Plan: docs/superpowers/plans/2026-05-25-llm-first-router-overhaul.md Task 1.
// Spec: docs/superpowers/specs/2026-05-24-llm-first-router-overhaul-design.md §13 (rollback).
//
// Two responsibilities:
//   1. planRollback()  — pure, returns a description of what rollback does (testable)
//   2. dryRun() / execRollback()  — CLI entry points
//
// Safety:
//   - execFileSync (no shell, no command injection)
//   - Entry-point guard uses resolve() (Windows + Cyrillic paths safe, per quirk #103)
//   - episodes-*.jsonl and observer/notes/* are PRESERVED, never reverted (G5/G6)
//   - Parser stays forward-compatible to schema v4 after rollback (G5, Task 15)

import {
  existsSync,
  copyFileSync,
  readdirSync,
  rmSync,
  mkdirSync,
  statSync,
} from 'node:fs';
import { join, resolve } from 'node:path';
import { homedir } from 'node:os';
import { execFileSync } from 'node:child_process';
import { fileURLToPath } from 'node:url';

const ARCHIVE = 'docs/archive/llm-bootstrap-2026-05';

/**
 * Pure description of the rollback plan.
 * Used by tools/test-rollback.test.mjs and as the source of truth for the CLI.
 */
export function planRollback() {
  return {
    gitTag: 'brain-pre-llm-bootstrap',
    gitStrategy: 'git checkout brain-pre-llm-bootstrap -- <tracked paths>',
    userLevelRestores: [
      {
        from: `${ARCHIVE}/settings-snapshot/user-settings.json.pre-overhaul`,
        to: '~/.claude/settings.json',
      },
      { from: `${ARCHIVE}/user-hooks/*`, to: '~/.claude/hooks/' },
    ],
    flagStrategy: 'restore-snapshot-delete-new',
    preserve: [
      'docs/observer/episodes-*.jsonl',
      'docs/observer/notes/*',
    ],
    parserNote:
      'после отката parser остаётся forward-compatible к v4 эпизодам (read-only graceful skip) — Task 15 (G5)',
  };
}

/**
 * Dry-run: verify rollback artefacts exist and surface missing ones.
 * Returns true if rollback is ready, false otherwise.
 */
export function dryRun() {
  const plan = planRollback();
  let ok = true;

  const baseSnap = `${ARCHIVE}/settings-snapshot/user-settings.json.pre-overhaul`;
  if (!existsSync(baseSnap)) {
    console.error('MISSING snapshot:', baseSnap);
    ok = false;
  }
  const projSnap = `${ARCHIVE}/settings-snapshot/project-settings.json.pre-overhaul`;
  if (!existsSync(projSnap)) {
    console.error('MISSING snapshot:', projSnap);
    ok = false;
  }
  const hooksDir = `${ARCHIVE}/user-hooks`;
  if (!existsSync(hooksDir) || readdirSync(hooksDir).length === 0) {
    console.error('MISSING or empty hooks snapshot:', hooksDir);
    ok = false;
  }
  const nodesSnap = `${ARCHIVE}/nodes-yaml-archive/nodes.yaml.pre-overhaul`;
  if (!existsSync(nodesSnap)) {
    console.error('MISSING snapshot:', nodesSnap);
    ok = false;
  }

  try {
    execFileSync('git', ['rev-parse', plan.gitTag], { stdio: 'pipe' });
  } catch {
    console.error('MISSING git tag:', plan.gitTag);
    ok = false;
  }

  console.log(ok ? '[dry-run] OK — rollback ready' : '[dry-run] FAIL — see above');
  return ok;
}

/**
 * Execute rollback of user-level state + runtime flags.
 * Git-tracked rollback is left to the operator (separate manual step in ROLLBACK.md)
 * to keep destructive `git checkout` explicit.
 */
export function execRollback() {
  const home = homedir();

  // 1. user settings.json
  const usFrom = `${ARCHIVE}/settings-snapshot/user-settings.json.pre-overhaul`;
  if (existsSync(usFrom)) {
    copyFileSync(usFrom, join(home, '.claude', 'settings.json'));
    console.log('[execute] restored ~/.claude/settings.json');
  } else {
    console.error('[execute] SKIP user settings — snapshot missing');
  }

  // 2. user hooks (full directory restore — wipe new hooks, restore snapshot)
  const hooksSrc = `${ARCHIVE}/user-hooks`;
  const hooksDst = join(home, '.claude', 'hooks');
  if (existsSync(hooksSrc)) {
    if (!existsSync(hooksDst)) mkdirSync(hooksDst, { recursive: true });
    // wipe current
    for (const f of readdirSync(hooksDst)) {
      const fp = join(hooksDst, f);
      if (statSync(fp).isFile()) rmSync(fp);
    }
    // restore snapshot
    let count = 0;
    for (const f of readdirSync(hooksSrc)) {
      const sp = join(hooksSrc, f);
      if (statSync(sp).isFile()) {
        copyFileSync(sp, join(hooksDst, f));
        count++;
      }
    }
    console.log(`[execute] restored ~/.claude/hooks/ (${count} files)`);
  } else {
    console.error('[execute] SKIP user hooks — snapshot missing');
  }

  // 3. runtime flags: delete *-mode.json files not present in snapshot, restore snapshot files
  const runtimeDir = join(home, '.claude', 'runtime');
  const snapDir = `${ARCHIVE}/runtime-flags-snapshot`;
  if (existsSync(runtimeDir)) {
    const snapFlags = existsSync(snapDir) ? readdirSync(snapDir) : [];
    let deleted = 0;
    for (const f of readdirSync(runtimeDir).filter((x) => x.endsWith('-mode.json'))) {
      if (!snapFlags.includes(f)) {
        rmSync(join(runtimeDir, f));
        deleted++;
      }
    }
    let restored = 0;
    for (const f of snapFlags) {
      copyFileSync(join(snapDir, f), join(runtimeDir, f));
      restored++;
    }
    console.log(
      `[execute] runtime flags: deleted ${deleted} new, restored ${restored} from snapshot`,
    );
  } else {
    console.error('[execute] SKIP runtime flags — ~/.claude/runtime/ missing');
  }

  console.log(
    '[execute] user-level + flags restored. ' +
      'Now run: git checkout brain-pre-llm-bootstrap -- . && npm install',
  );
}

// Entry-point guard — Cyrillic-safe (quirk #103: import.meta.url === argv[1] fails on RU paths).
const argv1 = process.argv[1] ? resolve(process.argv[1]) : '';
const here = fileURLToPath(import.meta.url);
const isMain = argv1 && argv1 === here;

if (isMain) {
  const mode = process.argv[2];
  if (mode === '--dry-run') {
    process.exit(dryRun() ? 0 : 1);
  } else if (mode === '--execute') {
    execRollback();
  } else {
    console.log('usage: node tools/test-rollback.mjs --dry-run | --execute');
    console.log('');
    console.log('  --dry-run    verify rollback artefacts are in place; exit 0 if ready');
    console.log('  --execute    restore user-level state + runtime flags from snapshot');
    console.log('               (run "git checkout brain-pre-llm-bootstrap -- ." separately)');
  }
}
