#!/usr/bin/env node
/**
 * PR-C Deprecation Check Script
 * Scans OpenClaw config and plugin state for deprecated modules.
 * 
 * Run: node scripts/check-deprecations.mjs
 * 
 * Checks:
 *   1. Active Memory blocking mode
 *   2. Dreaming REM phase enabled
 *   3. Dream Diary generation
 *   4. QMD search mode / QMD engine references
 *   5. Honcho memory plugin enabled
 *   6. LanceDB memory plugin enabled  
 *   7. memory-wiki plugin loaded
 *   8. Commitments auto-infer
 *   9. Grounded Backfill / REM Backfill CLI usage
 */

import { readFileSync, existsSync, readdirSync } from "node:fs";
import { join } from "node:path";
import { homedir } from "node:os";
import { warnOnce, warnMany } from "./lib/deprecation-warning.mjs";

const AGENTS_HOME = join(homedir(), ".openclaw");
const CONFIG_PATH = join(AGENTS_HOME, "openclaw.json");
const OPENCLAW_HOME = process.env.OPENCLAW_HOME || "/opt/homebrew/lib/node_modules/openclaw";
const EXTENSIONS_DIR = join(OPENCLAW_HOME, "dist", "extensions");

// Load user config
function loadConfig() {
  if (!existsSync(CONFIG_PATH)) return null;
  try {
    return JSON.parse(readFileSync(CONFIG_PATH, "utf8"));
  } catch {
    return null;
  }
}

// Load plugin entry for a given extension id
function loadPlugin(id) {
  const pluginJsonPath = join(EXTENSIONS_DIR, id, "openclaw.plugin.json");
  if (!existsSync(pluginJsonPath)) return null;
  try {
    return JSON.parse(readFileSync(pluginJsonPath, "utf8"));
  } catch {
    return null;
  }
}

// Check if a plugin is enabled in user config
function isPluginEnabled(config, pluginId) {
  const entries = config?.plugins?.entries;
  if (!entries) return false;
  const entry = entries[pluginId];
  if (!entry) return false;
  return entry.enabled !== false;
}

// ─── Check Functions ────────────────────────────────

function checkActiveMemoryBlocking(config) {
  const warnings = [];
  const entry = config?.plugins?.entries?.["active-memory"];
  if (!entry) return warnings;
  
  const mode = entry.config?.mode;
  if (mode === "blocking") {
    warnings.push({
      key: "active-memory.blocking",
      message: "active-memory blocking mode is deprecated. Set mode to 'precompute' instead."
    });
  }
  return warnings;
}

function checkDreamingRemPhase(config) {
  const warnings = [];
  const entry = config?.plugins?.entries?.["memory-core"];
  if (!entry) return warnings;
  
  const dreaming = entry.config?.dreaming;
  if (!dreaming) return warnings;
  
  // Check REM phase enabled
  const remEnabled = dreaming?.phases?.rem?.enabled;
  if (remEnabled === true) {
    warnings.push({
      key: "dreaming.rem-phase",
      message: "Dreaming REM phase is deprecated. It will be replaced by Collect/Promote."
    });
  }
  
  return warnings;
}

function checkDreamDiary(config) {
  const warnings = [];
  const entry = config?.plugins?.entries?.["memory-core"];
  if (!entry) return warnings;
  
  const dreaming = entry.config?.dreaming;
  if (!dreaming) return warnings;
  
  // Dream Diary is implied by REM phase or certain storage modes
  const storage = dreaming?.storage;
  const hasDiaryMode = storage?.mode === "separate" || storage?.mode === "both";
  const separateReports = storage?.separateReports === true;
  
  if (hasDiaryMode || separateReports) {
    warnings.push({
      key: "dreaming.dream-diary",
      message: "Dream Diary generation is deprecated and will be removed."
    });
  }
  
  // Also check if dreaming has a configured model (used for diary)
  if (dreaming?.model) {
    warnings.push({
      key: "dreaming.diary-model",
      message: "Dreaming diary model override is deprecated."
    });
  }
  
  return warnings;
}

function checkQmdReference(config) {
  const warnings = [];
  
  // Check memory search config for QMD
  const memorySearch = config?.agents?.defaults?.memorySearch;
  if (memorySearch?.provider === "qmd" || memorySearch?.backend === "qmd") {
    warnings.push({
      key: "qmd.memory-search",
      message: "QMD memory engine is legacy. Migrate to Builtin MemoryCore."
    });
  }
  
  // Check active-memory QMD reference
  const activeCfg = config?.plugins?.entries?.["active-memory"]?.config;
  if (activeCfg?.qmd?.searchMode) {
    warnings.push({
      key: "qmd.active-memory",
      message: "QMD search mode in active-memory is legacy. Remove qmd config."
    });
  }
  
  return warnings;
}

function checkHonchoLanceDB(config) {
  const warnings = [];
  
  // Check if honcho or lancedb plugins are loaded
  const pluginEntries = config?.plugins?.entries || {};
  
  if (pluginEntries["memory-honcho"]?.enabled !== false && isPluginInExtensions("honcho")) {
    warnings.push({
      key: "honcho.plugin",
      message: "Honcho memory plugin is legacy. Existing data readable during migration."
    });
  }
  
  if (pluginEntries["memory-lancedb"]?.enabled !== false && isPluginInExtensions("lancedb")) {
    warnings.push({
      key: "lancedb.plugin",
      message: "LanceDB memory plugin is legacy. Existing data readable during migration."
    });
  }
  
  return warnings;
}

function checkMemoryWiki(config) {
  const warnings = [];
  const entry = config?.plugins?.entries?.["memory-wiki"];
  
  if (entry?.enabled !== false) {
    // Check if memory-wiki extension exists and isn't disabled
    const wikiPlugin = loadPlugin("memory-wiki");
    if (wikiPlugin) {
      warnings.push({
        key: "memory-wiki.plugin",
        message: "memory-wiki plugin is legacy. wiki_search/wiki_get/wiki_apply/wiki_lint/wiki_status remain available during migration."
      });
    }
  }
  
  return warnings;
}

function checkCommitmentsAutoInfer(config) {
  const warnings = [];
  
  // Commitments auto-infer is part of the session-memory bundled module
  const commitments = config?.commitments;
  if (commitments?.autoInfer === true) {
    warnings.push({
      key: "commitments.auto-infer",
      message: "Commitments auto-infer is deprecated. Use explicit cron tasks instead."
    });
  }
  
  return warnings;
}

function checkGroundedBackfill(config) {
  const warnings = [];
  
  // Grounded Backfill is a CLI feature — we check if related config exists
  const dreaming = config?.plugins?.entries?.["memory-core"]?.config?.dreaming;
  if (!dreaming) return warnings;
  
  // If dreaming has unusual storage paths that suggest backfill usage
  const storage = dreaming?.storage;
  if (storage?.mode === "separate") {
    warnings.push({
      key: "backfill.storage-mode",
      message: "Grounded Backfill / REM Backfill is deprecated and will not evolve further."
    });
  }
  
  return warnings;
}

// ─── Helpers ────────────────────────────────────────

function isPluginInExtensions(name) {
  try {
    const dirs = readdirSync(EXTENSIONS_DIR, { withFileTypes: true })
      .filter(d => d.isDirectory());
    
    for (const d of dirs) {
      if (d.name.includes(name)) return true;
      // Check plugin.json
      const pluginPath = join(EXTENSIONS_DIR, d.name, "openclaw.plugin.json");
      if (existsSync(pluginPath)) {
        const plugin = JSON.parse(readFileSync(pluginPath, "utf8"));
        if (plugin.id?.includes(name)) return true;
      }
    }
  } catch {}
  return false;
}

// ─── Legacy Registry (PR-1 Freeze) ───────────────────
// Maps deprecation keys to replacement info and migration window.
// Used to enhance check-deprecations output.

const LEGACY_REGISTRY = {
  "active-memory.blocking": {
    module: "active-memory blocking mode",
    status: "Active. Deprecated.",
    replacement: 'Set mode to "precompute" in active-memory config',
    migrationWindow: "90 days from 2026-06-04",
    removalTarget: "2026-09-04",
  },
  "dreaming.rem-phase": {
    module: "Dreaming REM phase",
    status: "Active. Deprecated.",
    replacement: "Collect/Promote two-phase dreaming (PR-5)",
    migrationWindow: "90 days from 2026-06-04",
    removalTarget: "2026-09-04",
  },
  "dreaming.dream-diary": {
    module: "Dream Diary",
    status: "Active. Deprecated.",
    replacement: "Inline dreaming output (no separate diary storage)",
    migrationWindow: "90 days from 2026-06-04",
    removalTarget: "2026-09-04",
  },
  "dreaming.diary-model": {
    module: "Dream Diary model override",
    status: "Active. Deprecated.",
    replacement: "Use default dreaming model",
    migrationWindow: "90 days from 2026-06-04",
    removalTarget: "2026-09-04",
  },
  "qmd.memory-search": {
    module: "QMD memory search engine",
    status: "Active. Deprecated.",
    replacement: "Builtin MemoryCore FTS5 + BM25",
    migrationWindow: "90 days from 2026-06-04",
    removalTarget: "2026-09-04",
  },
  "qmd.active-memory": {
    module: "QMD active-memory search mode",
    status: "Active. Deprecated.",
    replacement: "Remove qmd config block from active-memory",
    migrationWindow: "90 days from 2026-06-04",
    removalTarget: "2026-09-04",
  },
  "honcho.plugin": {
    module: "Honcho memory plugin",
    status: "Legacy. Data readable during migration.",
    replacement: "memory-core (FTS5 + BM25)",
    migrationWindow: "60 days from 2026-06-04",
    removalTarget: "2026-08-04",
  },
  "lancedb.plugin": {
    module: "LanceDB memory plugin",
    status: "Legacy. Data readable during migration.",
    replacement: "memory-core (FTS5 + BM25)",
    migrationWindow: "60 days from 2026-06-04",
    removalTarget: "2026-08-04",
  },
  "memory-wiki.plugin": {
    module: "memory-wiki plugin",
    status: "Active. Deprecated.",
    replacement: "memory-core wiki compilation",
    migrationWindow: "90 days from 2026-06-04",
    removalTarget: "2026-09-04",
  },
  "commitments.auto-infer": {
    module: "Commitments auto-infer",
    status: "Active. Deprecated.",
    replacement: "Explicit cron tasks (use cron tool)",
    migrationWindow: "90 days from 2026-06-04",
    removalTarget: "2026-09-04",
  },
  "backfill.storage-mode": {
    module: "Grounded Backfill / REM Backfill CLI",
    status: "Active. Deprecated.",
    replacement: "No replacement. Stop using immediately.",
    migrationWindow: "Immediate — effective 2026-06-04",
    removalTarget: "2026-06-04",
  },
};

function getLegacyInfo(key) {
  return LEGACY_REGISTRY[key] || null;
}

function formatLegacyTable(warnings) {
  // Group warnings by their legacy info
  const seen = new Set();
  const rows = [];
  for (const w of warnings) {
    if (seen.has(w.key)) continue;
    seen.add(w.key);
    const info = LEGACY_REGISTRY[w.key] || {
      module: w.key,
      status: "Unknown",
      replacement: "N/A",
      migrationWindow: "N/A",
      removalTarget: "N/A",
    };
    rows.push(info);
  }
  return rows;
}

// ─── Main ────────────────────────────────────────────

function runAllChecks() {
  const config = loadConfig();
  const allWarnings = [];
  const checkResults = [];

  if (!config) {
    console.warn("[DEPRECATED][OpenClaw v2] config: Could not load openclaw.json");
    return { warnings: [], results: [{ name: "config", error: "Could not load config" }] };
  }

  const checks = [
    { name: "active-memory blocking mode", fn: () => checkActiveMemoryBlocking(config) },
    { name: "dreaming REM phase", fn: () => checkDreamingRemPhase(config) },
    { name: "dream diary", fn: () => checkDreamDiary(config) },
    { name: "QMD reference", fn: () => checkQmdReference(config) },
    { name: "Honcho / LanceDB", fn: () => checkHonchoLanceDB(config) },
    { name: "memory-wiki", fn: () => checkMemoryWiki(config) },
    { name: "commitments auto-infer", fn: () => checkCommitmentsAutoInfer(config) },
    { name: "grounded backfill", fn: () => checkGroundedBackfill(config) },
  ];

  console.log("");
  console.log("═══════════════════════════════════════");
  console.log("  PR-C: Deprecation Warning Check");
  console.log(`  Architecture Freeze: 2026-06-04`);
  console.log(`  ${new Date().toISOString()}`);
  console.log("═══════════════════════════════════════");
  console.log("");

  for (const check of checks) {
    try {
      const warnings = check.fn();
      checkResults.push({ name: check.name, warnings, passed: warnings.length === 0 });
      allWarnings.push(...warnings);
    } catch (e) {
      checkResults.push({ name: check.name, warnings: [], passed: false, error: e.message });
    }
  }

  // Emit warnings (deduplicated)
  if (allWarnings.length > 0) {
    console.log("  ⚠ Deprecation warnings found:\n");
    for (const w of allWarnings) {
      warnOnce(w.key, w.message);
    }
  } else {
    console.log("  ✓ No deprecation warnings found.");
  }

  // Summary
  console.log("");
  const checksWithWarnings = checkResults.filter(c => c.warnings.length > 0);
  const checksFailed = checkResults.filter(c => c.error);
  
  console.log(`  Checks run:      ${checks.length}`);
  console.log(`  With warnings:   ${checksWithWarnings.length}`);
  console.log(`  Total warnings:  ${allWarnings.length}`);
  
  if (checksFailed.length > 0) {
    console.log(`  Check errors:    ${checksFailed.length}`);
    for (const c of checksFailed) {
      console.log(`    ⚠ ${c.name}: ${c.error}`);
    }
  }

  // ─── PR-1 Enhanced Output: Legacy Table ─────────────
  if (allWarnings.length > 0) {
    const legacyRows = formatLegacyTable(allWarnings);
    
    console.log("");
    console.log("  ─────────────────────────────────────────────");
    console.log("  Deprecated Modules (PR-1 Legacy Inventory):");
    console.log("  ─────────────────────────────────────────────");
    console.log("");
    
    for (const row of legacyRows) {
      console.log(`  Module:            ${row.module}`);
      console.log(`  Status:            ${row.status}`);
      console.log(`  Replacement:       ${row.replacement}`);
      console.log(`  Migration Window:  ${row.migrationWindow}`);
      console.log(`  Removal Target:    ${row.removalTarget}`);
      console.log("");
    }
    
    // Migration timeline
    console.log("  ─────────────────────────────────────────────");
    console.log("  Migration Timeline:");
    console.log("");
    console.log("  Day 0     2026-06-04   Freeze active");
    console.log("  Day 30    2026-07-04   Legacy warnings active");
    console.log("  Day 60    2026-08-04   Honcho/LanceDB read-only cutoff");
    console.log("  Day 90    2026-09-04   All legacy modules removed");
    console.log("");
    
    // Per-module key list for scripting
    console.log("  Deprecated keys:");
    for (const w of allWarnings) {
      const info = LEGACY_REGISTRY[w.key];
      const target = info ? info.removalTarget : "N/A";
      console.log(`    • ${w.key} (removal: ${target})`);
    }
  }

  console.log("");
  return { warnings: allWarnings, results: checkResults };
}

// Run if called as main
if (process.argv[1]?.includes("check-deprecations")) {
  const result = runAllChecks();
  process.exit(0); // Never fail on deprecation warnings
}

export { runAllChecks, loadConfig, LEGACY_REGISTRY, getLegacyInfo, formatLegacyTable, 
  checkActiveMemoryBlocking, checkDreamingRemPhase, checkDreamDiary,
  checkQmdReference, checkHonchoLanceDB, checkMemoryWiki, 
  checkCommitmentsAutoInfer, checkGroundedBackfill };
