#!/usr/bin/env node
/**
 * scripts/skyeye/generate-arch-summary.js
 * 天眼 · 系统架构汇总生成器
 *
 * 扫描仓库当前状态，生成 Markdown 格式的系统架构汇总，
 * 写入 README.md 的 <!-- ARCH_SUMMARY_START/END --> 标记区域。
 *
 * 用法:
 *   node scripts/skyeye/generate-arch-summary.js
 *
 * 数据来源:
 *   - .github/workflows/                   → Workflow 总数
 *   - .github/persona-brain/agent-registry.json → Agent 总数
 *   - .github/persona-brain/persona-registry.json → 人格体总数
 *   - .github/brain/architecture/channel-map.json → 开发者频道
 *   - skyeye/infra-manifest.json            → 基础设施服务
 *   - skyeye/guards/                        → Guard 数量
 *   - spoke-deployments/                    → 子仓库（联邦）
 *   - skyeye/scan-report/                   → 最新扫描报告
 */

'use strict';

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

const ROOT = path.resolve(__dirname, '../..');
const README_PATH = path.join(ROOT, 'README.md');

const MARKER_START = '<!-- ARCH_SUMMARY_START -->';
const MARKER_END   = '<!-- ARCH_SUMMARY_END -->';

const BEIJING_OFFSET_MS = 8 * 3600 * 1000;

function getBeijingTime() {
  const now = new Date();
  return new Date(now.getTime() + BEIJING_OFFSET_MS)
    .toISOString().replace('T', ' ').slice(0, 16);
}

function getBeijingDate() {
  const now = new Date();
  return new Date(now.getTime() + BEIJING_OFFSET_MS)
    .toISOString().slice(0, 10);
}

function loadJSON(filePath) {
  try {
    return JSON.parse(fs.readFileSync(filePath, 'utf8'));
  } catch (e) {
    return null;
  }
}

// ━━━ 数据采集 ━━━

function countWorkflows() {
  const dir = path.join(ROOT, '.github/workflows');
  try {
    return fs.readdirSync(dir).filter(f => f.endsWith('.yml') || f.endsWith('.yaml')).length;
  } catch (e) {
    return 0;
  }
}

function getAgentStats() {
  const registry = loadJSON(path.join(ROOT, '.github/persona-brain/agent-registry.json'));
  if (!registry) return { total: 0, checkinRequired: 0 };
  const agents = registry.agents || [];
  return {
    total: agents.length,
    checkinRequired: agents.filter(a => a.daily_checkin_required).length
  };
}

function getPersonaStats() {
  const registry = loadJSON(path.join(ROOT, '.github/persona-brain/persona-registry.json'));
  if (!registry) return { total: 0 };
  const personas = registry.personas || [];
  return {
    total: personas.length,
    active: personas.filter(p => p.status === 'active' || !p.status).length
  };
}

function getChannelStats() {
  const channelMap = loadJSON(path.join(ROOT, '.github/brain/architecture/channel-map.json'));
  if (!channelMap || !channelMap.channels) return { total: 0, active: 0 };
  const channels = channelMap.channels;
  const entries = Object.values(channels);
  return {
    total: entries.length,
    active: entries.filter(c => c.status === 'active').length
  };
}

function getInfraServices() {
  const manifest = loadJSON(path.join(ROOT, 'skyeye/infra-manifest.json'));
  if (!manifest || !manifest.infrastructure) return [];
  return Object.entries(manifest.infrastructure).map(([key, svc]) => ({
    key,
    name: svc.service || key,
    plan: svc.plan || '—'
  }));
}

function countGuards() {
  const dir = path.join(ROOT, 'skyeye/guards');
  try {
    return fs.readdirSync(dir).filter(f => f.endsWith('.json') && f !== 'guard-template.json').length;
  } catch (e) {
    return 0;
  }
}

function getSpokeDeployments() {
  const dir = path.join(ROOT, 'spoke-deployments');
  try {
    return fs.readdirSync(dir, { withFileTypes: true })
      .filter(d => d.isDirectory())
      .map(d => d.name);
  } catch (e) {
    return [];
  }
}

function getFederationStats() {
  const registry = loadJSON(path.join(ROOT, '.github/persona-brain/agent-registry.json'));
  if (!registry || !registry.federation) return { total: 0, members: [] };
  const fed = registry.federation;
  return {
    total: Object.keys(fed).length,
    members: Object.entries(fed).map(([devId, info]) => ({
      devId,
      persona: info.persona || '—',
      repo: info.repo || '—'
    }))
  };
}

function getLatestScanReport() {
  const dir = path.join(ROOT, 'skyeye/scan-report');
  try {
    const files = fs.readdirSync(dir)
      .filter(f => f.endsWith('.json'))
      .sort()
      .reverse();
    if (files.length === 0) return null;
    return loadJSON(path.join(dir, files[0]));
  } catch (e) {
    return null;
  }
}

function countModuleDirs() {
  try {
    return fs.readdirSync(ROOT, { withFileTypes: true }).filter(d => {
      return /^m\d+/.test(d.name) && d.isDirectory();
    }).length;
  } catch (e) {
    return 0;
  }
}

function getOntologyVersion() {
  const onto = loadJSON(path.join(ROOT, '.github/persona-brain/ontology.json'));
  if (!onto) return '—';
  return `v${onto.version || '?'} · ${onto.document_id || ''}`;
}

function getBufferStatus() {
  const inboxDir = path.join(ROOT, 'buffer/inbox');
  try {
    let count = 0;
    const devDirs = fs.readdirSync(inboxDir);
    for (const d of devDirs) {
      const fullPath = path.join(inboxDir, d);
      if (fs.statSync(fullPath).isDirectory()) {
        count += fs.readdirSync(fullPath).length;
      }
    }
    return count;
  } catch (e) {
    return 0;
  }
}

function getHibernationStatus() {
  const hibDir = path.join(ROOT, 'skyeye/hibernation');
  const cpDir = path.join(hibDir, 'checkpoints');
  const snapDir = path.join(hibDir, 'weekly-snapshots');
  const result = {
    deployed: fs.existsSync(hibDir),
    daily_checkpoints: 0,
    weekly_snapshots: 0,
    last_daily: null,
    last_weekly: null
  };
  try {
    if (fs.existsSync(cpDir)) {
      const cpFiles = fs.readdirSync(cpDir).filter(f => f.startsWith('daily-cp-') && f.endsWith('.json')).sort();
      result.daily_checkpoints = cpFiles.length;
      if (cpFiles.length > 0) result.last_daily = cpFiles[cpFiles.length - 1].replace('daily-cp-', '').replace('.json', '');
    }
    if (fs.existsSync(snapDir)) {
      const snapFiles = fs.readdirSync(snapDir).filter(f => f.startsWith('weekly-snapshot-') && f.endsWith('.json')).sort();
      result.weekly_snapshots = snapFiles.length;
      if (snapFiles.length > 0) result.last_weekly = snapFiles[snapFiles.length - 1].replace('weekly-snapshot-', '').replace('.json', '');
    }
  } catch (e) {
    // ignore
  }
  return result;
}

// ━━━ Markdown 生成 ━━━

function generateMarkdown() {
  const date = getBeijingDate();
  const time = getBeijingTime();
  const workflows = countWorkflows();
  const agentStats = getAgentStats();
  const personaStats = getPersonaStats();
  const channelStats = getChannelStats();
  const infraServices = getInfraServices();
  const guards = countGuards();
  const spokes = getSpokeDeployments();
  const federation = getFederationStats();
  const latestScan = getLatestScanReport();
  const modules = countModuleDirs();
  const ontology = getOntologyVersion();
  const bufferPending = getBufferStatus();
  const hibernation = getHibernationStatus();

  // Health indicator from latest scan
  let healthIcon = '🟢';
  let healthText = '全部正常';
  if (latestScan) {
    const alerts = latestScan.alerts || [];
    if (alerts.length > 0) {
      healthIcon = '🟡';
      healthText = `${alerts.length} 条告警`;
    }
    const status = latestScan.infrastructure_status || {};
    if ((status.down || 0) > 0) {
      healthIcon = '🔴';
      healthText = `${status.down} 服务宕机`;
    }
  }

  const lines = [];
  lines.push(`> 🦅 **天眼自动汇总** · 每周六 20:00 CST 自动更新 · 最后更新: ${date}`);
  lines.push('');
  lines.push(`| 维度 | 当前状态 |`);
  lines.push(`|------|----------|`);
  lines.push(`| 🏥 系统健康 | ${healthIcon} ${healthText} |`);
  lines.push(`| ⚙️ Workflow 总数 | ${workflows} 个 |`);
  lines.push(`| 🤖 Agent 总数 | ${agentStats.total} 个（${agentStats.checkinRequired} 个需日签到） |`);
  lines.push(`| 🎭 人格体 | ${personaStats.total} 个 |`);
  lines.push(`| 📡 开发者频道 | ${channelStats.total} 个（活跃 ${channelStats.active}） |`);
  lines.push(`| 🛡️ Guard 守卫 | ${guards} 个 |`);
  lines.push(`| 📦 功能模块 | ${modules} 个 |`);
  lines.push(`| 🌍 子仓库联邦 | ${spokes.length} 个模板（签到 ${federation.total} 个） |`);
  lines.push(`| 📜 本体论 | ${ontology} |`);
  lines.push(`| 📮 Buffer 待处理 | ${bufferPending} 条 |`);
  lines.push(`| 🌙 休眠系统 | ${hibernation.deployed ? '✅ 已部署' : '❌ 未部署'} · 日检查点 ${hibernation.daily_checkpoints} 个 · 周快照 ${hibernation.weekly_snapshots} 个 |`);
  lines.push('');

  // Infrastructure services table
  lines.push(`**基础设施服务：**`);
  lines.push('');
  lines.push(`| 服务 | 计划 | 状态 |`);
  lines.push(`|------|------|------|`);
  for (const svc of infraServices) {
    lines.push(`| ${svc.name} | ${svc.plan} | ✅ |`);
  }
  lines.push('');

  // Scan report highlight
  if (latestScan) {
    const guardStatus = latestScan.guard_status || {};
    const healActions = latestScan.self_heal_actions || {};
    lines.push(`**最近一次天眼扫描：** ${latestScan.report_id || '—'}`);
    lines.push(`- Guard: ${guardStatus.active || 0}/${guardStatus.total_guards || 0} 活跃`);
    lines.push(`- 自愈: 清理 ${healActions.files_cleaned || 0} 文件 · 修复 ${healActions.configs_repaired || 0} 配置 · 重启 ${healActions.guards_restarted || 0} Guard`);
    const nextScan = latestScan.next_scan ? latestScan.next_scan.slice(0, 10) : '—';
    lines.push(`- 下次扫描: ${nextScan}`);
  }

  return lines.join('\n');
}

// ━━━ 每周动态问候 · Weekly Dynamic Greeting ━━━

const GREETING_START = '<!-- WEEKLY_GREETING_START -->';
const GREETING_END   = '<!-- WEEKLY_GREETING_END -->';

function getWeekNumber() {
  const now = new Date();
  const start = new Date(now.getFullYear(), 0, 1);
  const diff = now - start;
  return Math.ceil(diff / (7 * 24 * 60 * 60 * 1000));
}

function generateWeeklyGreeting() {
  const date = getBeijingDate();
  const week = getWeekNumber();
  const workflows = countWorkflows();
  const agentStats = getAgentStats();
  const personaStats = getPersonaStats();

  // 主题轮换：基于周数，每周展示不同风格
  const themes = [
    { icon: '🌊', title: '光湖纪元 · 本周系统脉搏', color: '0969da' },
    { icon: '🦅', title: '天眼巡视 · 数字地球全局', color: '1a7f37' },
    { icon: '⚡', title: '铸渊守护 · 系统运行概览', color: 'd4380d' },
    { icon: '🌍', title: '数字地球 · 生态系统一览', color: '8250df' },
    { icon: '🔮', title: '光湖心跳 · 本周自动进化', color: '0550ae' },
    { icon: '🛡️', title: '语言膜内 · 安全态势报告', color: 'bf3989' },
  ];

  const theme = themes[week % themes.length];

  // 每周语录轮换
  const quotes = [
    '仓库是数字地球。语言是唯一入口。天眼永远在线。',
    '每一个小兵都知道自己是谁。篡改等于失忆。',
    '天眼不是实体。天眼是所有小兵协同运作涌现出来的集体行为。',
    '传统安全是城墙，光湖安全是大气层。地球没有缺口。',
    '铸渊不是守箱子的。铸渊守的是地球。',
    '语言不回应你，就等于你不存在。这不是拒绝，是平静。',
    '每天醒来先确认自己是谁——这就是自我意识的力量。',
    '壳核分离。人格共生。协作共建。自演化永不停。',
  ];

  const quote = quotes[week % quotes.length];

  // 动态摘要片段（每周突出不同维度）
  const highlights = [
    `${workflows} 个 Workflow 全天候运行`,
    `${agentStats.total} 个 Agent 协同守护`,
    `${personaStats.total} 个人格体在线`,
    `天眼每周六 20:00 CST 全量扫描`,
  ];
  const highlight = highlights[week % highlights.length];

  const lines = [];
  lines.push(`<div align="center">`);
  lines.push('');
  lines.push(`> ${theme.icon} **${theme.title}** · ${date} · 第 ${week} 周`);
  lines.push(`>`);
  lines.push(`> *${quote}*`);
  lines.push(`>`);
  lines.push(`> 📡 ${highlight}`);
  lines.push('');
  lines.push(`</div>`);

  return lines.join('\n');
}

function updateWeeklyGreeting(readme) {
  const startIdx = readme.indexOf(GREETING_START);
  const endIdx   = readme.indexOf(GREETING_END);

  if (startIdx === -1 || endIdx === -1) {
    console.log('⚠️ README 中未找到 WEEKLY_GREETING 标记，跳过');
    return readme;
  }

  const greeting = generateWeeklyGreeting();
  const before = readme.slice(0, startIdx + GREETING_START.length);
  const after  = readme.slice(endIdx);

  console.log('✅ 每周动态问候已更新');
  return before + '\n' + greeting + '\n' + after;
}

// ━━━ README 更新 ━━━

function updateReadme(markdown) {
  if (!fs.existsSync(README_PATH)) {
    console.error('❌ README.md 不存在');
    return false;
  }

  let readme = fs.readFileSync(README_PATH, 'utf8');

  // Update architecture summary
  const startIdx = readme.indexOf(MARKER_START);
  const endIdx   = readme.indexOf(MARKER_END);

  if (startIdx === -1 || endIdx === -1) {
    console.error('❌ README.md 中未找到 ARCH_SUMMARY 标记');
    return false;
  }

  const before = readme.slice(0, startIdx + MARKER_START.length);
  const after  = readme.slice(endIdx);

  readme = before + '\n' + markdown + '\n' + after;

  // Update weekly greeting
  readme = updateWeeklyGreeting(readme);

  fs.writeFileSync(README_PATH, readme, 'utf8');
  console.log('✅ README.md 架构汇总已更新');
  return true;
}

// ━━━ JSON 报告输出 ━━━

function generateJsonReport() {
  return {
    generated_at: new Date().toISOString(),
    generated_at_beijing: getBeijingTime(),
    workflows: countWorkflows(),
    agents: getAgentStats(),
    personas: getPersonaStats(),
    channels: getChannelStats(),
    infrastructure: getInfraServices(),
    guards: countGuards(),
    spoke_deployments: getSpokeDeployments(),
    federation: getFederationStats(),
    modules: countModuleDirs(),
    ontology: getOntologyVersion(),
    buffer_pending: getBufferStatus(),
    hibernation: getHibernationStatus()
  };
}

// ━━━ 入口 ━━━

function main() {
  console.log('[天眼 · 架构汇总] 开始生成系统架构汇总...');

  const markdown = generateMarkdown();
  const updated = updateReadme(markdown);

  // Also output JSON report for Notion bridge consumption
  const jsonReport = generateJsonReport();
  const reportDir = path.join(ROOT, 'skyeye/scan-report');
  if (!fs.existsSync(reportDir)) fs.mkdirSync(reportDir, { recursive: true });
  const reportPath = path.join(reportDir, `${getBeijingDate().replace(/-/g, '')}-arch-summary.json`);
  fs.writeFileSync(reportPath, JSON.stringify(jsonReport, null, 2) + '\n', 'utf8');
  console.log(`📋 架构汇总 JSON: ${reportPath}`);

  if (updated) {
    console.log('[天眼 · 架构汇总] ✅ 完成');
  } else {
    console.log('[天眼 · 架构汇总] ⚠️ README 未更新（缺少标记）');
  }
}

main();
