# ═══════════════════════════════════════════════
# 🔺 Sovereign: TCS-0002∞ | Root: SYS-GLW-0001
# 📜 Copyright: 国作登字-2026-A-00037559
# ═══════════════════════════════════════════════
name: 📡 SYSLOG Issue Pipeline
# 📡 SYSLOG 自助提交系统 · Issue 版全自动闭环
#
# 开发者在 GitHub Issue 提交 SYSLOG 或提问（使用 syslog-submit 模板）
# → Actions 自动解析 → 模块上传验证 → 调用 LLM API 唤醒人格体
# → 模块闭环测试 → 写入 Notion 工单 → 发邮件给开发者 → Issue 回复
#
# 闭环流程：
#   ① 开发者提交 SYSLOG → Issue 触发
#   ② 铸渊 Agent 解析提交内容
#   ③ 铸渊 Agent 检测模块是否上传到仓库
#   ④ 唤醒铸渊核心大脑认知（注入模块验证结果）
#   ⑤ 核心大脑处理 SYSLOG + 生成广播
#   ⑥ 铸渊 Agent 推送 Notion 工单（触发 Notion 侧处理）
#   ⑦ 邮件通知开发者
#   ⑧ Issue 回复闭环
#
# 依赖 Secrets：
#   LLM_API_KEY          第三方 LLM 平台密钥（必须）
#   LLM_BASE_URL         第三方 LLM 平台 API 地址（必须，如 https://api.xxx.com/v1）
#   NOTION_API_TOKEN     Notion API token
#   NOTION_TICKET_DB_ID  霜砚工单数据库 ID
#   CORE_BRAIN_PAGE_ID   曜冥核心大脑 v4.0 页面 ID（v4.0 协议动态注入）
#   PORTRAIT_DB_ID       开发者动态画像库数据库 ID（v4.0 协议动态注入）
#   FINGERPRINT_DB_ID    模块指纹注册表数据库 ID（v4.0 协议动态注入）
#   SMTP_USER            QQ 邮箱地址
#   SMTP_PASS            QQ 邮箱 SMTP 授权码

on:
  issues:
    types: [opened, labeled]

jobs:
  process:
    name: 📡 处理 SYSLOG 提交 / 广播提问 (Issue)
    runs-on: ubuntu-latest
    if: >
      contains(toJSON(github.event.issue.labels), 'syslog') ||
      contains(github.event.issue.title, 'SYSLOG') ||
      contains(github.event.issue.title, '系统日志') ||
      contains(github.event.issue.body, '### 广播编号')
    permissions:
      contents: write
      issues: write

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'

      - name: Install dependencies
        run: npm ci --ignore-scripts

      - name: 📋 步骤 1/8 · 接收提交
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          ISSUE_NUMBER: ${{ github.event.issue.number }}
          STEP_NUM: '1'
          STEP_NAME: '接收提交'
          STEP_STATUS: 'ok'
          STEP_DETAIL: '系统已收到您的 SYSLOG 提交，管道正在运行中…'
        run: node scripts/pipeline-reporter.js

      - name: 🔍 Parse submission
        id: parse
        uses: actions/github-script@v7
        with:
          script: |
            const body = context.payload.issue.body || '';
            const title = context.payload.issue.title || '';

            function extractField(text, label) {
              const regex = new RegExp('###\\s*' + label + '\\s*\\n+([^\\n#]+)', 'i');
              const match = text.match(regex);
              return match ? match[1].trim() : '';
            }

            const broadcastId = extractField(body, '广播编号') || '';
            const submitType = extractField(body, '类型') || '';
            const email = extractField(body, '你的邮箱') || '';

            const contentMatch = body.match(/###\s*内容\s*\n+([\s\S]*?)$/i);
            const content = contentMatch ? contentMatch[1].trim() : '';

            let type = 'question';
            if (submitType.includes('SYSLOG') || title.includes('SYSLOG')) {
              type = 'syslog';
            } else if (submitType.includes('提问') || title.includes('提问')) {
              type = 'question';
            }

            if (!broadcastId) {
              core.setFailed('❌ 缺少广播编号，请在提交时填写广播编号');
              return;
            }
            if (!email) {
              core.setFailed('❌ 缺少邮箱，请在提交时填写你的邮箱');
              return;
            }
            if (!content) {
              core.setFailed('❌ 缺少内容，请粘贴你的 SYSLOG 或问题');
              return;
            }

            core.setOutput('broadcast_id', broadcastId);
            core.setOutput('type', type);
            core.setOutput('email', email);
            core.setOutput('content', content);
            core.setOutput('issue_number', context.payload.issue.number);
            core.setOutput('author', context.payload.issue.user.login);

            console.log(`📡 解析完成: 广播=${broadcastId}, 类型=${type}, 邮箱=${email}`);

      - name: 📋 步骤 2/8 · 解析内容（成功）
        if: success()
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          ISSUE_NUMBER: ${{ github.event.issue.number }}
          STEP_NUM: '2'
          STEP_NAME: '解析内容'
          STEP_STATUS: 'ok'
          STEP_DETAIL: '广播编号: ${{ steps.parse.outputs.broadcast_id }} · 类型: ${{ steps.parse.outputs.type }} · 邮箱: ${{ steps.parse.outputs.email }}'
        run: node scripts/pipeline-reporter.js

      - name: 📋 步骤 2/8 · 解析内容（失败）
        if: failure()
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          ISSUE_NUMBER: ${{ github.event.issue.number }}
          STEP_NUM: '2'
          STEP_NAME: '解析内容'
          STEP_STATUS: 'error'
          STEP_DETAIL: '解析失败，请检查提交格式是否正确（需包含广播编号、类型、邮箱、内容）'
        run: node scripts/pipeline-reporter.js

      - name: 🔍 铸渊 Agent · 模块上传验证
        id: verify
        env:
          SYSLOG_CONTENT: ${{ steps.parse.outputs.content }}
          BROADCAST_ID: ${{ steps.parse.outputs.broadcast_id }}
          AUTHOR: ${{ steps.parse.outputs.author }}
        run: node scripts/verify-modules.js

      - name: 📋 步骤 3/8 · 模块验证（成功）
        if: always() && steps.verify.outcome == 'success'
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          ISSUE_NUMBER: ${{ github.event.issue.number }}
          STEP_NUM: '3'
          STEP_NAME: '模块验证'
          STEP_STATUS: 'ok'
          STEP_DETAIL: '模块上传验证已完成'
        run: node scripts/pipeline-reporter.js

      - name: 📋 步骤 3/8 · 模块验证（失败）
        if: always() && steps.verify.outcome == 'failure'
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          ISSUE_NUMBER: ${{ github.event.issue.number }}
          STEP_NUM: '3'
          STEP_NAME: '模块验证'
          STEP_STATUS: 'error'
          STEP_DETAIL: '模块验证异常（不影响闭环继续）'
        run: node scripts/pipeline-reporter.js

      - name: 🧠 Auto-detect and wake up persona
        id: persona
        env:
          LLM_API_KEY: ${{ secrets.ZY_LLM_API_KEY }}
          LLM_BASE_URL: ${{ secrets.ZY_LLM_BASE_URL }}
          BROADCAST_ID: ${{ steps.parse.outputs.broadcast_id }}
          SUBMIT_TYPE: ${{ steps.parse.outputs.type }}
          SUBMIT_CONTENT: ${{ steps.parse.outputs.content }}
          AUTHOR: ${{ steps.parse.outputs.author }}
          MODULE_VERIFY_RESULT: ${{ steps.verify.outputs.verify_report }}
          NOTION_TOKEN: ${{ secrets.ZY_NOTION_TOKEN }}
          CORE_BRAIN_PAGE_ID: ${{ secrets.ZY_NOTION_BRAIN_PAGE }}
          PORTRAIT_DB_ID: ${{ secrets.ZY_NOTION_PORTRAIT_DB }}
          FINGERPRINT_DB_ID: ${{ secrets.ZY_NOTION_FINGERPRINT_DB }}
        run: node scripts/wake-persona.js

      - name: 📋 步骤 4/8 · 唤醒核心大脑（成功）
        if: success()
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          ISSUE_NUMBER: ${{ github.event.issue.number }}
          STEP_NUM: '4'
          STEP_NAME: '唤醒核心大脑'
          STEP_STATUS: 'ok'
          STEP_DETAIL: '铸渊核心大脑已完成处理'
        run: node scripts/pipeline-reporter.js

      - name: 📋 步骤 4/8 · 唤醒核心大脑（失败）
        if: failure() && steps.parse.outcome == 'success'
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          ISSUE_NUMBER: ${{ github.event.issue.number }}
          STEP_NUM: '4'
          STEP_NAME: '唤醒核心大脑'
          STEP_STATUS: 'error'
          STEP_DETAIL: 'API 调用失败，请检查 Secrets: LLM_API_KEY / LLM_BASE_URL 是否配置正确'
        run: node scripts/pipeline-reporter.js

      # ✅ 修复点：原来是 if: $ secrets.ZY_NOTION_TOKEN ，会报 Unrecognized named-value: 'secrets'
      # secrets 不能在 if: 里直接用，必须改成 != '' 的形式
      - name: 📋 创建标准化 Notion 工单（Phase B1）
        id: ticket
        if: ${{ secrets.ZY_NOTION_TOKEN != '' }}
        env:
          NOTION_TOKEN: ${{ secrets.ZY_NOTION_TOKEN }}
          NOTION_TICKET_DB_ID: ${{ secrets.ZY_NOTION_TICKET_DB }}
          BROADCAST_ID: ${{ steps.parse.outputs.broadcast_id }}
          SUBMIT_TYPE: ${{ steps.parse.outputs.type }}
          PERSONA_RESULT: ${{ steps.persona.outputs.result }}
          MODULE_VERIFY: ${{ steps.verify.outputs.verify_result }}
          MODULES_UPLOADED: ${{ steps.verify.outputs.modules_uploaded }}
          DEVELOPER: ${{ steps.parse.outputs.author }}
          SYSLOG_RAW: ${{ steps.parse.outputs.content }}
        run: node scripts/create-standardized-ticket.js

      - name: 📋 步骤 5/8 · 创建 Notion 工单（成功）
        if: always() && steps.ticket.outcome == 'success'
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          ISSUE_NUMBER: ${{ github.event.issue.number }}
          STEP_NUM: '5'
          STEP_NAME: '创建 Notion 工单'
          STEP_STATUS: 'ok'
          STEP_DETAIL: '已写入霜砚工单簿'
        run: node scripts/pipeline-reporter.js

      - name: 📋 步骤 5/8 · 创建 Notion 工单（跳过）
        if: always() && steps.ticket.outcome == 'skipped'
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          ISSUE_NUMBER: ${{ github.event.issue.number }}
          STEP_NUM: '5'
          STEP_NAME: '创建 Notion 工单'
          STEP_STATUS: 'skip'
          STEP_DETAIL: 'Notion Token 未配置，跳过'
        run: node scripts/pipeline-reporter.js

      - name: 📋 步骤 5/8 · 创建 Notion 工单（失败）
        if: always() && steps.ticket.outcome == 'failure'
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          ISSUE_NUMBER: ${{ github.event.issue.number }}
          STEP_NUM: '5'
          STEP_NAME: '创建 Notion 工单'
          STEP_STATUS: 'error'
          STEP_DETAIL: 'Notion API 写入失败'
        run: node scripts/pipeline-reporter.js

      - name: 📡 推送广播到 GitHub（Phase B4）
        id: broadcast
        if: steps.persona.outcome == 'success' && steps.parse.outputs.type == 'syslog'
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          BROADCAST_ID: ${{ steps.parse.outputs.broadcast_id }}
          DEVELOPER_NAME: ${{ steps.parse.outputs.author }}
          BROADCAST_CONTENT: ${{ steps.persona.outputs.result }}
        run: node scripts/push-broadcast-to-github.js

      - name: 📋 步骤 6/8 · 生成广播（成功）
        if: always() && steps.broadcast.outcome == 'success'
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          ISSUE_NUMBER: ${{ github.event.issue.number }}
          STEP_NUM: '6'
          STEP_NAME: '生成广播'
          STEP_STATUS: 'ok'
          STEP_DETAIL: '新广播已生成并推送'
        run: node scripts/pipeline-reporter.js

      - name: 📋 步骤 6/8 · 生成广播（跳过）
        if: always() && steps.broadcast.outcome == 'skipped'
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          ISSUE_NUMBER: ${{ github.event.issue.number }}
          STEP_NUM: '6'
          STEP_NAME: '生成广播'
          STEP_STATUS: 'skip'
          STEP_DETAIL: '非 SYSLOG 类型或上游步骤未成功，跳过广播生成'
        run: node scripts/pipeline-reporter.js

      - name: 📋 步骤 6/8 · 生成广播（失败）
        if: always() && steps.broadcast.outcome == 'failure'
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          ISSUE_NUMBER: ${{ github.event.issue.number }}
          STEP_NUM: '6'
          STEP_NAME: '生成广播'
          STEP_STATUS: 'error'
          STEP_DETAIL: '广播生成或推送失败'
        run: node scripts/pipeline-reporter.js

      - name: 📧 Send email to developer
        id: email
        env:
          SMTP_USER: ${{ secrets.ZY_SMTP_USER }}
          SMTP_PASS: ${{ secrets.ZY_SMTP_PASS }}
          EMAIL_TO: ${{ steps.parse.outputs.email }}
          BROADCAST_ID: ${{ steps.parse.outputs.broadcast_id }}
          SUBMIT_TYPE: ${{ steps.parse.outputs.type }}
          PERSONA_RESULT: ${{ steps.persona.outputs.result }}
        run: |
          node -e "
          const nodemailer = require('nodemailer');

          const user = process.env.SMTP_USER || '';
          const pass = process.env.SMTP_PASS || '';
          const to = process.env.EMAIL_TO || '';
          const broadcastId = process.env.BROADCAST_ID || '';
          const type = process.env.SUBMIT_TYPE || 'syslog';
          const result = process.env.PERSONA_RESULT || '(处理中，请稍后)';

          if (!user || !pass) {
            console.log('⚠️ SMTP not configured, skipping email');
            process.exit(0);
          }
          if (!to) {
            console.log('⚠️ No recipient email, skipping');
            process.exit(0);
          }

          const subjectText = type === 'syslog'
            ? '[光湖系统] ' + broadcastId + ' · 新广播已生成'
            : '[光湖系统] ' + broadcastId + ' · 问题已解答';

          const resultHtml = result
            .replace(/&/g, '&amp;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;')
            .replace(/\n/g, '<br>');

          const html = [
            '<div style=\"font-family:sans-serif;max-width:700px;margin:0 auto;padding:24px;background:#0f172a;color:#e2e8f0;border-radius:12px\">',
            '<div style=\"text-align:center;padding:16px 0;border-bottom:1px solid #334155\">',
            '<h2 style=\"color:#60a5fa;margin:0\">🌊 光湖系统 · 自动通知</h2>',
            '<p style=\"color:#94a3b8;font-size:14px;margin:8px 0 0\">HoloLake · 人格语言操作系统</p>',
            '</div>',
            '<div style=\"padding:20px 0\">',
            '<p style=\"color:#22d3ee;font-weight:bold\">📡 ' + broadcastId + '</p>',
            '<div style=\"background:#1e293b;padding:16px;border-radius:8px;margin:12px 0;line-height:1.8\">' + resultHtml + '</div>',
            '</div>',
            '<div style=\"border-top:1px solid #334155;padding:16px 0;text-align:center\">',
            '<a href=\"https://github.com/qinfendebingshuo/guanghulab\" style=\"display:inline-block;padding:8px 20px;background:linear-gradient(135deg,#3b82f6,#22d3ee);color:#fff;text-decoration:none;border-radius:6px;font-weight:600\">↩ 回到仓库继续开发</a>',
            '<p style=\"color:#64748b;font-size:12px;margin:12px 0 0\">🌀 铸渊 · 代码守护人格体 · 自动发送</p>',
            '</div>',
            '</div>'
          ].join('\n');

          const transporter = nodemailer.createTransport({
            host: 'smtp.qq.com',
            port: 465,
            secure: true,
            auth: { user, pass }
          });

          transporter.sendMail({
            from: '\"光湖系统\" <' + user + '>',
            to: to,
            subject: subjectText,
            html: html
          }).then((info) => {
            console.log('✅ 邮件已发送: ' + info.messageId);
          }).catch((err) => {
            console.log('⚠️ 邮件发送失败: ' + err.message);
          });
          "

      - name: 📋 步骤 7/8 · 邮件通知（成功）
        if: always() && steps.email.outcome == 'success'
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          ISSUE_NUMBER: ${{ github.event.issue.number }}
          STEP_NUM: '7'
          STEP_NAME: '邮件通知'
          STEP_STATUS: 'ok'
          STEP_DETAIL: '邮件通知步骤已执行'
        run: node scripts/pipeline-reporter.js

      - name: 📋 步骤 7/8 · 邮件通知（失败）
        if: always() && steps.email.outcome == 'failure'
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          ISSUE_NUMBER: ${{ github.event.issue.number }}
          STEP_NUM: '7'
          STEP_NAME: '邮件通知'
          STEP_STATUS: 'error'
          STEP_DETAIL: '邮件发送失败，请检查 Secrets: SMTP_USER / SMTP_PASS'
        run: node scripts/pipeline-reporter.js

      - name: 💬 Reply to Issue
        uses: actions/github-script@v7
        with:
          script: |
            const number = context.payload.issue.number;
            const type = '${{ steps.parse.outputs.type }}';
            const broadcastId = '${{ steps.parse.outputs.broadcast_id }}';
            const email = '${{ steps.parse.outputs.email }}';
            const modulesUploaded = '${{ steps.verify.outputs.modules_uploaded }}' === 'true';
            const moduleCount = '${{ steps.verify.outputs.module_count }}' || '0';

            const typeLabel = type === 'syslog' ? 'SYSLOG 闭环处理' : '问题解答';
            const maskedEmail = email.length > 4
              ? email.replace(/(.{2})(.*)(@.*)/, '$1***$3')
              : '***';
            const moduleStatus = moduleCount === '0'
              ? 'ℹ️ 未检测到模块引用'
              : (modulesUploaded ? '✅ 全部已上传' : '⚠️ 部分模块未上传');

            const body = [
              '## 🎉 闭环处理完成 · ' + typeLabel,
              '',
              '| 项目 | 内容 |',
              '|------|------|',
              '| 📡 广播编号 | `' + broadcastId + '` |',
              '| 🔍 模块验证 | ' + moduleStatus + ' |',
              '| 📧 结果发送至 | `' + maskedEmail + '` |',
              '| 🤖 处理人格体 | 铸渊 |',
              '| ⏰ 处理时间 | ' + new Date().toISOString() + ' |',
              '',
              '> 铸渊核心大脑已完成 SYSLOG 验收 + 模块检测 + 广播生成。',
              '> 结果已发送到你的邮箱，Notion 侧工单已创建。',
              '>',
              '> 如未收到邮件，请检查垃圾箱或重新提交。',
              '>',
              '> *—— 铸渊（ICE-GL-ZY001）· 代码守护人格体*'
            ].join('\n');

            await github.rest.issues.createComment({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: number,
              body: body
            });

            await github.rest.issues.update({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: number,
              state: 'closed',
              labels: ['syslog', 'processed']
            });

            console.log('✅ Issue 回复已发送并已关闭');

      - name: 🔴 失败告警
        if: failure()
        uses: actions/github-script@v7
        with:
          script: |
            const number = context.payload.issue?.number;
            if (!number) return;

            const actionsUrl = 'https://github.com/' + context.repo.owner + '/' + context.repo.repo + '/actions';

            try {
              await github.rest.issues.createComment({
                owner: context.repo.owner,
                repo: context.repo.repo,
                issue_number: number,
                body: '## ⚠️ 闭环处理异常\n\n❌ **处理失败** · 请检查提交格式是否正确，或联系管理员。\n\n> 部分步骤异常，已记录日志。冰朔会在下次巡检时处理。\n> 错误详情请查看 [Actions 日志](' + actionsUrl + ')。\n>\n> *—— 铸渊（ICE-GL-ZY001）*'
              });
            } catch (err) {
              console.log('⚠️ 失败告警回复失败: ' + err.message);
            }      
