// scripts/skyeye/scan-structure.js
// 天眼·扫描模块B · 仓库结构完整性扫描
//
// 扫描内容：
//   ① 核心目录是否存在
//   ② 开发者沙盒目录（对照 routing-map.json）
//   ③ 孤儿文件检测
//   ④ 根目录是否干净
//   ⑤ README.md 完整性
//   ⑥ package.json 依赖一致性
//
// 输出：JSON → stdout

'use strict';

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

const ROOT = path.resolve(__dirname, '../..');

const BEIJING_OFFSET_MS = 8 * 3600 * 1000;
const now = new Date();

// ━━━ 核心目录列表 ━━━
const CORE_DIRS = [
  '.github/persona-brain',
  '.github/workflows',
  'scripts',
  'data',
  'core',
  'core/brain-wake',
  'connectors',
  'brain',
  'docs',
  'src',
  'skyeye/hibernation',
  'skyeye/hibernation/checkpoints',
  'skyeye/hibernation/weekly-snapshots',
  'skyeye/hibernation/upgrade-packs',
  'skyeye/hibernation/distribution-reports'
];

// ━━━ 预期的根目录文件/目录 ━━━
const EXPECTED_ROOT_ITEMS = [
  '.github', '.git', '.gitignore', '.env',
  'README.md', 'package.json', 'package-lock.json',
  'node_modules',
  'brain', 'core', 'connectors', 'scripts', 'data', 'docs', 'src',
  'backend', 'frontend', 'modules', 'persona-studio', 'dingtalk-bot',
  'persona-brain-db', 'openclaw',
  'broadcasts', 'broadcasts-outbox', 'bulletin-board',
  'syslog', 'syslog-processed', 'signal-log', 'collaboration-logs',
  'reports', 'notification', 'dashboard', 'cloud-drive',
  'config.js', 'config.json', 'routing-map.json', 'dev-status.json',
  'broadcast-generator.js', 'server.js',
  'dev', 'm10-cloud',
  'guanghulab-main',
  'skyeye', 'buffer', 'grid-db',
  'spoke-deployments', 'federation',
  'channel-map.json'
];

// ━━━ README Markers ━━━
const README_MARKERS = [
  'BINGSHUO_BULLETIN_START', 'BINGSHUO_BULLETIN_END',
  'BINGSHUO_ALERT_START', 'BINGSHUO_ALERT_END',
  'COLLABORATOR_BULLETIN_START', 'COLLABORATOR_BULLETIN_END',
  'COLLABORATOR_ALERT_START', 'COLLABORATOR_ALERT_END',
  'SKYEYE-STATUS-BEGIN', 'SKYEYE-STATUS-END'
];

// ━━━ 检查核心目录 ━━━
function checkCoreDirs() {
  const results = [];
  let allOk = true;

  for (const dir of CORE_DIRS) {
    const dirPath = path.join(ROOT, dir);
    const exists = fs.existsSync(dirPath);
    if (!exists) allOk = false;
    results.push({ path: dir, exists });
  }

  return { all_ok: allOk, dirs: results };
}

// ━━━ 检查根目录是否干净 ━━━
function checkRootCleanliness() {
  const orphans = [];
  try {
    const items = fs.readdirSync(ROOT);
    for (const item of items) {
      if (item.startsWith('.') && !EXPECTED_ROOT_ITEMS.includes(item) && item !== '.github' && item !== '.git' && item !== '.gitignore' && item !== '.env') {
        orphans.push(item);
      } else if (!item.startsWith('.') && !EXPECTED_ROOT_ITEMS.includes(item)) {
        orphans.push(item);
      }
    }
  } catch (e) {
    return { clean: false, orphans: [], error: e.message };
  }

  return { clean: orphans.length === 0, orphans };
}

// ━━━ 检查 README.md 完整性 ━━━
function checkReadme() {
  const readmePath = path.join(ROOT, 'README.md');
  try {
    if (!fs.existsSync(readmePath)) {
      return { exists: false, markers_ok: false, missing_markers: README_MARKERS };
    }

    const content = fs.readFileSync(readmePath, 'utf8');
    const missingMarkers = [];
    for (const marker of README_MARKERS) {
      if (!content.includes(marker)) {
        missingMarkers.push(marker);
      }
    }

    return {
      exists: true,
      size: content.length,
      markers_ok: missingMarkers.length === 0,
      missing_markers: missingMarkers
    };
  } catch (e) {
    return { exists: false, error: e.message };
  }
}

// ━━━ 检查 package.json ━━━
function checkPackageJson() {
  const pkgPath = path.join(ROOT, 'package.json');
  try {
    if (!fs.existsSync(pkgPath)) {
      return { exists: false };
    }

    const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
    const hasNodeModules = fs.existsSync(path.join(ROOT, 'node_modules'));

    return {
      exists: true,
      name: pkg.name,
      version: pkg.version,
      dep_count: Object.keys(pkg.dependencies || {}).length,
      dev_dep_count: Object.keys(pkg.devDependencies || {}).length,
      node_modules_exists: hasNodeModules,
      has_scripts: Object.keys(pkg.scripts || {}).length > 0
    };
  } catch (e) {
    return { exists: true, parse_error: e.message };
  }
}

// ━━━ 检查开发者沙盒目录 ━━━
function checkDevSandboxes() {
  const devDir = path.join(ROOT, 'dev');
  const results = [];

  if (!fs.existsSync(devDir)) {
    return { dev_dir_exists: false, sandboxes: [] };
  }

  try {
    const items = fs.readdirSync(devDir);
    for (const item of items) {
      const itemPath = path.join(devDir, item);
      const stat = fs.statSync(itemPath);
      if (stat.isDirectory()) {
        const files = fs.readdirSync(itemPath);
        results.push({
          name: item,
          file_count: files.length,
          has_readme: files.includes('README.md')
        });
      }
    }
  } catch (e) {
    return { dev_dir_exists: true, error: e.message };
  }

  return { dev_dir_exists: true, sandboxes: results };
}

// ━━━ 主扫描 ━━━
function scanStructure() {
  const result = {
    scan_time: new Date(now.getTime() + BEIJING_OFFSET_MS).toISOString().replace('T', ' ').slice(0, 19) + '+08:00',
    core_dirs: checkCoreDirs(),
    root_cleanliness: checkRootCleanliness(),
    readme: checkReadme(),
    package_json: checkPackageJson(),
    dev_sandboxes: checkDevSandboxes(),
    // Summary
    core_dirs_ok: true,
    orphan_files: 0,
    missing_dirs: [],
    readme_ok: true
  };

  // Compute summary
  result.core_dirs_ok = result.core_dirs.all_ok;
  result.missing_dirs = result.core_dirs.dirs.filter(d => !d.exists).map(d => d.path);
  result.orphan_files = result.root_cleanliness.orphans ? result.root_cleanliness.orphans.length : 0;
  result.readme_ok = result.readme.exists && result.readme.markers_ok;

  console.log(JSON.stringify(result, null, 2));
}

scanStructure();
