/**
 * robot-manager 权限审计脚本
 *
 * 静态检查：
 * 1. Controller 里所有 @RequirePermissions('robot-manager:xxx') 的 action
 * 2. 种子文件 ROBOT_PERMISSIONS 里定义的 action
 * 3. 对比找出：
 *    - ❌ "被使用但未定义"（后端报 500 的隐形坑）
 *    - ⚠️ "已定义但无任何角色拥有"（除 Admin bypass 外所有人都会被拒）
 *    - ℹ️ "已定义但未被使用"（冗余，可清理）
 *
 * 用法：
 *   npx ts-node --transpile-only testing/scripts/robot-manager-permission-audit.ts
 */

/* eslint-disable @typescript-eslint/no-var-requires */
const fs = require('fs') as typeof import('fs');
const path = require('path') as typeof import('path');

const ROOT = path.resolve(__dirname, '..', '..');
const CONTROLLERS_DIR = path.join(ROOT, 'backend/src/modules/robot-manager');
const SEED_FILE = path.join(ROOT, 'backend/prisma/seeds/robot-manager-e2e-seed.ts');

const MODULE_RESOURCE = 'robot-manager';

interface UsageSite {
  action: string;
  file: string;
  line: number;
}

// ------------------- 1. 扫 @RequirePermissions -------------------
function scanUsedActions(): UsageSite[] {
  const results: UsageSite[] = [];
  const walk = (dir: string) => {
    for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
      const full = path.join(dir, entry.name);
      if (entry.isDirectory()) walk(full);
      else if (entry.name.endsWith('.ts')) {
        const lines = fs.readFileSync(full, 'utf-8').split('\n');
        lines.forEach((line, i) => {
          const m = line.match(new RegExp(`@RequirePermissions\\(\\s*['"]${MODULE_RESOURCE}:([^'"\\s]+)['"]`));
          if (m) {
            results.push({ action: m[1], file: path.relative(ROOT, full), line: i + 1 });
          }
        });
      }
    }
  };
  walk(CONTROLLERS_DIR);
  return results;
}

// ------------------- 2. 从种子提取 ROBOT_PERMISSIONS -------------------
function parseDefinedActions(): Set<string> {
  const content = fs.readFileSync(SEED_FILE, 'utf-8');
  const defined = new Set<string>();
  // 匹配 { resource: 'robot-manager', action: 'xxx' }
  const re = /\{\s*resource:\s*['"]robot-manager['"]\s*,\s*action:\s*['"]([^'"]+)['"]/g;
  let m;
  while ((m = re.exec(content)) !== null) {
    defined.add(m[1]);
  }
  return defined;
}

// ------------------- 3. 解析每个 role 的 permissionKeys -------------------
interface RoleSnapshot {
  code: string;
  actions: Set<string>;
}
function parseRoles(): RoleSnapshot[] {
  const content = fs.readFileSync(SEED_FILE, 'utf-8');
  const roles: RoleSnapshot[] = [];
  const re = /\{\s*code:\s*['"]([^'"]+)['"][\s\S]*?permissionKeys:\s*(?:\[([\s\S]*?)\]|ROBOT_PERMISSIONS\.map[\s\S]*?)[,\s]/g;
  let m;
  while ((m = re.exec(content)) !== null) {
    const code = m[1];
    const arrBody = m[2];
    const actions = new Set<string>();
    if (arrBody) {
      const ar = /['"]robot-manager:([^'"]+)['"]/g;
      let a;
      while ((a = ar.exec(arrBody)) !== null) actions.add(a[1]);
    } else {
      // permissionKeys: ROBOT_PERMISSIONS.map(...) —— 拥有所有已定义的 action
      actions.add('__ALL__');
    }
    roles.push({ code, actions });
  }
  return roles;
}

// ------------------- 4. 报告 -------------------
function main() {
  const used = scanUsedActions();
  const defined = parseDefinedActions();
  const roles = parseRoles();

  const usedActions = new Set(used.map((u) => u.action));

  const missing = [...usedActions].filter((a) => !defined.has(a));
  const unused = [...defined].filter((a) => !usedActions.has(a));

  // 每个权限至少一个角色拥有？
  const coveredByRole = new Set<string>();
  for (const r of roles) {
    if (r.actions.has('__ALL__')) {
      for (const a of defined) coveredByRole.add(a);
    } else {
      for (const a of r.actions) coveredByRole.add(a);
    }
  }
  const noRoleHolds = [...defined].filter((a) => !coveredByRole.has(a));

  let hasError = false;
  console.log('\n=== robot-manager 权限审计报告 ===\n');

  console.log(`📊 统计：${used.length} 处装饰器使用、${defined.size} 个权限定义、${roles.length} 个角色\n`);

  if (missing.length > 0) {
    hasError = true;
    console.log('❌ 被装饰器使用但种子未定义的 action（生产环境会导致 403）：');
    for (const a of missing) {
      const sites = used.filter((u) => u.action === a);
      console.log(`   - ${MODULE_RESOURCE}:${a}`);
      for (const s of sites) console.log(`       at ${s.file}:${s.line}`);
    }
    console.log();
  }

  if (noRoleHolds.length > 0) {
    hasError = true;
    console.log('⚠️  已定义但无任何角色拥有（除 Admin bypass 外所有人都被拒）：');
    for (const a of noRoleHolds) console.log(`   - ${MODULE_RESOURCE}:${a}`);
    console.log();
  }

  if (unused.length > 0) {
    console.log('ℹ️  已定义但装饰器未使用（可能冗余）：');
    for (const a of unused) console.log(`   - ${MODULE_RESOURCE}:${a}`);
    console.log();
  }

  if (!hasError) {
    console.log('✅ 权限定义与使用完全一致\n');
  }

  console.log('--- 角色权限一览 ---');
  for (const r of roles) {
    const acts = r.actions.has('__ALL__') ? `<all ${defined.size} permissions>` : [...r.actions].sort().join(', ');
    console.log(`  ${r.code}: ${acts}`);
  }
  console.log();

  process.exit(hasError ? 1 : 0);
}

main();
