// scripts/skyeye/diagnose.js
// 天眼·诊断引擎
//
// 输入：/tmp/skyeye/ 下所有扫描结果
// 输出：诊断报告 JSON → stdout
//
// 关键逻辑：
//   汇总异常 → 根因分析 → 检测因果关系 → 生成修复计划
//   诊断要找根因，不要只看症状

'use strict';

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

const SKYEYE_DIR = '/tmp/skyeye';

// ━━━ 安全读取 JSON ━━━
function readScanResult(filename) {
  const filePath = path.join(SKYEYE_DIR, filename);
  try {
    if (!fs.existsSync(filePath)) return null;
    return JSON.parse(fs.readFileSync(filePath, 'utf8'));
  } catch (e) {
    console.error(`⚠️ 无法读取 ${filename}: ${e.message}`);
    return null;
  }
}

// ━━━ 问题分类器 ━━━
function classifyIssue(symptom, source) {
  // 根据症状判断可修复性和优先级
  const autoFixablePatterns = [
    { pattern: /routing.?map.*不一致|未映射/i, fix: 'update_routing_map', priority: 'P1' },
    { pattern: /dev.?status.*过期|超过.*24h/i, fix: 'trigger_sync', priority: 'P1' },
    { pattern: /memory.*过期|超过.*24h/i, fix: 'update_memory', priority: 'P1' },
    { pattern: /workflow.*失败|run_failure/i, fix: 'retry_workflow', priority: 'P1' },
    { pattern: /目录.*缺失|不存在/i, fix: 'create_directory', priority: 'P1' },
    { pattern: /孤儿文件/i, fix: 'log_orphans', priority: 'P2' },
    { pattern: /README.*marker|标记.*缺失/i, fix: 'repair_readme', priority: 'P1' },
    { pattern: /knowledge.?base.*重复/i, fix: 'deduplicate_kb', priority: 'P2' },
    { pattern: /copilot.*instructions.*空|不存在/i, fix: 'note_copilot', priority: 'P2' },
    { pattern: /syntax.*error|语法.*错误/i, fix: 'log_syntax_error', priority: 'P0' },
    { pattern: /cron.*conflict|冲突/i, fix: 'log_conflict', priority: 'P2' },
    { pattern: /hibernation.*checkpoint.*过期|checkpoint.*缺失/i, fix: 'trigger_daily_hibernation', priority: 'P1' },
    { pattern: /hibernation.*目录.*缺失/i, fix: 'create_directory', priority: 'P1' },
    { pattern: /upgrade.?pack.*缺失|升级包.*缺失/i, fix: 'trigger_weekly_hibernation', priority: 'P1' }
  ];

  const needsHumanPatterns = [
    { pattern: /Secret.*缺失|未设置|NOTION_TOKEN|SMTP|DEPLOY_KEY/i, reason: 'Secret 需管理员配置' },
    { pattern: /Notion.*API.*失败|权限/i, reason: 'Notion 集成需人工检查' },
    { pattern: /SSH.*不通|服务器.*连接/i, reason: '服务器访问需人工排查' },
    { pattern: /数据库.*结构/i, reason: 'Notion 数据库结构需人工修改' }
  ];

  // Check if auto-fixable
  for (const p of autoFixablePatterns) {
    if (p.pattern.test(symptom)) {
      return { fixable: true, fix_plan: p.fix, priority: p.priority };
    }
  }

  // Check if needs human
  for (const p of needsHumanPatterns) {
    if (p.pattern.test(symptom)) {
      return { fixable: false, fix_plan: 'needs_human', priority: 'P0', reason: p.reason };
    }
  }

  // Default: watch list
  return { fixable: false, fix_plan: 'watch', priority: 'P2' };
}

// ━━━ 根因分析 ━━━
function analyzeRootCause(issues) {
  // Group related issues and find root causes
  const rootCauses = new Map();

  for (const issue of issues) {
    // Check if this issue could be caused by another
    let rootCause = issue.symptom;

    // Missing secret → downstream API failures
    if (/API.*失败|连通.*失败/.test(issue.symptom)) {
      const secretIssue = issues.find(i => /Secret.*缺失/.test(i.symptom) && i.symptom.includes('NOTION'));
      if (secretIssue) {
        rootCause = 'Secret 缺失导致 API 连接失败';
        issue.root_cause = rootCause;
        issue.related_to = secretIssue.id;
      }
    }

    // dev-status stale could be caused by Notion API failure
    if (/dev.?status.*过期/.test(issue.symptom)) {
      const notionIssue = issues.find(i => /Notion.*API/.test(i.symptom));
      if (notionIssue) {
        rootCause = 'Notion API 不可用导致 dev-status 无法同步';
        issue.root_cause = rootCause;
        issue.related_to = notionIssue.id;
      }
    }
  }

  return issues;
}

// ━━━ 从扫描结果提取问题 ━━━
function extractIssues() {
  const issues = [];
  let issueCounter = 0;

  function addIssue(source, symptom, impact) {
    issueCounter++;
    const id = `SKYEYE-${String(issueCounter).padStart(3, '0')}`;
    const classification = classifyIssue(symptom, source);
    issues.push({
      id,
      source,
      symptom,
      root_cause: symptom, // Will be refined by analyzeRootCause
      impact: impact || '系统稳定性',
      ...classification
    });
  }

  // ── Workflow Health Issues ──
  const wfHealth = readScanResult('workflow-health.json');
  if (wfHealth) {
    for (const issue of (wfHealth.issues || [])) {
      addIssue('workflow', `${issue.file}: ${issue.detail}`, 'Workflow 功能异常');
    }
    for (const conflict of (wfHealth.cron_conflicts || [])) {
      addIssue('workflow', `Cron 冲突: ${conflict.detail}`, '定时任务时序冲突');
    }
  }

  // ── Structure Health Issues ──
  const structHealth = readScanResult('structure-health.json');
  if (structHealth) {
    for (const dir of (structHealth.missing_dirs || [])) {
      addIssue('structure', `目录缺失: ${dir}`, '仓库结构不完整');
    }
    if (structHealth.orphan_files > 0) {
      addIssue('structure', `发现 ${structHealth.orphan_files} 个孤儿文件`, '仓库整洁度');
    }
    if (structHealth.readme && !structHealth.readme_ok) {
      const missing = structHealth.readme.missing_markers || [];
      addIssue('structure', `README marker 缺失: ${missing.join(', ')}`, 'README 自动更新失败');
    }
  }

  // ── Brain Health Issues ──
  const brainHealth = readScanResult('brain-health.json');
  if (brainHealth) {
    if (brainHealth.memory && brainHealth.memory.status !== '✅') {
      for (const issue of (brainHealth.memory.issues || [])) {
        addIssue('brain', `memory.json: ${issue}`, '核心大脑数据过期');
      }
    }
    if (brainHealth.routing_map && brainHealth.routing_map.status !== '✅') {
      for (const issue of (brainHealth.routing_map.issues || [])) {
        addIssue('brain', `routing-map.json: ${issue}`, '路由映射不一致');
      }
    }
    if (brainHealth.dev_status && brainHealth.dev_status.status !== '✅') {
      for (const issue of (brainHealth.dev_status.issues || [])) {
        addIssue('brain', `dev-status.json: ${issue}`, '开发者状态数据过期');
      }
    }
    if (brainHealth.knowledge_base && brainHealth.knowledge_base.status !== '✅') {
      for (const issue of (brainHealth.knowledge_base.issues || [])) {
        addIssue('brain', `knowledge-base.json: ${issue}`, '知识库数据质量');
      }
    }
    if (brainHealth.copilot_instructions && brainHealth.copilot_instructions.status !== '✅') {
      addIssue('brain', 'copilot-instructions.md 不存在或为空', '代码助手指令缺失');
    }
  }

  // ── Bridge Health Issues ──
  const bridgeHealth = readScanResult('bridge-health.json');
  if (bridgeHealth) {
    if (bridgeHealth.notion_api && bridgeHealth.notion_api.status !== '🟢') {
      addIssue('bridge', `Notion API: ${bridgeHealth.notion_api.detail}`, '外部数据同步中断');
    }
    if (bridgeHealth.github_api && bridgeHealth.github_api.status !== '🟢') {
      addIssue('bridge', `GitHub API: ${bridgeHealth.github_api.detail}`, 'CI/CD 功能受限');
    }
    if (bridgeHealth.secrets && !bridgeHealth.secrets.complete) {
      const missing = bridgeHealth.secrets.missing || [];
      for (const secret of missing) {
        addIssue('bridge', `Secret 缺失: ${secret}`, '功能不可用');
      }
    }
  }

  // ── Hibernation Health Issues ──
  const hibDir = path.join(path.resolve(__dirname, '../..'), 'skyeye/hibernation');
  if (!fs.existsSync(hibDir)) {
    addIssue('hibernation', 'hibernation 目录缺失', '休眠系统不可用');
  } else {
    const cpDir = path.join(hibDir, 'checkpoints');
    if (fs.existsSync(cpDir)) {
      const cpFiles = fs.readdirSync(cpDir).filter(f => f.startsWith('daily-cp-') && f.endsWith('.json'));
      if (cpFiles.length === 0) {
        addIssue('hibernation', 'hibernation checkpoint 缺失: 无日检查点', '日休眠可能未运行');
      }
    }
    const requiredSubDirs = ['checkpoints', 'weekly-snapshots', 'upgrade-packs', 'distribution-reports'];
    for (const sub of requiredSubDirs) {
      if (!fs.existsSync(path.join(hibDir, sub))) {
        addIssue('hibernation', `hibernation 目录缺失: ${sub}`, '休眠子系统不完整');
      }
    }
  }

  return issues;
}

// ━━━ 主诊断 ━━━
function diagnose() {
  let issues = extractIssues();

  // 根因分析
  issues = analyzeRootCause(issues);

  // 统计
  const autoFixable = issues.filter(i => i.fixable).length;
  const needsHuman = issues.filter(i => !i.fixable && i.fix_plan === 'needs_human').length;
  const watchList = issues.filter(i => !i.fixable && i.fix_plan === 'watch').length;

  // 按优先级排序
  const priorityOrder = { 'P0': 0, 'P1': 1, 'P2': 2 };
  issues.sort((a, b) => (priorityOrder[a.priority] || 9) - (priorityOrder[b.priority] || 9));

  const result = {
    diagnosis_time: new Date(new Date().getTime() + 8 * 3600 * 1000)
      .toISOString().replace('T', ' ').slice(0, 19) + '+08:00',
    total_issues: issues.length,
    auto_fixable: autoFixable,
    needs_human: needsHuman,
    watch_list: watchList,
    issues
  };

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

diagnose();
