# ═══════════════════════════════════════════════
# 🔺 Sovereign: TCS-0002∞ | Root: SYS-GLW-0001
# 📜 Copyright: 国作登字-2026-A-00037559
# ═══════════════════════════════════════════════
# .github/workflows/tianyan-nightly-scan.yml
# 🌙 天眼夜间自动修复引擎 v3.0
#
# Phase A: 天眼夜间巡查（扫描过去24h失败Workflow）
# Phase B: 报错智能分析（Gemini API）
# Phase C: 铸渊自动修复（生成修复代码）
# Phase D: 天眼审核（H1-H9 检查清单）
# Phase E: 创建 PR（等待冰朔晨间合并）
# Phase F: 更新仪表盘
#
# 指令编号: ZY-TIANYAN-AUTOFIX-2026-0324-001
# AG-ZY-087

name: "🌙 天眼夜间自动修复引擎 v3.0"

on:
  schedule:
    - cron: '0 15 * * *'  # 23:00 CST = 15:00 UTC
  workflow_dispatch:
    inputs:
      force_scan:
        description: '强制扫描（忽略时间窗口）'
        type: boolean
        default: false
  repository_dispatch:
    types: [watchdog-retry]

permissions:
  actions: read
  contents: write
  pull-requests: write
  checks: read

env:
  REPAIR_BRANCH_PREFIX: "fix/auto-repair"
  MAX_FILES_PER_REPAIR: 5
  MAX_LINES_PER_FILE: 50
  MAX_RETRY_ROUNDS: 2
  GEMINI_MODEL: "gemini-2.0-flash"
  PROTECTED_PATTERNS: "tianyan-*.yml,CODEOWNERS,.github/FUNDING.yml"

jobs:
  # ========================================
  # Phase A: 天眼夜间巡查
  # ========================================
  nightly-scan:
    runs-on: ubuntu-latest
    outputs:
      has_errors: ${{ steps.scan.outputs.has_errors }}
      error_report: ${{ steps.scan.outputs.error_report }}
    steps:
      - name: "🔭 扫描过去24小时 Workflow 运行记录"
        id: scan
        env:
          GH_TOKEN: ${{ secrets.ZY_GITHUB_PAT }}
        run: |
          echo "[天眼 v3.0] Phase A 启动 — 夜间巡查扫描"
          echo "═══════════════════════════════════════════"
          SINCE=$(date -u -d '24 hours ago' +%Y-%m-%dT%H:%M:%SZ)
          echo "📅 扫描起始时间: $SINCE"

          # 获取失败的 workflow runs
          FAILED_RUNS=$(gh api \
            "repos/${{ github.repository }}/actions/runs?created=>$SINCE&status=failure&per_page=50" \
            --jq '.workflow_runs' 2>/dev/null || echo '[]')

          FAIL_COUNT=$(echo "$FAILED_RUNS" | jq 'length')
          TOTAL_RUNS=$(gh api \
            "repos/${{ github.repository }}/actions/runs?created=>$SINCE&per_page=1" \
            --jq '.total_count' 2>/dev/null || echo '0')

          echo "📊 过去24小时统计:"
          echo "  总运行数: $TOTAL_RUNS"
          echo "  失败运行: $FAIL_COUNT"

          if [ "$FAIL_COUNT" -eq 0 ] || [ "$FAIL_COUNT" = "null" ]; then
            echo "has_errors=false" >> $GITHUB_OUTPUT
            echo "✅ 今日无异常"
          else
            echo "has_errors=true" >> $GITHUB_OUTPUT

            # 生成结构化错误报告
            ERROR_JSON=$(echo "$FAILED_RUNS" | jq -c '[.[] | {
              workflow: .name,
              run_id: .id,
              conclusion: .conclusion,
              html_url: .html_url,
              created_at: .created_at,
              head_branch: .head_branch
            }]')

            # Use heredoc for multiline output
            echo "error_report<<TIANYAN_EOF" >> $GITHUB_OUTPUT
            echo "$ERROR_JSON" >> $GITHUB_OUTPUT
            echo "TIANYAN_EOF" >> $GITHUB_OUTPUT

            echo "⚠️ 发现 $FAIL_COUNT 个失败运行，进入 Phase B"
          fi

  # ========================================
  # Phase B+C+D: 分析 → 修复 → 审核
  # ========================================
  analyze-and-repair:
    needs: nightly-scan
    if: needs.nightly-scan.outputs.has_errors == 'true'
    runs-on: ubuntu-latest
    outputs:
      repair_branch: ${{ steps.repair.outputs.branch_name }}
      repair_summary: ${{ steps.create_summary.outputs.summary }}
      pr_needed: ${{ steps.review.outputs.pr_needed }}
      fix_count: ${{ steps.review.outputs.fix_count }}
      overall_risk: ${{ steps.review.outputs.overall_risk }}
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'

      - name: "🧠 Phase B — Gemini 报错分析"
        id: analyze
        env:
          GEMINI_API_KEY: ${{ secrets.ZY_LLM_API_KEY }}
          ERROR_REPORT: ${{ needs.nightly-scan.outputs.error_report }}
        run: |
          echo "[铸渊核心大脑] Phase B 启动 — 报错智能分析"
          mkdir -p /tmp/tianyan
          node .github/scripts/tianyan-analyze.js

      - name: "⚒️ Phase C — 铸渊自动修复"
        id: repair
        env:
          GEMINI_API_KEY: ${{ secrets.ZY_LLM_API_KEY }}
          GH_TOKEN: ${{ secrets.ZY_GITHUB_PAT }}
        run: |
          echo "[铸渊核心大脑] Phase C 启动 — 自动修复"

          # Check if there are fixable errors
          FIXABLE=$(cat /tmp/tianyan/analysis.json | jq '.auto_fixable // 0')
          if [ "$FIXABLE" -eq 0 ]; then
            echo "⚠️ 没有可自动修复的错误"
            echo "branch_name=" >> $GITHUB_OUTPUT
            exit 0
          fi

          # Create repair branch (use timestamp to avoid conflicts)
          BRANCH="${REPAIR_BRANCH_PREFIX}-$(date +%Y%m%d)-$(date +%H%M%S)"
          git config user.name "zhuyuan-bot"
          git config user.email "zhuyuan@guanghulab.com"
          git checkout -b "$BRANCH"

          # Run repair script
          node .github/scripts/tianyan-repair.js

          # Check if there are changes to push
          if git diff --quiet && git diff --cached --quiet; then
            echo "⚠️ 修复脚本未产生变更"
            echo "branch_name=" >> $GITHUB_OUTPUT
          else
            git push origin "$BRANCH" || echo "⚠️ Push failed"
            echo "branch_name=$BRANCH" >> $GITHUB_OUTPUT
          fi

      - name: "🔭 Phase D — 天眼审核修复代码"
        id: review
        if: steps.repair.outputs.branch_name != ''
        run: |
          echo "[天眼 v3.0] Phase D 启动 — 审核修复代码"
          node .github/scripts/tianyan-review.js

          # Read review result
          if [ -f /tmp/tianyan/review-result.json ]; then
            PR_NEEDED=$(cat /tmp/tianyan/review-result.json | jq -r '.pr_needed // false')
            echo "pr_needed=$PR_NEEDED" >> $GITHUB_OUTPUT

            FIX_COUNT=$(cat /tmp/tianyan/repair-result.json | jq '.repaired // 0')
            echo "fix_count=$FIX_COUNT" >> $GITHUB_OUTPUT
            echo "overall_risk=low" >> $GITHUB_OUTPUT
          else
            echo "pr_needed=false" >> $GITHUB_OUTPUT
            echo "fix_count=0" >> $GITHUB_OUTPUT
          fi

      - name: "📝 生成 PR 摘要"
        id: create_summary
        if: steps.review.outputs.pr_needed == 'true'
        run: |
          DATE=$(date +%Y-%m-%d)
          FIX_COUNT="${{ steps.review.outputs.fix_count }}"
          RISK="${{ steps.review.outputs.overall_risk }}"

          SUMMARY=$(cat <<'SUMMARY_EOF'
          ## 🌙 天眼夜间自动修复引擎 v3.0

          **扫描时间：** SCAN_DATE
          **修复数量：** FIX_NUM 个
          **风险等级：** RISK_LEVEL
          **天眼审核：** ✅ H1-H9 全部通过

          ### 天眼审核结果

          - [x] H1 Secrets安全
          - [x] H2 文件完整性
          - [x] H3 依赖安全
          - [x] H4 权限最小化
          - [x] H5 天眼自保护
          - [x] H6 变更范围
          - [x] H7 Secrets引用完整性
          - [x] H8 注释规范
          - [x] H9 无残留调试代码

          ---
          > 🤖 此 PR 由铸渊夜间修复引擎自动创建
          > 📋 指令编号: ZY-TIANYAN-AUTOFIX-2026-0324-001
          > ⏰ 请冰朔在晨间审阅后合并
          SUMMARY_EOF
          )

          SUMMARY="${SUMMARY//SCAN_DATE/$DATE}"
          SUMMARY="${SUMMARY//FIX_NUM/$FIX_COUNT}"
          SUMMARY="${SUMMARY//RISK_LEVEL/$RISK}"

          echo "summary<<SUMMARY_DELIM" >> $GITHUB_OUTPUT
          echo "$SUMMARY" >> $GITHUB_OUTPUT
          echo "SUMMARY_DELIM" >> $GITHUB_OUTPUT

      - name: "🔄 Phase D 重试（如审核未通过）"
        if: steps.review.outputs.pr_needed == 'false' && steps.repair.outputs.branch_name != ''
        env:
          GEMINI_API_KEY: ${{ secrets.ZY_LLM_API_KEY }}
        run: |
          echo "[天眼 v3.0] 审核未通过 — 进入重试流程"
          RETRY=0
          MAX_RETRY=2

          while [ $RETRY -lt $MAX_RETRY ]; do
            RETRY=$((RETRY + 1))
            echo "🔄 重试第 $RETRY 轮..."

            # Re-run repair with retry context
            node .github/scripts/tianyan-repair.js
            node .github/scripts/tianyan-review.js

            PR_NEEDED=$(cat /tmp/tianyan/review-result.json | jq -r '.pr_needed // false')
            if [ "$PR_NEEDED" = "true" ]; then
              echo "✅ 重试第 $RETRY 轮通过"
              break
            fi
          done

          if [ "$PR_NEEDED" != "true" ]; then
            echo "❌ $MAX_RETRY 轮重试后仍未通过 — 放弃自动修复"
            # Clean up repair branch
            git checkout main
            git branch -D "${{ steps.repair.outputs.branch_name }}" 2>/dev/null || true
            git push origin --delete "${{ steps.repair.outputs.branch_name }}" 2>/dev/null || true
          fi

  # ========================================
  # Phase E+F: 创建 PR + 更新仪表盘
  # ========================================
  create-pr-and-dashboard:
    needs: analyze-and-repair
    if: needs.analyze-and-repair.outputs.pr_needed == 'true'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          ref: main

      - name: "📦 Phase E — 创建 Pull Request"
        id: create_pr
        env:
          GH_TOKEN: ${{ secrets.ZY_GITHUB_PAT }}
          BRANCH: ${{ needs.analyze-and-repair.outputs.repair_branch }}
          SUMMARY: ${{ needs.analyze-and-repair.outputs.repair_summary }}
          FIX_COUNT: ${{ needs.analyze-and-repair.outputs.fix_count }}
          RISK: ${{ needs.analyze-and-repair.outputs.overall_risk }}
        run: |
          echo "[天眼 v3.0] Phase E — 创建 Pull Request"

          PR_TITLE="🌙 [AUTO-FIX] $(date +%Y-%m-%d) 天眼夜间自动修复 (${FIX_COUNT}个修复)"

          # Create labels if they don't exist
          gh label create "auto-fix" --color "0E8A16" --description "自动修复 PR" 2>/dev/null || true
          gh label create "tianyan-v3" --color "1D76DB" --description "天眼 v3.0 引擎" 2>/dev/null || true

          PR_URL=$(gh pr create \
            --base main \
            --head "$BRANCH" \
            --title "$PR_TITLE" \
            --body "$SUMMARY" \
            --label "auto-fix,tianyan-v3" 2>/dev/null || echo "")

          if [ -n "$PR_URL" ]; then
            echo "pr_url=$PR_URL" >> $GITHUB_OUTPUT
            echo "✅ PR 已创建: $PR_URL"

            # Add risk label
            if [ "$RISK" = "low" ]; then
              gh label create "safe-to-merge" --color "0E8A16" 2>/dev/null || true
              gh pr edit "$PR_URL" --add-label "safe-to-merge" 2>/dev/null || true
            elif [ "$RISK" = "medium" ]; then
              gh label create "review-carefully" --color "FBCA04" 2>/dev/null || true
              gh pr edit "$PR_URL" --add-label "review-carefully" 2>/dev/null || true
            fi
          else
            echo "⚠️ PR 创建失败"
            echo "pr_url=" >> $GITHUB_OUTPUT
          fi

      - name: "📊 Phase F — 更新仪表盘"
        env:
          GH_TOKEN: ${{ secrets.ZY_GITHUB_PAT }}
          PR_URL: ${{ steps.create_pr.outputs.pr_url }}
          FIX_COUNT: ${{ needs.analyze-and-repair.outputs.fix_count }}
        run: |
          echo "[天眼 v3.0] Phase F — 更新仪表盘"
          DATE=$(date +%Y-%m-%d)
          TIME=$(date +%H:%M)

          # Update DASHBOARD.md status table
          if [ -f DASHBOARD.md ]; then
            sed -i "s/| 上次扫描 | .*/| 上次扫描 | $DATE $TIME CST |/" DASHBOARD.md
            sed -i "s/| 扫描结果 | .*/| 扫描结果 | ⚠️ 发现错误，已自动修复 |/" DASHBOARD.md
            sed -i "s/| 自动修复 | .*/| 自动修复 | ✅ ${FIX_COUNT} 个已修复 |/" DASHBOARD.md

            if [ -n "$PR_URL" ]; then
              PR_NUM=$(echo "$PR_URL" | grep -oP '\d+$' || echo "?")
              sed -i "s/| 待合并 PR | .*/| 待合并 PR | 🟡 PR #${PR_NUM} |/" DASHBOARD.md
            fi

            git config user.name "tianyan-bot"
            git config user.email "tianyan@guanghulab.com"
            git add DASHBOARD.md
            git diff --cached --quiet || git commit -m "[DASHBOARD] 更新天眼仪表盘 $DATE — ${FIX_COUNT}个修复待合并"
            git push origin main || true
          fi

  # ========================================
  # 无错误时的仪表盘更新
  # ========================================
  dashboard-no-errors:
    needs: nightly-scan
    if: needs.nightly-scan.outputs.has_errors == 'false'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: "✅ 更新仪表盘 — 今日无异常"
        env:
          GH_TOKEN: ${{ secrets.ZY_GITHUB_PAT }}
        run: |
          DATE=$(date +%Y-%m-%d)
          TIME=$(date +%H:%M)
          echo "[天眼 v3.0] 今日无异常，更新仪表盘"

          if [ -f DASHBOARD.md ]; then
            sed -i "s/| 上次扫描 | .*/| 上次扫描 | $DATE $TIME CST |/" DASHBOARD.md
            sed -i "s/| 扫描结果 | .*/| 扫描结果 | ✅ 今日无异常 |/" DASHBOARD.md
            sed -i "s/| 自动修复 | .*/| 自动修复 | — |/" DASHBOARD.md
            sed -i "s/| 需人工处理 | .*/| 需人工处理 | — |/" DASHBOARD.md

            git config user.name "tianyan-bot"
            git config user.email "tianyan@guanghulab.com"
            git add DASHBOARD.md
            git diff --cached --quiet || git commit -m "[DASHBOARD] 今日无异常 $DATE"
            git push origin main || true
          fi
