/**
 * ============================================================================
 * MyClaw — delete_agents 核心模块
 * ============================================================================
 *
 * 提供 Agent 批量删除的底层能力，被以下两处复用：
 *   1. CLI：mc delete  (交互式批量删除)
 *   2. API：sync_workspace.py  /api/agents  /api/agents/trash
 *
 * 导出：
 *   listAllAgents()          → 取 JSON注册 ∪ agents文件夹 的并集，附统计信息
 *   trashPath(p)             → 跨平台移入回收站（macOS/Windows/Linux）
 *   deleteRegisteredAgent(id)→ 调用 openclaw agents delete --force
 *   deleteOrphanAgent(ag)    → 对孤立 agent 的所有路径执行 trashPath
 * ============================================================================
 */

'use strict';

const fs   = require('fs');
const path = require('path');
const os   = require('os');
const { spawnSync, execSync } = require('child_process');

// ─────────────────────────────────────────────
// 路径工具
// ─────────────────────────────────────────────

function getOpenclawDir() {
  if (process.platform === 'win32' || fs.existsSync('/root/.openclaw')) {
    return '/root/.openclaw';
  }
  return path.join(os.homedir(), '.openclaw');
}

// ─────────────────────────────────────────────
// listAllAgents
// ─────────────────────────────────────────────

/**
 * 返回所有 Agent 的信息列表（JSON注册表 ∪ agents文件夹）。
 *
 * @returns {Array<{
 *   id: string,
 *   inJson: boolean,       — 是否在 openclaw.json 里注册
 *   inFolder: boolean,     — agents/ 目录下是否有对应文件夹
 *   workspace: string,     — workspace 目录绝对路径
 *   agentDir: string,      — agent 配置目录（含 auth-profiles.json）
 *   sessionsDir: string,   — 会话记录目录
 *   sessionCount: number,  — .jsonl 会话文件数量
 *   lastUpdated: number|null — 最近会话 mtime（毫秒时间戳）
 * }>}
 */
function listAllAgents() {
  const base       = getOpenclawDir();
  const configPath = path.join(base, 'openclaw.json');
  const agentsDir  = path.join(base, 'agents');

  // ── 1. 读取 JSON 注册的 agent ──
  const jsonAgents = {};
  try {
    const cfg = JSON.parse(fs.readFileSync(configPath, 'utf8'));
    for (const entry of ((cfg.agents || {}).list || [])) {
      if (entry && entry.id) {
        jsonAgents[entry.id] = {
          workspace: entry.workspace || '',
          agentDir:  entry.agentDir  || '',
        };
      }
    }
  } catch (_) {}

  // ── 2. 扫描 agents/ 文件夹 ──
  const folderIds = new Set();
  try {
    if (fs.existsSync(agentsDir)) {
      for (const name of fs.readdirSync(agentsDir)) {
        if (fs.statSync(path.join(agentsDir, name)).isDirectory()) {
          folderIds.add(name);
        }
      }
    }
  } catch (_) {}

  // ── 3. 合并并集 ──
  const allIds = [...new Set([...Object.keys(jsonAgents), ...folderIds])].sort();
  const result = [];

  for (const id of allIds) {
    const inJson   = id in jsonAgents;
    const inFolder = folderIds.has(id);

    const workspace  = inJson ? jsonAgents[id].workspace : path.join(base, 'workspace-' + id);
    const agentDir   = inJson ? jsonAgents[id].agentDir  : path.join(agentsDir, id, 'agent');
    const sessionsDir = path.join(agentsDir, id, 'sessions');

    // ── 统计会话 ──
    let sessionCount = 0;
    let lastUpdated  = null;

    try {
      if (fs.existsSync(sessionsDir)) {
        const files = fs.readdirSync(sessionsDir).filter(f => f.endsWith('.jsonl'));
        sessionCount = files.length;
        const mtimes = files
          .map(f => { try { return fs.statSync(path.join(sessionsDir, f)).mtimeMs; } catch (_) { return 0; } })
          .filter(Boolean);
        if (mtimes.length > 0) lastUpdated = Math.max(...mtimes);
      }
    } catch (_) {}

    // fallback：用目录 mtime
    if (lastUpdated === null) {
      try {
        const dir = fs.existsSync(workspace) ? workspace : path.join(agentsDir, id);
        if (fs.existsSync(dir)) lastUpdated = fs.statSync(dir).mtimeMs;
      } catch (_) {}
    }

    result.push({ id, inJson, inFolder, workspace, agentDir, sessionsDir, sessionCount, lastUpdated });
  }

  // 按最后更新时间降序（最新在前），null 排最后
  result.sort((a, b) => {
    if (a.lastUpdated === null && b.lastUpdated === null) return 0;
    if (a.lastUpdated === null) return 1;
    if (b.lastUpdated === null) return -1;
    return b.lastUpdated - a.lastUpdated;
  });

  return result;
}

// ─────────────────────────────────────────────
// trashPath — 跨平台移入回收站
// ─────────────────────────────────────────────

/**
 * 将指定路径移入系统回收站。
 *
 * @param {string} p - 要删除的文件/目录路径
 * @returns {{ ok: boolean, dest?: string, method?: string, note?: string, error?: string }}
 */
function trashPath(p) {
  if (!p || typeof p !== 'string') return { ok: false, error: '路径无效' };
  p = path.normalize(p);
  if (!fs.existsSync(p)) return { ok: true, note: '路径不存在，跳过' };

  try {
    const plat = process.platform;

    // ── macOS ──
    if (plat === 'darwin') {
      const trashDir = path.join(os.homedir(), '.Trash');
      const base     = path.basename(p);
      let dest       = path.join(trashDir, base);
      if (fs.existsSync(dest)) dest = path.join(trashDir, base + '.' + Date.now());
      fs.renameSync(p, dest);
      return { ok: true, dest };
    }

    // ── Windows ──
    if (plat === 'win32') {
      // 文件用 DeleteFile，目录用 DeleteDirectory
      const isDir = fs.statSync(p).isDirectory();
      const safePath = p.replace(/'/g, '');
      const method   = isDir ? 'DeleteDirectory' : 'DeleteFile';
      const extraArgs = isDir
        ? `'${safePath}', 'OnlyErrorDialogs', 'SendToRecycleBin'`
        : `'${safePath}', 'OnlyErrorDialogs', 'SendToRecycleBin'`;
      const psCmd = `Add-Type -AssemblyName Microsoft.VisualBasic; [Microsoft.VisualBasic.FileIO.FileSystem]::${method}(${extraArgs})`;
      const ret   = spawnSync('powershell', ['-NoProfile', '-Command', psCmd], { timeout: 15000 });
      if (ret.status === 0) return { ok: true, method: 'powershell' };
      return { ok: false, error: (ret.stderr || Buffer.alloc(0)).toString().trim() };
    }

    // ── Linux ──
    for (const cmd of [['gio', 'trash', p], ['trash-put', p]]) {
      const ret = spawnSync(cmd[0], cmd.slice(1), { timeout: 10000 });
      if (ret.status === 0) return { ok: true, method: cmd[0] };
      if (ret.error && ret.error.code === 'ENOENT') continue; // 命令不存在
    }
    // 兜底：直接删除并告知用户
    fs.rmSync(p, { recursive: true, force: true });
    return { ok: true, method: 'rm', note: '未找到回收站工具（gio/trash-put），已直接删除' };

  } catch (e) {
    return { ok: false, error: e.message };
  }
}

// ─────────────────────────────────────────────
// deleteRegisteredAgent — 删除已在 JSON 注册的 agent
// ─────────────────────────────────────────────

/**
 * 调用 openclaw agents delete --force 删除已注册的 agent。
 * 会同时清理 JSON 条目、workspace 和 agentDir。
 *
 * @param {string} id
 * @returns {{ ok: boolean, error?: string }}
 */
function deleteRegisteredAgent(id) {
  try {
    execSync('openclaw agents delete ' + id + ' --force', {
      stdio: 'pipe',
      timeout: 30000,
    });
    return { ok: true };
  } catch (e) {
    const stderr = e.stderr ? e.stderr.toString().trim() : e.message;
    return { ok: false, error: stderr };
  }
}

// ─────────────────────────────────────────────
// deleteOrphanAgent — 删除孤立 agent（仅有文件夹）
// ─────────────────────────────────────────────

/**
 * 阶段1：对孤立 agent 模拟官方最小删除行为。
 * 依次 trash：workspace 目录、agents/xxx/agent/ 子目录（不含 sessions）。
 *
 * @param {{ id: string, workspace: string }} ag
 * @returns {{ ok: boolean, results: Array }}
 */
function deleteOrphanAgent(ag) {
  const base       = getOpenclawDir();
  const agentSubdir = path.join(base, 'agents', ag.id, 'agent'); // 只删 agent/ 子目录

  const targets = [ag.workspace, agentSubdir].filter(Boolean);
  const results = targets.map(p => ({ path: p, ...trashPath(p) }));
  const ok      = results.every(r => r.ok);
  return { ok, results };
}

// ─────────────────────────────────────────────
// cleanAgentDirs — 阶段2：清理 agents/<id>/ 整个目录（含 sessions）
// ─────────────────────────────────────────────

/**
 * 阶段2：清理 agents/<id>/ 整个目录（含 sessions/）。
 * 对注册 agent 和孤立 agent 均适用：
 *   - 注册 agent：openclaw delete 已清理 agent/ 子目录，此步清理 sessions/ 残余
 *   - 孤立 agent：deleteOrphanAgent 已清理 agent/ 子目录，此步清理 sessions/ 残余
 *
 * @param {string} id
 * @returns {{ ok: boolean, results: Array }}
 */
function cleanAgentDirs(id) {
  const base      = getOpenclawDir();
  const agentRoot = path.join(base, 'agents', id);
  const res       = trashPath(agentRoot);
  return { ok: res.ok, results: [{ path: agentRoot, ...res }] };
}

// ─────────────────────────────────────────────
// module.exports
// ─────────────────────────────────────────────

module.exports = {
  listAllAgents,
  trashPath,
  deleteRegisteredAgent,
  deleteOrphanAgent,
  cleanAgentDirs,
  getOpenclawDir,
};
